aboutsummaryrefslogtreecommitdiffstats
path: root/emu-radio/lte-emulator/lte_main.cc
diff options
context:
space:
mode:
Diffstat (limited to 'emu-radio/lte-emulator/lte_main.cc')
-rw-r--r--emu-radio/lte-emulator/lte_main.cc775
1 files changed, 775 insertions, 0 deletions
diff --git a/emu-radio/lte-emulator/lte_main.cc b/emu-radio/lte-emulator/lte_main.cc
new file mode 100644
index 00000000..47992b45
--- /dev/null
+++ b/emu-radio/lte-emulator/lte_main.cc
@@ -0,0 +1,775 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * 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: Xuan Zeng <xuan.zeng@irt-systemx.fr>
+ */
+
+#include <ns3/lte-helper.h>
+#include <ns3/epc-helper.h>
+#include <ns3/core-module.h>
+#include <ns3/network-module.h>
+#include <ns3/ipv4-global-routing-helper.h>
+#include <ns3/internet-module.h>
+#include <ns3/mobility-module.h>
+#include <ns3/lte-module.h>
+#include <ns3/csma-helper.h>
+#include <ns3/tap-bridge-module.h>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/asio.hpp>
+#include <boost/property_tree/json_parser.hpp>
+#include <future>
+#include <unordered_map>
+
+#include "extensions/lte-tap-helper.h"
+#include "extensions/lte-tap-ue-net-device.h"
+
+#define UE_IP_CONFIGURABLE 1
+
+#ifdef UE_IP_CONFIGURABLE
+#include "extensions/tap-point-to-point-epc-helper.h"
+#endif
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+#define CONSTANT_POSITION "constant_position"
+#define RANDOM_WAYPOINT "random_waypoint"
+
+#include "connection-pool.h"
+#include "query.h"
+#include "communication-protocol.h"
+#include "src/lte-emulator.h"
+
+#define DEFAULT_EXPERIMENT_ID "lte-emulation"
+#define N_AP 1
+
+using namespace ns3;
+
+/**
+ * this is a program to emulate a LTE channel with 1 EnodeB and multiple UE clients, which can be
+ * connected to either containers or real machines. IP stack is used interally to forward packets through
+ * epc core.
+ */
+
+
+/**
+ * \brief an helper to assign an IP address to an existing network device
+ * NOTE: if the ip address passed as parameter has been assigned to another device before the call to this function,
+ * ns3 will crash and remind you about IP address conflicts.
+ */
+Ipv4InterfaceContainer AssignAnyIpv4Address (Ptr <NetDevice> device, Ipv4Address ipAddress)
+{
+ Ipv4AddressHelper ueAddrHelper;
+ Ipv4Mask fakemask ("255.255.255.0");//the mask is irrelevant here.
+ Ipv4Mask fakemask2 (ipAddress.Get () & fakemask.Get ());
+ Ipv4Address id = Ipv4Address (ipAddress.Get () ^ fakemask2.Get ());
+
+ ueAddrHelper.SetBase (ipAddress, fakemask2, id);
+ return ueAddrHelper.Assign (NetDeviceContainer (device));
+
+}
+
+/**
+ * \brief a callback to send arp reply when an arp request is received from outside the emulator,
+ * NOTE: we need to wirte code to handle arp request ourselves inside LTE emulator because ARP protocol is not
+ * intrinsically supported by a LTE device(on Enode B or UE). But arp should be needed by the container/VM outside the emulator
+ * program. We implement this callback to solve the incomptability between external container/VM and internal emulated LTE node
+ *
+ */
+void
+SendArpReply (std::vector <std::string> ueIpAddrs, Ptr <NetDevice> device, Ptr<const Packet> p, uint16_t protocol, const Address &from, const Address &to, NetDevice::PacketType packetType)
+{
+ Ptr <Packet> packet = p->Copy ();
+ ArpHeader arp;
+ uint32_t size = packet->RemoveHeader (arp);
+
+ if (size == 0)
+ return;
+
+ if (!arp.IsRequest ())
+ return;
+
+ bool shouldREply = false;
+
+ ///do nothing. Don't send arp reply) if destionation IP address is not equal to one UE's Ip address
+ for (unsigned iUe = 0; iUe < ueIpAddrs.size (); iUe++)
+ {
+ if (arp.GetDestinationIpv4Address () == Ipv4Address (ueIpAddrs.at (iUe)
+ .c_str ()))
+ {
+ shouldREply = true;
+ break;
+ }
+ }
+
+ if (!shouldREply)
+ return;
+
+ Ipv4Address myIp = arp.GetDestinationIpv4Address ();
+ Ipv4Address toIp = arp.GetSourceIpv4Address ();
+ Address toMac = arp.GetSourceHardwareAddress ();
+ ArpHeader replyArp;
+
+ replyArp.SetReply (device->GetAddress (), myIp, toMac, toIp);
+ Ptr <Packet> replyPacket = Create<Packet> ();
+ replyPacket->AddHeader (replyArp);
+ device->Send (replyPacket, toMac, ArpL3Protocol::PROT_NUMBER);
+}
+
+/**
+ * \brief overwrite mac address of emulated device such that it will be the same as that of tap device.
+ * This is require for communication with external containers/VM
+ */
+void setMac (Ptr <NetDevice> m_bridgedDevice, std::string m_tapDeviceName)
+{
+ int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
+
+ /// Bind to that socket and let the kernel allocate an endpoint
+ struct sockaddr_un un;
+ memset (&un, 0, sizeof (un));
+ un.sun_family = AF_UNIX;
+ bind (sock, (struct sockaddr *) &un, sizeof (sa_family_t));
+
+ // Set the ns-3 device's mac address to the overlying container's mac address
+ struct ifreq s;
+ strncpy (s.ifr_name, m_tapDeviceName.c_str (), sizeof (s.ifr_name));
+
+ int ioctlResult = ioctl (sock, SIOCGIFHWADDR, &s);
+
+ if (ioctlResult == 0)
+ {
+ Mac48Address learnedMac;
+ learnedMac.CopyFrom ((uint8_t *) s.ifr_hwaddr
+ .sa_data);
+ m_bridgedDevice->SetAddress (learnedMac);
+ }
+
+ close (sock);
+}
+
+/**
+ * \brief populate arp cache on the emulated pgw node with mac of VM/container in advance,
+ * this is requred when external VM/container uses /32 ip addresses
+ */
+void
+populateArpCache (Ptr <Node> pgw, NetDeviceContainer csmaDevices, Mac48Address bsMac, Ipv4Address bsIp, int numberOfNodes)
+{
+ Ptr <Ipv4L3Protocol> pgwIp = pgw->GetObject<Ipv4L3Protocol> ();
+ NS_ASSERT (pgwIp != 0);
+ ObjectVectorValue interfaces;
+ pgwIp->GetAttribute ("InterfaceList", interfaces);
+ Mac48Address PgwMacAddr = Mac48Address::ConvertFrom (csmaDevices.Get (1)
+ ->GetAddress ());
+
+ for (ObjectVectorValue::Iterator j = interfaces.Begin (); j != interfaces.End (); j++)
+ {
+ Ptr <Ipv4Interface> ipIface = (*j).second
+ ->GetObject<Ipv4Interface> ();
+ NS_ASSERT (ipIface != 0);
+ //std::cout<<"ip addr="<<ipIface->GetAddress(0).GetLocal()<<"\n";
+ Ptr <NetDevice> device = ipIface->GetDevice ();
+
+ if (device == csmaDevices.Get (1))///the csma interface on pgw
+ {
+ Ptr <ArpCache> cache = ipIface->GetArpCache ();
+ ArpCache::Entry *entry = cache->Add (bsIp);
+ entry->MarkWaitReply (0);
+ entry->MarkAlive (bsMac);
+ entry->MarkPermanent ();
+ break;
+ }
+ }
+}
+
+int main (int argc, char *argv[])
+{
+
+ //////////////////////
+ //
+ // parameter list:
+ //
+ /////////////////////
+ double distance = 1; //in meters, initial distance between UEs and Enode B
+ unsigned uplinkBW = 100;
+ unsigned downlinkBW = 100;
+ unsigned lteTxMode = 2;//0=SISO,1=Tx diversity,2=spatial multiplexing
+ std::string pathLossModel = "ns3::Cost231PropagationLossModel";//ns3::FriisPropagationLossModel
+ //FriisSpectrumPropagationLossModel//Cost231PropagationLossModel
+
+ bool isUeFixed = false;///for debugging purpose only
+ std::string fadingModel = "ns3::TraceFadingLossModel";
+ std::string fadingTrace = "/usr/share/lte-emulator/fading_trace_EPA_3kmph.fad";
+ bool isFading = true;
+ int AmcModel = LteAmc::PiroEW2010;//PiroEW2010 or MiErrorModel
+ unsigned rccTxBuffer = 1500 * 140;//140 packets
+ bool isAMRccEnabled = false;
+ bool isLogging = true;
+ bool isIpPrint = false;
+
+ GlobalValue::Bind ("SimulatorImplementationType", StringValue ("ns3::RealtimeSimulatorImpl"));
+ GlobalValue::Bind ("ChecksumEnabled", BooleanValue (true));
+
+
+ //////////////////////////
+ //
+ // Command line parsing
+ //
+ //////////////////////////
+
+ std::string bs_x_str = "";
+ std::string bs_y_str = "";
+ std::string bs_name = "";
+ std::string bs_tap = "";
+ std::string sta_list_str = "";
+ std::string sta_taps_str = "";
+
+ std::string sta_ips_str = "";
+
+ std::string sta_macs_str = "";
+ std::string n_sta_str = "";
+ std::string bs_mac_str = "";
+ std::string experiment_id_str = "";
+ std::string control_port_str = "";
+
+ std::string bs_ip_str = "";
+
+ CommandLine cmd;
+ cmd.AddValue ("bs-tap", "Name of the tap between NS3 and the base station", bs_tap);
+ cmd.AddValue ("n-sta", "Number of stations", n_sta_str);
+ cmd.AddValue ("sta-list", "List of the stations of the simulation", sta_list_str);
+ cmd.AddValue ("sta-taps", "List of the taps between NS3 and the mobile stations", sta_taps_str);
+
+ cmd.AddValue ("sta-ips", "List of the IPs of the UEs in the format of 1.0.0.3/24,1.0.0.4/24 ...", sta_ips_str);
+
+ cmd.AddValue ("sta-macs", "List of the macs of the mobile stations", sta_macs_str);
+ cmd.AddValue ("bs-x", "X position of the Base Station", bs_x_str);
+ cmd.AddValue ("bs-y", "Y position of the Base Station", bs_y_str);
+ cmd.AddValue ("experiment-id", "Unique identifier for the experiment", experiment_id_str);
+ cmd.AddValue ("bs-name", "Index of the base station", bs_name);
+ cmd.AddValue ("bs-mac", "Base station MAC address", bs_mac_str);
+ cmd.AddValue ("bs-ip", "Base station IP address, in the format of 192.0.0.3/24", bs_ip_str);
+
+ cmd.AddValue ("control-port", "Control port for dynamically managing the stations movement", control_port_str);
+
+ cmd.AddValue<double> ("distance", "Initial distance between the bs and the other stations", distance);
+
+ ///parameters for configuring the lte channel
+ cmd.AddValue ("txBuffer", "rcc tx buffer", rccTxBuffer);
+ cmd.AddValue ("isFading", "whether to enable fading in the channel", isFading);
+ cmd.AddValue ("fadingTrace", "the fading trace file name", fadingTrace);
+
+
+ ///parameters for debugging the lte channel
+ cmd.AddValue ("printIP", "whether to print IP addresses in simulation", isIpPrint);
+ cmd.AddValue ("isUeFixed", "whether ue moves or not, this is used for testing without mobility server", isUeFixed);
+
+ ///log physical rate used by LTE device
+ cmd.AddValue ("logging", "whether to log statistics of lte mac and physical layer", isLogging);
+
+ cmd.Parse (argc, argv);
+
+ if (bs_tap == "" || n_sta_str == "" || sta_list_str == "" || sta_taps_str == "" || sta_macs_str == ""
+ || sta_ips_str == "" ||
+
+ bs_x_str == "" || bs_y_str == "" || bs_name == "" || bs_mac_str == "" ||
+
+ bs_ip_str == "" || control_port_str == "" || experiment_id_str == "")
+ {
+ std::cerr << "Important parameters are missing!" << std::endl;
+ return -1;
+ }
+
+ //////////////////////////////////
+ //
+ // further comandline parsing
+ //
+ //////////////////////////////////
+ std::list <std::string> station_list;
+ boost::split (station_list, sta_list_str, boost::is_any_of (","));
+
+ std::list <std::string> taps_list;
+ boost::split (taps_list, sta_taps_str, boost::is_any_of (","));
+
+ std::list <std::string> macs_list;
+ boost::split (macs_list, sta_macs_str, boost::is_any_of (","));
+
+ std::list <std::string> sta_ips_list;
+ boost::split (sta_ips_list, sta_ips_str, boost::is_any_of (","));
+
+
+ //UE IPs
+ std::vector <std::string> ueIpAddrs;
+ std::string Ip1;
+ std::string mask1;
+
+ std::list<std::string>::const_iterator sta_ip_i;
+ bool first = true;
+ for (sta_ip_i = sta_ips_list.begin (); sta_ip_i != sta_ips_list.end (); sta_ip_i++)
+ {
+ std::list <std::string> ipComponents;
+ boost::split (ipComponents, *sta_ip_i, boost::is_any_of ("/"));
+ ueIpAddrs.push_back (ipComponents.front ());
+ if (first)
+ {
+ Ip1 = ipComponents.front ();
+ mask1 = "/" + (ipComponents.back ());
+ first = false;
+ }
+ }
+
+ ///BS IP configuration using the one passed from command line
+ std::list <std::string> BsIpAddr;
+ boost::split (BsIpAddr, bs_ip_str, boost::is_any_of ("/"));
+
+ std::string bsIp = BsIpAddr.front ();
+ std::string bsMask = "/" + (BsIpAddr.back ());
+
+ ///number of UEs
+ uint16_t numberOfNodes = (uint16_t) atoi (n_sta_str.c_str ());
+
+ //maximum value of id portion of ip address(to avoid address conflicts)
+ uint32_t maxIP = Ipv4Address (bsIp.c_str ()).Get ();//max first initialized to bs' ip
+ for (uint16_t iUe = 0; iUe < numberOfNodes; iUe++)
+ {
+ uint32_t ueIP = Ipv4Address (ueIpAddrs.at (iUe)
+ .c_str ()).Get ();
+ if (ueIP > maxIP)
+ maxIP = ueIP;
+ }
+
+ /**
+ * TO handle the extrem case of all /32 ip address. while assigned /32 ip address might be replaced with /24 ones in the emulator, the external container/VM
+ * can keep using /32 address, the behaviour shall be consistent even in case of /32 address are used
+ */
+ if (bsMask == "/32")
+ bsMask = "/24";
+ if (mask1 == "/32")
+ mask1 = "/24";
+
+ ///to check ip address duplicaton, since the ip address are assigned by lurch and not guaranteed to be in a sequential way
+ uint32_t bsMaskInNumber = (Ipv4Mask (bsMask.c_str ()).Get ());
+ uint32_t bsIpInNumber = Ipv4Address (bsIp.c_str ()).Get ();
+ uint32_t bsPrefix = bsIpInNumber & bsMaskInNumber;
+ uint32_t uePrefix = Ipv4Address (Ip1.c_str ()).Get () & (Ipv4Mask (mask1.c_str ()).Get ());
+ uint32_t maxId = (maxIP & bsMaskInNumber) ^maxIP;
+ uint32_t nextId = ((uint32_t) (2e32 - 1) ^ bsMaskInNumber) & (maxId + 1);
+ uint32_t nextIP = bsPrefix | nextId;// nextIP that can be used, it's to be assigned to LTE gateway(pgw)
+ uint32_t next2IP = 0;// the next next IP that can be used, it's to be assigned to LTE inner network
+ uint32_t inc = 2;
+ bool duplicated = true;
+
+ int trials = 0;
+ //after 10 trials, we will leave the ns3 system to detect duplicate IP addresses allocation and crash
+ while (duplicated && trials
+ < 10)//normally we don't have address collisions, so we are not going to iterate many times to get a combination of IP address configuration matching requrements passed from command line
+ {
+ trials++;
+ next2IP = (((int) (2e32 - 1) ^ bsMaskInNumber) & (maxId + inc)) | uePrefix;
+ duplicated = false;
+ if (next2IP == bsIpInNumber || next2IP + 1 == bsIpInNumber)
+ duplicated = true;
+
+ for (uint16_t iUe = 0; iUe < numberOfNodes; iUe++)
+ {
+ uint32_t ueIP = Ipv4Address (ueIpAddrs.at (iUe)
+ .c_str ()).Get ();
+ if (next2IP == ueIP || next2IP + 1 == ueIP)
+ duplicated = true;
+ }
+ inc++;
+ }
+
+
+
+
+
+ //control port
+ unsigned short control_port = (unsigned short) atoi (control_port_str.c_str ());
+
+ //bs position
+ double bs_x = atof (bs_x_str.c_str ());
+ double bs_y = atof (bs_y_str.c_str ());
+
+
+ //////////////////////////////////
+ //
+ // configure lte channel
+ //
+ //////////////////////////////////
+
+ Config::SetDefault ("ns3::LteEnbNetDevice::UlBandwidth", UintegerValue (uplinkBW));
+ Config::SetDefault ("ns3::LteEnbNetDevice::DlBandwidth", UintegerValue (downlinkBW));
+ Config::SetDefault ("ns3::LteEnbRrc::DefaultTransmissionMode", UintegerValue (lteTxMode));
+ Config::SetDefault ("ns3::LteHelper::PathlossModel", StringValue (pathLossModel));
+ Config::SetDefault ("ns3::LteHelper::Scheduler", StringValue ("ns3::PfFfMacScheduler"));
+
+ ///NOTE: ref: https://sites.google.com/site/lteencyclopedia/lte-radio-link-budgeting-and-rf-planning, gives the following set of parameters. Not used in our emulator any more
+ /*
+ Config::SetDefault("ns3::LteUePhy::TxPower", DoubleValue(24));
+ Config::SetDefault("ns3::LteUePhy::NoiseFigure", DoubleValue(7.0));
+ Config::SetDefault("ns3::LteEnbPhy::TxPower", DoubleValue(46));
+ Config::SetDefault("ns3::LteEnbPhy::NoiseFigure", DoubleValue(2.0));
+ */
+
+ /*error model configuration*/
+ if (AmcModel == LteAmc::PiroEW2010)
+ {
+ Config::SetDefault ("ns3::LteAmc::AmcModel", EnumValue (LteAmc::PiroEW2010));
+ Config::SetDefault ("ns3::LteAmc::Ber", DoubleValue (0.00005));
+ }
+ else
+ {
+ Config::SetDefault ("ns3::LteAmc::AmcModel", EnumValue (LteAmc::MiErrorModel));
+ }
+
+ if (isAMRccEnabled)
+ Config::SetDefault ("ns3::LteEnbRrc::EpsBearerToRlcMapping", EnumValue (ns3::LteEnbRrc::RLC_AM_ALWAYS));
+
+ ///rcc layer tx queue Buffer size in bytes, having impact on throughput performance, idealy should be equal to DBP
+ Config::SetDefault ("ns3::LteRlcUm::MaxTxBufferSize", UintegerValue (rccTxBuffer));//140 packets with 1500bytes
+
+ ///create lte helper with our patch to support tap device and lte channel emulation
+ Ptr <LteTapHelper> lteHelper = CreateObject<LteTapHelper> ();
+
+ ///channel fading configuration
+ if (isFading)
+ {
+ ///for fading configuration:
+ lteHelper->SetAttribute ("FadingModel", StringValue (fadingModel));
+
+ std::ifstream ifTraceFile;
+ ifTraceFile.open (fadingTrace.c_str (), std::ifstream::in);
+ if (ifTraceFile.good ()) //trace file can be found
+ {
+ lteHelper->SetFadingModelAttribute ("TraceFilename", StringValue (fadingTrace));
+ }
+ else
+ {
+ ifTraceFile.close ();
+ std::ifstream ifTraceFile2;
+ ifTraceFile2.open ("fading-traces/fading_trace_EPA_3kmph.fad", std::ifstream::in);
+ if (ifTraceFile2.good ())
+ {
+ lteHelper->SetFadingModelAttribute ("TraceFilename", StringValue ("fading-traces/fading_trace_EPA_3kmph.fad"));
+ }
+ else
+ {
+ std::cout << "WARNING: fading trace file not found, fading disabled\n";
+ }
+ }
+
+ // these parameters have to set only in case of the trace format
+ // differs from the standard one, that is
+ // - 10 seconds length trace
+ // - 10,000 samples
+ // - 0.5 seconds for window size
+ // - 100 RB
+ lteHelper->SetFadingModelAttribute ("TraceLength", TimeValue (Seconds (10.0)));
+ lteHelper->SetFadingModelAttribute ("SamplesNum", UintegerValue (10000));
+ lteHelper->SetFadingModelAttribute ("WindowSize", TimeValue (Seconds (0.5)));
+ lteHelper->SetFadingModelAttribute ("RbNum", UintegerValue (100));
+ }
+
+#ifdef UE_IP_CONFIGURABLE
+ Ptr <TapPointToPointEpcHelper> epcHelper = CreateObject<TapPointToPointEpcHelper> (Ip1, mask1, maxIP
+ + 2);//reserve one for pgw out interface
+#else
+ Ptr<PointToPointEpcHelper> epcHelper = CreateObject<PointToPointEpcHelper> ();
+#endif
+
+ lteHelper->SetEpcHelper (epcHelper);
+
+ Ptr <Node> pgw = epcHelper->GetPgwNode ();
+
+ ///Create a ghost node for representing the container/VM on pgw side in the emulator
+ NodeContainer remoteHostContainer;
+ remoteHostContainer.Create (1);
+ Ptr <Node> ghostNode = remoteHostContainer.Get (0);
+ InternetStackHelper internet;
+ internet.Install (remoteHostContainer);
+
+ ///Create the Internet using CSMA link
+ CsmaHelper csmah;
+ NodeContainer csmaNodes (ghostNode);
+
+ ///install internet stack for pgw node:
+ csmaNodes.Add (pgw);
+ csmah.SetChannelAttribute ("DataRate", DataRateValue (DataRate ("1Gb/s")));
+ csmah.SetDeviceAttribute ("Mtu", UintegerValue (1500));
+ csmah.SetChannelAttribute ("Delay", TimeValue (Seconds (0)));//small enough
+ NetDeviceContainer csmaDevices = csmah.Install (csmaNodes);
+
+ AssignAnyIpv4Address (csmaDevices.Get (0), bsIp.c_str ());//assign explicity an address to ghost/BS node because it must be the same as that in VM
+
+ Ipv4Address addrghost = ghostNode->GetObject<Ipv4> ()
+ ->GetAddress (1, 0)
+ .GetLocal ();
+
+ Ipv4InterfaceContainer interfacesipv4csma = AssignAnyIpv4Address (csmaDevices.Get (1), Ipv4Address (nextIP));;//next IP after max IP assigned to ue and enode B
+
+ ///NOTE: this is to handle arp request
+ pgw->RegisterProtocolHandler (MakeBoundCallback (&SendArpReply, ueIpAddrs), ArpL3Protocol::PROT_NUMBER, csmaDevices.Get (1)/*, true*/);
+ ///set a route to ghost node only on pgw, otherwise packets for uplink cannot come back
+ Ipv4StaticRoutingHelper ipv4RoutingHelper;
+
+ ///uncoment the following to see ip routing table
+ // Ptr<OutputStreamWrapper> routintable = Create<OutputStreamWrapper>("routingtable",std::ios::out);
+ // ipv4RoutingHelper.PrintRoutingTableAt(Seconds(0), pgw, routintable);
+ Ptr <Ipv4StaticRouting> pgwStaticRouting = ipv4RoutingHelper.GetStaticRouting (pgw->GetObject<Ipv4> ());
+ pgwStaticRouting->AddHostRouteTo (Ipv4Address (bsIp.c_str ()), 2);
+
+ ///add route for each UE manually to support /32 address for UE
+ for (int ith = 0; ith < numberOfNodes; ith++)
+ {
+ pgwStaticRouting->AddHostRouteTo (Ipv4Address (ueIpAddrs.at (ith)
+ .c_str ()), 1);
+ }
+
+ if (isIpPrint)
+ {
+ std::cout << "ghost node IP address=" << addrghost << "\n";
+ std::cout << "pgw IP addressOut=" << pgw->GetObject<Ipv4> ()
+ ->GetAddress (2, 0)
+ .GetLocal () << "\n";
+ std::cout << "pgw IP addressIn=" << pgw->GetObject<Ipv4> ()
+ ->GetAddress (1, 0)
+ .GetLocal () << "\n";
+ }
+
+ ///ue and enodeB nodes
+ NodeContainer ueNodes;
+ NodeContainer enbNodes;
+ enbNodes.Create (1);
+ ueNodes.Create (numberOfNodes);
+
+ ///populate arp cache, necessary if the external VM container are configured to use /32 IP addresses
+ populateArpCache (pgw, csmaDevices, Mac48Address (bs_mac_str.c_str ()), Ipv4Address (bsIp.c_str ()), numberOfNodes);
+
+ ////////////////////////////////////
+ //
+ // initial Mobility Configuration
+ //
+ ////////////////////////////////////
+
+ /// Install Mobility Model for enodeB
+ Ptr <ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
+ positionAlloc->Add (Vector (bs_x, bs_y, 0));
+ MobilityHelper mobility;
+ mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+ mobility.SetPositionAllocator (positionAlloc);
+ mobility.Install (enbNodes);
+
+ if (isUeFixed)
+ {
+ ///install mobility for UE
+ Ptr <ListPositionAllocator> UEpositionAlloc = CreateObject<ListPositionAllocator> ();
+ for (uint16_t i = 0; i < numberOfNodes; i++)
+ {
+ UEpositionAlloc->Add (Vector (distance * i, distance, 0));
+ }
+
+ mobility.SetPositionAllocator (UEpositionAlloc);
+ mobility.Install (ueNodes);
+ }
+ else
+ {
+ // UEs mobility. By default the UEs start from the same position of the Enode B
+ MobilityHelper staMobility;
+ Ptr <ListPositionAllocator> UEpositionAlloc = CreateObject<ListPositionAllocator> ();
+ for (uint16_t i = 0; i < numberOfNodes; i++)
+ {
+ UEpositionAlloc->Add (Vector (bs_x, bs_y + distance, 0.0));
+ }
+ staMobility.SetPositionAllocator (UEpositionAlloc);
+ staMobility.SetMobilityModel ("ns3::WaypointMobilityModel", "InitialPositionIsWaypoint", BooleanValue (false));
+ staMobility.Install (ueNodes);
+ }
+
+
+
+ /// Install LTE Devices to the enodeB and UE nodes
+ NetDeviceContainer enbLteDevs = lteHelper->InstallEnbDevice (enbNodes);
+ NetDeviceContainer ueLteDevs = lteHelper->InstallUeDevice (ueNodes);
+
+ /// Install the IP stack on the UEs
+ internet.Install (ueNodes);
+ Ipv4InterfaceContainer ueIpIface;
+#ifdef UE_IP_CONFIGURABLE
+ for (unsigned i = 0; i < ueLteDevs.GetN (); i++)
+ ueIpIface.Add (epcHelper->AssignUeIpv4Address (ueLteDevs.Get (i), ueIpAddrs.at (i)
+ .c_str ()));
+#else
+ ueIpIface = epcHelper->AssignUeIpv4Address (NetDeviceContainer (ueLteDevs));
+#endif
+
+ /// Assign IP address to UEs, and set default gateways for them
+ for (uint32_t u = 0; u < ueNodes.GetN (); ++u)
+ {
+ Ptr <Node> ueNode = ueNodes.Get (u);
+ /// Set the default gateway for the UE
+ Ptr <Ipv4StaticRouting> ueStaticRouting = ipv4RoutingHelper.GetStaticRouting (ueNode->GetObject<Ipv4> ());
+ ueStaticRouting->SetDefaultRoute (epcHelper->GetUeDefaultGatewayAddress (), 1);
+ Ptr <Ipv4> ipv4ue = ueNode->GetObject<Ipv4> (); // Get Ipv4 instance of the node
+ Ipv4Address addrUe = ipv4ue->GetAddress (1, 0)
+ .GetLocal ();
+ if (isIpPrint)
+ {
+ std::cout << "ue IP address=" << addrUe << "\n";
+ std::cout << "ue gateway=" << epcHelper->GetUeDefaultGatewayAddress () << "\n";
+ }
+ }
+
+ if (isIpPrint)
+ {
+ Ptr <Ipv4> ipv4enb = enbNodes.Get (0)
+ ->GetObject<Ipv4> ();
+ Ipv4Address addrenb = ipv4enb->GetAddress (1, 0)
+ .GetLocal ();
+ std::cout << "enb IP address to ue=" << addrenb << "\n";
+ }
+
+
+
+ /// Attach UEs to eNodeB
+ for (uint16_t i = 0; i < numberOfNodes; i++)
+ {
+ lteHelper->Attach (ueLteDevs.Get (i), enbLteDevs.Get (0));
+ }
+ lteHelper->ActivateDedicatedEpsBearer (ueLteDevs, EpsBearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT), EpcTft::Default ());
+
+ //uncomment the following to enable full lte traces
+ //lteHelper->EnableTraces ();
+ // Uncomment to enable PCAP tracing
+ //p2ph.EnablePcapAll("lena-epc-first");
+
+
+
+ //////////////////////////////////////
+ //
+ // TapBridge devices configuration
+ //
+ /////////////////////////////////////
+
+ TapBridgeHelper tapBridge;
+ tapBridge.SetAttribute ("Mode", StringValue ("UseLocal"));
+
+ std::unordered_map <std::string, ns3::Ptr<ns3::Node>> map_name_ns3node;
+ std::list<std::string>::const_iterator station;
+ std::list<std::string>::const_iterator tap_sta;
+ std::list<std::string>::const_iterator mac_sta;
+ uint32_t i;
+
+ //install tapbridge for UEs
+ for (tap_sta = taps_list.begin (), mac_sta = macs_list.begin (), station = station_list.begin (), i = 0;
+ tap_sta != taps_list.end () && mac_sta != macs_list.end ()
+ && station != station_list.end (); tap_sta++, mac_sta++, station++, i++)
+ {
+ map_name_ns3node[*station] = ueNodes.Get (i);
+ ueLteDevs.Get (i)
+ ->GetObject<LteTapUeNetDevice> ()
+ ->setMacAdressOnVM (Mac48Address (mac_sta->c_str ()));
+ ueLteDevs.Get (i)
+ ->GetObject<LteTapUeNetDevice> ()
+ ->setBsIpAddress (Ipv4Address (bsIp.c_str ()));
+
+ tapBridge.SetAttribute ("DeviceName", StringValue (tap_sta->c_str ()));
+ tapBridge.Install (ueNodes.Get (i), ueLteDevs.Get (i));
+ setMac (ueLteDevs.Get (i), *tap_sta);
+ }
+
+ map_name_ns3node[bs_name] = enbNodes.Get (0);
+
+ ///install tapbridge for eNodeB
+ tapBridge.SetAttribute ("DeviceName", StringValue (bs_tap.c_str ()));
+ tapBridge.Install (ghostNode, csmaDevices.Get (0));
+
+ //NOTE: required to overwrite the mac address of emulated device so that it is the same as that of tap device
+ setMac (csmaDevices.Get (0), bs_tap);
+
+ /////////////////////////////////
+ //
+ // Start of the simulation
+ //
+ ////////////////////////////////
+
+ if (isUeFixed)
+ {
+ Simulator::Stop ();
+ Simulator::Run ();
+ Simulator::Destroy ();
+ return 0;
+ }
+
+
+ ////////////////////////////////////
+ //
+ // lte mac and physical layer loggin
+ //
+ ////////////////////////////////////
+
+ if (isLogging)
+ {
+ lteHelper->NewEnableTxPhyTraces ();
+ }
+
+ auto handle = std::async (std::launch::async, [] ()
+ {
+ Simulator::Stop ();
+ Simulator::Run ();
+ Simulator::Destroy ();
+ });
+
+
+
+ //////////////////////////////////////////////////
+ //
+ // handle websocket control commands from outside
+ //
+ ///////////////////////////////////////////////////
+ ns3::emulator::LteEmulator emulator (map_name_ns3node, lteHelper);
+
+ /// Handler function for outcoming connections
+ CommunicationProtocol protocol;
+
+ HandlerFunction handler = [&emulator, &protocol] (Server *s, websocketpp::connection_hdl hdl, message_ptr msg, const uint8_t *data, std::size_t size)
+ {
+ std::string command ((char *) data, size);
+ boost::trim (command);
+
+ std::cout << command << std::endl;
+
+ Query query = Query::fromJsonString (command);
+ protocol.processQuery (s, hdl, msg, emulator, query);
+ };
+
+ ns3::emulator::ConnectionPool connPool (control_port, 9000);
+
+ std::cout << "Starting listeners" << std::endl;
+
+ connPool.startListeners (handler)
+ .processEvents ();
+
+ /// If we reach this point the control servers have stopped, that means we can also stop the simulation.
+
+ Simulator::Stop ();
+
+ return 0;
+}
+