Low Throughput Observed Simulating TCP traffic over LTE

219 views
Skip to first unread message

Abhinaba Rakshit

unread,
Sep 13, 2023, 4:09:38 PM9/13/23
to ns-3-users
Hello,

I am trying to simulate TCP traffic over a simple LTE network with EPC and one remote host. I have referred the lena-simple-epc.cc example from lte module, to setup a simplest LTE network, with single UE, single eNB, EPC and one remote Host.

UE ))))) eNB --------- EPC --------remoteHost

The aim of this setup is to run TCP application over the network and observe the maximum datarate that can be obtained (Which should ideally be <= Bottleneck Bandwidth of the Network).

I have configured the eNB DL and UL bandwidth both to be 100 as shown below.
lteHelper -> SetEnbDeviceAttribute("DlBandwidth", UintegerValue(100));
lteHelper -> SetEnbDeviceAttribute("UlBandwidth", UintegerValue(100));

When I run a TCP application with PacketSinkHelper(TcpSocket) and BulkSendHelper(TcpSocket), we observe the throughput for both DL and UL to 4.3 Mbps and 4.2 Mbps respectively.However, when I use a UdpClientHelper and set the data rate to 120 Mbps , I observe the Throughput to be around 72 to 73 Mbps for both DL and UL. 

Well, my query to the community is why we observe TCP traffic to get clamped at 4-5 Mbps, when we have much more bandwidth available (verified by UDP traffic achieving 72 Mbps), should not it consume the entire bandwidth? Is any configuration missing on the EPC or LTE stack which can clamp TCP traffic to 5 Mbps?  Any help in this regard will be highly appreciated. 

Thank You

I am attaching the script used to simulate the scenario -
#include "ns3/applications-module.h"
#include "ns3/config-store-module.h"
#include "ns3/core-module.h"
#include "ns3/internet-module.h"
#include "ns3/lte-module.h"
#include "ns3/mobility-module.h"
#include "ns3/point-to-point-module.h"

using namespace ns3;

/**
* Sample simulation script for LTE+EPC. It instantiates several eNodeBs,
* attaches one UE per eNodeB starts a flow for each UE to and from a remote host.
* It also starts another flow between each UE pair.
*/

NS_LOG_COMPONENT_DEFINE("LenaSimpleEpc");

Ptr<PacketSink> sinkDL;
Ptr<PacketSink> sinkUL;
double last_rx_bytes_dl = 0;
double last_rx_bytes_ul = 0;

void
GetThroughput() {
Time now = Simulator::Now ();
double cur = (sinkDL->GetTotalRx() - last_rx_bytes_dl) * (double) 8 / 1e6;
std::cout << now.GetSeconds() << "s: Throughput DL : " << cur << "Mbits/s" << std::endl;
last_rx_bytes_dl = sinkDL->GetTotalRx ();

cur = (sinkUL->GetTotalRx() - last_rx_bytes_ul) * (double) 8 / 1e6;
std::cout << now.GetSeconds() << "s: Throughput UL : " << cur << "Mbits/s" << std::endl;
last_rx_bytes_ul = sinkUL->GetTotalRx ();

Simulator::Schedule(Seconds(1), &GetThroughput);
}

