1 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2012-2018 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
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: Manuel Requena <manuel.requena@cttc.es>
19  */
20 
21 #include "ns3/core-module.h"
22 #include "ns3/network-module.h"
23 #include "ns3/internet-module.h"
24 #include "ns3/mobility-module.h"
25 #include "ns3/lte-module.h"
26 #include "ns3/applications-module.h"
27 #include "ns3/point-to-point-module.h"
28 #include "ns3/config-store-module.h"
29 
30 using namespace ns3;
31 
32 NS_LOG_COMPONENT_DEFINE ("LenaX2HandoverExample");
33 
34 void
NotifyConnectionEstablishedUe(std::string context,uint64_t imsi,uint16_t cellid,uint16_t rnti)35 NotifyConnectionEstablishedUe (std::string context,
36                                uint64_t imsi,
37                                uint16_t cellid,
38                                uint16_t rnti)
39 {
40   std::cout << Simulator::Now ().As (Time::S) << " " << context
41             << " UE IMSI " << imsi
42             << ": connected to CellId " << cellid
43             << " with RNTI " << rnti
44             << std::endl;
45 }
46 
47 void
NotifyHandoverStartUe(std::string context,uint64_t imsi,uint16_t cellid,uint16_t rnti,uint16_t targetCellId)48 NotifyHandoverStartUe (std::string context,
49                        uint64_t imsi,
50                        uint16_t cellid,
51                        uint16_t rnti,
52                        uint16_t targetCellId)
53 {
54   std::cout << Simulator::Now ().As (Time::S) << " " << context
55             << " UE IMSI " << imsi
56             << ": previously connected to CellId " << cellid
57             << " with RNTI " << rnti
58             << ", doing handover to CellId " << targetCellId
59             << std::endl;
60 }
61 
62 void
NotifyHandoverEndOkUe(std::string context,uint64_t imsi,uint16_t cellid,uint16_t rnti)63 NotifyHandoverEndOkUe (std::string context,
64                        uint64_t imsi,
65                        uint16_t cellid,
66                        uint16_t rnti)
67 {
68   std::cout << Simulator::Now ().As (Time::S) << " " << context
69             << " UE IMSI " << imsi
70             << ": successful handover to CellId " << cellid
71             << " with RNTI " << rnti
72             << std::endl;
73 }
74 
75 void
NotifyConnectionEstablishedEnb(std::string context,uint64_t imsi,uint16_t cellid,uint16_t rnti)76 NotifyConnectionEstablishedEnb (std::string context,
77                                 uint64_t imsi,
78                                 uint16_t cellid,
79                                 uint16_t rnti)
80 {
81   std::cout << Simulator::Now ().As (Time::S) << " " << context
82             << " eNB CellId " << cellid
83             << ": successful connection of UE with IMSI " << imsi
84             << " RNTI " << rnti
85             << std::endl;
86 }
87 
88 void
NotifyHandoverStartEnb(std::string context,uint64_t imsi,uint16_t cellid,uint16_t rnti,uint16_t targetCellId)89 NotifyHandoverStartEnb (std::string context,
90                         uint64_t imsi,
91                         uint16_t cellid,
92                         uint16_t rnti,
93                         uint16_t targetCellId)
94 {
95   std::cout << Simulator::Now ().As (Time::S) << " " << context
96             << " eNB CellId " << cellid
97             << ": start handover of UE with IMSI " << imsi
98             << " RNTI " << rnti
99             << " to CellId " << targetCellId
100             << std::endl;
101 }
102 
103 void
NotifyHandoverEndOkEnb(std::string context,uint64_t imsi,uint16_t cellid,uint16_t rnti)104 NotifyHandoverEndOkEnb (std::string context,
105                         uint64_t imsi,
106                         uint16_t cellid,
107                         uint16_t rnti)
108 {
109   std::cout << Simulator::Now ().As (Time::S) << " " << context
110             << " eNB CellId " << cellid
111             << ": completed handover of UE with IMSI " << imsi
112             << " RNTI " << rnti
113             << std::endl;
114 }
115 
116 
117 /**
118  * Sample simulation script for a X2-based handover.
119  * It instantiates two eNodeB, attaches one UE to the 'source' eNB and
120  * triggers a handover of the UE towards the 'target' eNB.
121  */
122 int
main(int argc,char * argv[])123 main (int argc, char *argv[])
124 {
125   // LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_ALL);
126 
127   // LogComponentEnable ("LteHelper", logLevel);
128   // LogComponentEnable ("EpcHelper", logLevel);
129   // LogComponentEnable ("EpcEnbApplication", logLevel);
130   // LogComponentEnable ("EpcMmeApplication", logLevel);
131   // LogComponentEnable ("EpcPgwApplication", logLevel);
132   // LogComponentEnable ("EpcSgwApplication", logLevel);
133   // LogComponentEnable ("EpcX2", logLevel);
134 
135   // LogComponentEnable ("LteEnbRrc", logLevel);
136   // LogComponentEnable ("LteEnbNetDevice", logLevel);
137   // LogComponentEnable ("LteUeRrc", logLevel);
138   // LogComponentEnable ("LteUeNetDevice", logLevel);
139 
140   uint16_t numberOfUes = 1;
141   uint16_t numberOfEnbs = 2;
142   uint16_t numBearersPerUe = 2;
143   Time simTime = MilliSeconds (490);
144   double distance = 100.0;
145   bool disableDl = false;
146   bool disableUl = false;
147 
148   // change some default attributes so that they are reasonable for
149   // this scenario, but do this before processing command line
150   // arguments, so that the user is allowed to override these settings
151   Config::SetDefault ("ns3::UdpClient::Interval", TimeValue (MilliSeconds (10)));
152   Config::SetDefault ("ns3::UdpClient::MaxPackets", UintegerValue (1000000));
153   Config::SetDefault ("ns3::LteHelper::UseIdealRrc", BooleanValue (false));
154 
155   // Command line arguments
156   CommandLine cmd (__FILE__);
157   cmd.AddValue ("numberOfUes", "Number of UEs", numberOfUes);
158   cmd.AddValue ("numberOfEnbs", "Number of eNodeBs", numberOfEnbs);
159   cmd.AddValue ("simTime", "Total duration of the simulation", simTime);
160   cmd.AddValue ("disableDl", "Disable downlink data flows", disableDl);
161   cmd.AddValue ("disableUl", "Disable uplink data flows", disableUl);
162   cmd.Parse (argc, argv);
163 
164 
165   Ptr<LteHelper> lteHelper = CreateObject<LteHelper> ();
166   Ptr<PointToPointEpcHelper> epcHelper = CreateObject<PointToPointEpcHelper> ();
167   lteHelper->SetEpcHelper (epcHelper);
168   lteHelper->SetSchedulerType ("ns3::RrFfMacScheduler");
169   lteHelper->SetHandoverAlgorithmType ("ns3::NoOpHandoverAlgorithm"); // disable automatic handover
170 
171   Ptr<Node> pgw = epcHelper->GetPgwNode ();
172 
173   // Create a single RemoteHost
174   NodeContainer remoteHostContainer;
175   remoteHostContainer.Create (1);
176   Ptr<Node> remoteHost = remoteHostContainer.Get (0);
177   InternetStackHelper internet;
178   internet.Install (remoteHostContainer);
179 
180   // Create the Internet
181   PointToPointHelper p2ph;
182   p2ph.SetDeviceAttribute ("DataRate", DataRateValue (DataRate ("100Gb/s")));
183   p2ph.SetDeviceAttribute ("Mtu", UintegerValue (1500));
184   p2ph.SetChannelAttribute ("Delay", TimeValue (Seconds (0.010)));
185   NetDeviceContainer internetDevices = p2ph.Install (pgw, remoteHost);
186   Ipv4AddressHelper ipv4h;
187   ipv4h.SetBase ("1.0.0.0", "255.0.0.0");
188   Ipv4InterfaceContainer internetIpIfaces = ipv4h.Assign (internetDevices);
189   Ipv4Address remoteHostAddr = internetIpIfaces.GetAddress (1);
190 
191 
192   // Routing of the Internet Host (towards the LTE network)
193   Ipv4StaticRoutingHelper ipv4RoutingHelper;
194   Ptr<Ipv4StaticRouting> remoteHostStaticRouting = ipv4RoutingHelper.GetStaticRouting (remoteHost->GetObject<Ipv4> ());
195   // interface 0 is localhost, 1 is the p2p device
196   remoteHostStaticRouting->AddNetworkRouteTo (Ipv4Address ("7.0.0.0"), Ipv4Mask ("255.0.0.0"), 1);
197 
198   NodeContainer ueNodes;
199   NodeContainer enbNodes;
200   enbNodes.Create (numberOfEnbs);
201   ueNodes.Create (numberOfUes);
202 
203   // Install Mobility Model
204   Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
205   for (uint16_t i = 0; i < numberOfEnbs; i++)
206     {
207       positionAlloc->Add (Vector (distance * 2 * i - distance, 0, 0));
208     }
209   for (uint16_t i = 0; i < numberOfUes; i++)
210     {
211       positionAlloc->Add (Vector (0, 0, 0));
212     }
213   MobilityHelper mobility;
214   mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
215   mobility.SetPositionAllocator (positionAlloc);
216   mobility.Install (enbNodes);
217   mobility.Install (ueNodes);
218 
219   // Install LTE Devices in eNB and UEs
220   NetDeviceContainer enbLteDevs = lteHelper->InstallEnbDevice (enbNodes);
221   NetDeviceContainer ueLteDevs = lteHelper->InstallUeDevice (ueNodes);
222 
223   // Install the IP stack on the UEs
224   internet.Install (ueNodes);
225   Ipv4InterfaceContainer ueIpIfaces;
226   ueIpIfaces = epcHelper->AssignUeIpv4Address (NetDeviceContainer (ueLteDevs));
227 
228 
229   // Attach all UEs to the first eNodeB
230   for (uint16_t i = 0; i < numberOfUes; i++)
231     {
232       lteHelper->Attach (ueLteDevs.Get (i), enbLteDevs.Get (0));
233     }
234 
235 
236   NS_LOG_LOGIC ("setting up applications");
237 
238   // Install and start applications on UEs and remote host
239   uint16_t dlPort = 10000;
240   uint16_t ulPort = 20000;
241 
242   // randomize a bit start times to avoid simulation artifacts
243   // (e.g., buffer overflows due to packet transmissions happening
244   // exactly at the same time)
245   Ptr<UniformRandomVariable> startTimeSeconds = CreateObject<UniformRandomVariable> ();
246   startTimeSeconds->SetAttribute ("Min", DoubleValue (0.05));
247   startTimeSeconds->SetAttribute ("Max", DoubleValue (0.06));
248 
249   for (uint32_t u = 0; u < numberOfUes; ++u)
250     {
251       Ptr<Node> ue = ueNodes.Get (u);
252       // Set the default gateway for the UE
253       Ptr<Ipv4StaticRouting> ueStaticRouting = ipv4RoutingHelper.GetStaticRouting (ue->GetObject<Ipv4> ());
254       ueStaticRouting->SetDefaultRoute (epcHelper->GetUeDefaultGatewayAddress (), 1);
255 
256       for (uint32_t b = 0; b < numBearersPerUe; ++b)
257         {
258           ApplicationContainer clientApps;
259           ApplicationContainer serverApps;
260           Ptr<EpcTft> tft = Create<EpcTft> ();
261 
262           if (!disableDl)
263             {
264               ++dlPort;
265 
266               NS_LOG_LOGIC ("installing UDP DL app for UE " << u);
267               UdpClientHelper dlClientHelper (ueIpIfaces.GetAddress (u), dlPort);
268               clientApps.Add (dlClientHelper.Install (remoteHost));
269               PacketSinkHelper dlPacketSinkHelper ("ns3::UdpSocketFactory",
270                                                    InetSocketAddress (Ipv4Address::GetAny (), dlPort));
271               serverApps.Add (dlPacketSinkHelper.Install (ue));
272 
273               EpcTft::PacketFilter dlpf;
274               dlpf.localPortStart = dlPort;
275               dlpf.localPortEnd = dlPort;
276               tft->Add (dlpf);
277             }
278 
279           if (!disableUl)
280             {
281               ++ulPort;
282 
283               NS_LOG_LOGIC ("installing UDP UL app for UE " << u);
284               UdpClientHelper ulClientHelper (remoteHostAddr, ulPort);
285               clientApps.Add (ulClientHelper.Install (ue));
286               PacketSinkHelper ulPacketSinkHelper ("ns3::UdpSocketFactory",
287                                                    InetSocketAddress (Ipv4Address::GetAny (), ulPort));
288               serverApps.Add (ulPacketSinkHelper.Install (remoteHost));
289 
290               EpcTft::PacketFilter ulpf;
291               ulpf.remotePortStart = ulPort;
292               ulpf.remotePortEnd = ulPort;
293               tft->Add (ulpf);
294             }
295 
296           EpsBearer bearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT);
297           lteHelper->ActivateDedicatedEpsBearer (ueLteDevs.Get (u), bearer, tft);
298 
299           Time startTime = Seconds (startTimeSeconds->GetValue ());
300           serverApps.Start (startTime);
301           clientApps.Start (startTime);
302           clientApps.Stop (simTime);
303 
304         } // end for b
305     }
306 
307 
308   // Add X2 interface
309   lteHelper->AddX2Interface (enbNodes);
310 
311   // X2-based Handover
312   lteHelper->HandoverRequest (MilliSeconds (300), ueLteDevs.Get (0), enbLteDevs.Get (0), enbLteDevs.Get (1));
313 
314   // Uncomment to enable PCAP tracing
315   //p2ph.EnablePcapAll("lena-x2-handover");
316 
317   lteHelper->EnablePhyTraces ();
318   lteHelper->EnableMacTraces ();
319   lteHelper->EnableRlcTraces ();
320   lteHelper->EnablePdcpTraces ();
321   Ptr<RadioBearerStatsCalculator> rlcStats = lteHelper->GetRlcStats ();
322   rlcStats->SetAttribute ("EpochDuration", TimeValue (Seconds (0.05)));
323   Ptr<RadioBearerStatsCalculator> pdcpStats = lteHelper->GetPdcpStats ();
324   pdcpStats->SetAttribute ("EpochDuration", TimeValue (Seconds (0.05)));
325 
326 
327   // connect custom trace sinks for RRC connection establishment and handover notification
328   Config::Connect ("/NodeList/*/DeviceList/*/LteEnbRrc/ConnectionEstablished",
329                    MakeCallback (&NotifyConnectionEstablishedEnb));
330   Config::Connect ("/NodeList/*/DeviceList/*/LteUeRrc/ConnectionEstablished",
331                    MakeCallback (&NotifyConnectionEstablishedUe));
332   Config::Connect ("/NodeList/*/DeviceList/*/LteEnbRrc/HandoverStart",
333                    MakeCallback (&NotifyHandoverStartEnb));
334   Config::Connect ("/NodeList/*/DeviceList/*/LteUeRrc/HandoverStart",
335                    MakeCallback (&NotifyHandoverStartUe));
336   Config::Connect ("/NodeList/*/DeviceList/*/LteEnbRrc/HandoverEndOk",
337                    MakeCallback (&NotifyHandoverEndOkEnb));
338   Config::Connect ("/NodeList/*/DeviceList/*/LteUeRrc/HandoverEndOk",
339                    MakeCallback (&NotifyHandoverEndOkUe));
340 
341 
342   Simulator::Stop (simTime + MilliSeconds (20));
343   Simulator::Run ();
344 
345   // GtkConfigStore config;
346   // config.ConfigureAttributes ();
347 
348   Simulator::Destroy ();
349   return 0;
350 }
351