int
main(int argc, char* argv[])
{
uint16_t numEnb = 1;
uint16_t numUe = 1;
Time simTime = Seconds(60);
Time interPacketInterval = MicroSeconds(100);
bool disableDl = false;
bool disableUl = false;
bool disableTcp = false;

// Command line arguments
CommandLine cmd;
cmd.AddValue("numNEnb", "Number of eNodeBs", numEnb);
cmd.AddValue("numUe", "Number of UEs", numUe);
cmd.AddValue("simTime", "Total duration of the simulation", simTime);
cmd.AddValue("interPacketInterval", "Inter packet interval", interPacketInterval);
cmd.AddValue("disableDl", "Disable downlink data flows", disableDl);
cmd.AddValue("disableUl", "Disable uplink data flows", disableUl);
cmd.Parse(argc, argv);

Ptr<LteHelper> lteHelper = CreateObject<LteHelper>();
Ptr<PointToPointEpcHelper> epcHelper = CreateObject<PointToPointEpcHelper>();
lteHelper->SetEpcHelper(epcHelper);
lteHelper->SetEnbDeviceAttribute("DlBandwidth", UintegerValue(100));
lteHelper->SetEnbDeviceAttribute("UlBandwidth", UintegerValue(100));

Ptr<Node> pgw = epcHelper->GetPgwNode();

// Create a single RemoteHost
NodeContainer remoteHostContainer;
remoteHostContainer.Create(1);
Ptr<Node> remoteHost = remoteHostContainer.Get(0);
InternetStackHelper internet;
internet.Install(remoteHostContainer);

// Create the Internet
PointToPointHelper p2ph;
p2ph.SetDeviceAttribute("DataRate", DataRateValue(DataRate("100Gb/s")));
p2ph.SetDeviceAttribute("Mtu", UintegerValue(1500));
p2ph.SetChannelAttribute("Delay", TimeValue(MicroSeconds(10)));
NetDeviceContainer internetDevices = p2ph.Install(pgw, remoteHost);
Ipv4AddressHelper ipv4h;
ipv4h.SetBase("1.0.0.0", "255.0.0.0");
Ipv4InterfaceContainer internetIpIfaces = ipv4h.Assign(internetDevices);
// interface 0 is localhost, 1 is the p2p device
Ipv4Address remoteHostAddr = internetIpIfaces.GetAddress(1);

Ipv4StaticRoutingHelper ipv4RoutingHelper;
Ptr<Ipv4StaticRouting> remoteHostStaticRouting =
ipv4RoutingHelper.GetStaticRouting(remoteHost->GetObject<Ipv4>());
remoteHostStaticRouting->AddNetworkRouteTo(Ipv4Address("7.0.0.0"), Ipv4Mask("255.0.0.0"), 1);

NodeContainer ueNodes;
NodeContainer enbNodes;
enbNodes.Create(numEnb);
ueNodes.Create(numUe);

// Install Mobility Model
MobilityHelper mobility;
mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
Ptr<ListPositionAllocator> positionAllocEnb = CreateObject<ListPositionAllocator>();
for (uint16_t i = 0; i < numEnb; i++)
{
positionAllocEnb->Add(Vector(0, 0, 0));
}
mobility.SetPositionAllocator(positionAllocEnb);
mobility.Install(enbNodes);
Ptr<ListPositionAllocator> positionAllocUe = CreateObject<ListPositionAllocator>();
for (uint16_t i = 0; i < numUe; i++)
{
positionAllocUe->Add(Vector(0, 0, 0));
}
mobility.SetPositionAllocator(positionAllocUe);
mobility.Install(ueNodes);

// Install LTE Devices to the nodes
NetDeviceContainer enbLteDevs = lteHelper->InstallEnbDevice(enbNodes);
NetDeviceContainer ueLteDevs = lteHelper->InstallUeDevice(ueNodes);

// Install the IP stack on the UEs
internet.Install(ueNodes);
Ipv4InterfaceContainer ueIpIface;
ueIpIface = epcHelper->AssignUeIpv4Address(NetDeviceContainer(ueLteDevs));
// Assign IP address to UEs, and install applications
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);
}

// Attach one UE per eNodeB
for (uint16_t i = 0; i < numUe; i++)
{
uint16_t enbIndex = (i < enbNodes.GetN()) ? i : 0;
lteHelper->Attach(ueLteDevs.Get(i), enbLteDevs.Get(enbIndex));
// side effect: the default EPS bearer will be activated
}

// Install and start applications on UEs and remote host
uint16_t dlPort = 1100;
uint16_t ulPort = 2000;
ApplicationContainer clientApps;
ApplicationContainer serverApps;
for (uint32_t u = 0; u < ueNodes.GetN(); ++u)
{
if (!disableDl)
{
if(!disableTcp)
{
std::cout<<"Setting TCP Traffic"<<std::endl;
PacketSinkHelper dlPacketSinkHelper("ns3::TcpSocketFactory", InetSocketAddress(Ipv4Address::GetAny(), dlPort));
serverApps.Add(dlPacketSinkHelper.Install(ueNodes.Get(u)));

BulkSendHelper dlClient("ns3::TcpSocketFactory", InetSocketAddress(ueIpIface.GetAddress(u), dlPort));
clientApps.Add(dlClient.Install(remoteHost));

sinkDL = StaticCast<PacketSink> (serverApps.Get (0));
}
else
{
std::cout<<"Setting UDP Traffic"<<std::endl;
PacketSinkHelper dlPacketSinkHelper("ns3::UdpSocketFactory", InetSocketAddress(Ipv4Address::GetAny(), dlPort));
serverApps.Add(dlPacketSinkHelper.Install(ueNodes.Get(u)));

UdpClientHelper dlClient(ueIpIface.GetAddress(u), dlPort);
dlClient.SetAttribute("Interval", TimeValue(interPacketInterval));
dlClient.SetAttribute("MaxPackets", UintegerValue(1000000));
clientApps.Add(dlClient.Install(remoteHost));

sinkDL = StaticCast<PacketSink> (serverApps.Get (0));
}
dlPort++;
}

if (!disableUl)
{
if(!disableTcp)
{
std::cout<<"Setting TCP Traffic"<<std::endl;
PacketSinkHelper ulPacketSinkHelper("ns3::TcpSocketFactory", InetSocketAddress(Ipv4Address::GetAny(), ulPort));
serverApps.Add(ulPacketSinkHelper.Install(remoteHost));

BulkSendHelper ulClient("ns3::TcpSocketFactory", InetSocketAddress(remoteHostAddr, ulPort));
clientApps.Add(ulClient.Install(ueNodes.Get(u)));

sinkUL = StaticCast<PacketSink> (serverApps.Get (1));
}
else
{
std::cout<<"Setting UDP Traffic"<<std::endl;
PacketSinkHelper ulPacketSinkHelper("ns3::UdpSocketFactory", InetSocketAddress(Ipv4Address::GetAny(), ulPort));
serverApps.Add(ulPacketSinkHelper.Install(remoteHost));

UdpClientHelper ulClient(remoteHostAddr, ulPort);
ulClient.SetAttribute("Interval", TimeValue(interPacketInterval));
ulClient.SetAttribute("MaxPackets", UintegerValue(1000000));
clientApps.Add(ulClient.Install(ueNodes.Get(u)));

sinkUL = StaticCast<PacketSink> (serverApps.Get (1));
}
ulPort++;
}

}

serverApps.Start(Seconds(1));
clientApps.Start(Seconds(2));
serverApps.Stop(simTime);
clientApps.Stop(simTime);
// lteHelper->EnableTraces();
// Uncomment to enable PCAP tracing
// p2ph.EnablePcapAll("lena-simple-epc");
Simulator::Schedule(Seconds(1), &GetThroughput);
Simulator::Stop(simTime);
Simulator::Run();

/*GtkConfigStore config;
config.ConfigureAttributes();*/

Simulator::Destroy();
return 0;
}

Tommaso Pecorella

unread,
Sep 13, 2023, 5:47:00 PM9/13/23
to ns-3-users
That's the result of a known issue: https://gitlab.com/nsnam/ns-3-dev/-/issues/946

You have to increase the MSS, and possibly also the Rx and Tx window size (I don't remember if they're negotiated).

Abhinaba Rakshit

unread,
Sep 14, 2023, 5:57:52 AM9/14/23
to ns-3-users
Thanks for the quick reply,

I tried increasing the MSS and also the TxBuffer and RxBuffer. It did not help to increase the Throughput.
However, when I do a same TCP simulation with simple 2 point to point connection, Our BulkSendApplication fills up the entire pipe (i.e with 100Mbps Bandwidth I obtained around 90Mbps throughput).

I m wondering if it a known issue with LTE, or does LTE stack needs any other configuration change?

Thank You.

Tommaso Pecorella

unread,
Sep 14, 2023, 2:23:05 PM9/14/23
to ns-3-users
As far as I know, LTE shouldn't require any tweaks. If UDP is able to use 72 Mbps, TCP should have similar values, provided that the BW /delay product is not very strange. You can check the theoretical limits here: https://www.switch.ch/network/tools/tcp_throughput/

What can hinder the TCP throughput is the delay, loss rate, TX/RX windows (they do set a limit to the CWnd), and MSS. Other than that... it should go as fast as it can. My suggestion is to (also) check with Wireshark on the P2P link between the PGW and the remote host, perhaps you'll understand why it's slow. Look especially for a high number of retransmissions, low Cwnd, and "wrong" MSS.
Reply all
Reply to author
Forward
0 new messages