From 05cc12b496d1bbc3cdedbe285cdd5838fdff232d Mon Sep 17 00:00:00 2001 From: Nicola Baldo Date: Fri, 21 Oct 2011 17:31:08 +0200 Subject: [PATCH] S1-U now working also in uplink --- src/lte/helper/epc-helper.cc | 25 +- src/lte/helper/epc-helper.h | 8 +- src/lte/model/epc-enb-application.cc | 13 +- src/lte/model/epc-enb-application.h | 5 + src/lte/model/epc-sgw-pgw-application.cc | 14 +- src/lte/model/epc-sgw-pgw-application.h | 13 +- src/lte/test/epc-test-s1u-downlink.cc | 95 ++--- src/lte/test/epc-test-s1u-uplink.cc | 498 +++++++++++++++++++++++ src/lte/wscript | 1 + 9 files changed, 601 insertions(+), 71 deletions(-) create mode 100644 src/lte/test/epc-test-s1u-uplink.cc diff --git a/src/lte/helper/epc-helper.cc b/src/lte/helper/epc-helper.cc index 01b2be978..3d6bdfca4 100644 --- a/src/lte/helper/epc-helper.cc +++ b/src/lte/helper/epc-helper.cc @@ -64,26 +64,26 @@ EpcHelper::EpcHelper () NS_ASSERT (retval == 0); // create TUN device implementing tunneling of user data over GTP-U/UDP/IP - Ptr giTunDevice = CreateObject (); + Ptr tunDevice = CreateObject (); // yes we need this - giTunDevice->SetAddress (Mac48Address::Allocate ()); + tunDevice->SetAddress (Mac48Address::Allocate ()); - m_sgwPgw->AddDevice (giTunDevice); - NetDeviceContainer giTunDeviceContainer; - giTunDeviceContainer.Add (giTunDevice); + m_sgwPgw->AddDevice (tunDevice); + NetDeviceContainer tunDeviceContainer; + tunDeviceContainer.Add (tunDevice); // the TUN device is on the same subnet as the UEs, so when a packet // addressed to an UE arrives at the intenet to the WAN interface of // the PGW it will be forwarded to the TUN device. - Ipv4InterfaceContainer giTunDeviceIpv4IfContainer = m_ueAddressHelper.Assign (giTunDeviceContainer); + Ipv4InterfaceContainer tunDeviceIpv4IfContainer = m_ueAddressHelper.Assign (tunDeviceContainer); // create EpcSgwPgwApplication - m_sgwPgwApp = CreateObject (giTunDevice, sgwPgwS1uSocket); + m_sgwPgwApp = CreateObject (tunDevice, sgwPgwS1uSocket); m_sgwPgw->AddApplication (m_sgwPgwApp); // connect SgwPgwApplication and virtual net device for tunneling - giTunDevice->SetSendCallback (MakeCallback (&EpcSgwPgwApplication::RecvFromGiTunDevice, m_sgwPgwApp)); + tunDevice->SetSendCallback (MakeCallback (&EpcSgwPgwApplication::RecvFromTunDevice, m_sgwPgwApp)); } @@ -164,6 +164,7 @@ EpcHelper::AddEnb (Ptr enb, Ptr lteEnbNetDevice) Ptr enbLteSocket = Socket::CreateSocket (enb, TypeId::LookupByName ("ns3::PacketSocketFactory")); PacketSocketAddress enbLteSocketBindAddress; enbLteSocketBindAddress.SetSingleDevice (lteEnbNetDevice->GetIfIndex ()); + enbLteSocketBindAddress.SetProtocol (Ipv4L3Protocol::PROT_NUMBER); retval = enbLteSocket->Bind (enbLteSocketBindAddress); NS_ASSERT (retval == 0); PacketSocketAddress enbLteSocketConnectAddress; @@ -241,4 +242,12 @@ EpcHelper::AssignUeIpv4Address (NetDeviceContainer ueDevices) +Ipv4Address +EpcHelper::GetUeDefaultGatewayAddress () +{ + // return the address of the tun device + return m_sgwPgw->GetObject ()->GetAddress (1, 0).GetLocal (); +} + + } // namespace ns3 diff --git a/src/lte/helper/epc-helper.h b/src/lte/helper/epc-helper.h index 62dcd1e52..7066add83 100644 --- a/src/lte/helper/epc-helper.h +++ b/src/lte/helper/epc-helper.h @@ -104,6 +104,13 @@ public: Ipv4InterfaceContainer AssignUeIpv4Address (NetDeviceContainer ueDevices); + /** + * + * \return the address of the Default Gateway to be used by UEs to reach the internet + */ + Ipv4Address GetUeDefaultGatewayAddress (); + + private: @@ -118,7 +125,6 @@ private: */ Ipv4AddressHelper m_ueAddressHelper; - Ptr m_sgwPgw; Ptr m_sgwPgwApp; diff --git a/src/lte/model/epc-enb-application.cc b/src/lte/model/epc-enb-application.cc index 8379d6f6b..906a311db 100644 --- a/src/lte/model/epc-enb-application.cc +++ b/src/lte/model/epc-enb-application.cc @@ -45,9 +45,10 @@ EpcEnbApplication::GetTypeId (void) EpcEnbApplication::EpcEnbApplication (Ptr lteSocket, Ptr s1uSocket, Ipv4Address sgwAddress) : m_lteSocket (lteSocket), m_s1uSocket (s1uSocket), - m_sgwAddress (sgwAddress) + m_sgwAddress (sgwAddress), + m_gtpuUdpPort (2152) // fixed by the standard { - NS_LOG_FUNCTION (this); + NS_LOG_FUNCTION (this << lteSocket << s1uSocket << sgwAddress); m_s1uSocket->SetRecvCallback (MakeCallback (&EpcEnbApplication::RecvFromS1uSocket, this)); m_lteSocket->SetRecvCallback (MakeCallback (&EpcEnbApplication::RecvFromLteSocket, this)); } @@ -74,12 +75,18 @@ EpcEnbApplication::RecvFromLteSocket (Ptr socket) NS_LOG_FUNCTION (this); NS_ASSERT (socket == m_lteSocket); Ptr packet = socket->Recv (); + + // workaround for bug 231 https://www.nsnam.org/bugzilla/show_bug.cgi?id=231 + SocketAddressTag satag; + packet->RemovePacketTag (satag); + LteMacTag tag; bool found = packet->RemovePacketTag (tag); NS_ASSERT (found); LteFlowId_t flowId; flowId.m_rnti = tag.GetRnti (); flowId.m_lcId = tag.GetLcid (); + NS_LOG_LOGIC ("received packet with RNTI=" << flowId.m_rnti << ", LCID=" << (uint16_t) flowId.m_lcId); std::map::iterator it = m_rbidTeidMap.find (flowId); NS_ASSERT (it != m_rbidTeidMap.end ()); uint32_t teid = it->second; @@ -127,7 +134,7 @@ EpcEnbApplication::SendToS1uSocket (Ptr packet, uint32_t teid) gtpu.SetLength (packet->GetSize () + gtpu.GetSerializedSize () - 8); packet->AddHeader (gtpu); uint32_t flags = 0; - m_s1uSocket->SendTo (packet, flags, m_sgwAddress); + m_s1uSocket->SendTo (packet, flags, InetSocketAddress(m_sgwAddress, m_gtpuUdpPort)); } diff --git a/src/lte/model/epc-enb-application.h b/src/lte/model/epc-enb-application.h index 52e1ae29e..b82586047 100644 --- a/src/lte/model/epc-enb-application.h +++ b/src/lte/model/epc-enb-application.h @@ -141,6 +141,11 @@ private: * */ std::map m_teidRbidMap; + + /** + * UDP port to be used for GTP + */ + uint16_t m_gtpuUdpPort; }; diff --git a/src/lte/model/epc-sgw-pgw-application.cc b/src/lte/model/epc-sgw-pgw-application.cc index ce021d7ef..bd1345786 100644 --- a/src/lte/model/epc-sgw-pgw-application.cc +++ b/src/lte/model/epc-sgw-pgw-application.cc @@ -76,12 +76,12 @@ EpcSgwPgwApplication::GetTypeId (void) -EpcSgwPgwApplication::EpcSgwPgwApplication (const Ptr giTunDevice, const Ptr s1uSocket) +EpcSgwPgwApplication::EpcSgwPgwApplication (const Ptr tunDevice, const Ptr s1uSocket) : m_s1uSocket (s1uSocket), - m_giTunDevice (giTunDevice), + m_tunDevice (tunDevice), m_gtpuUdpPort (2152) // fixed by the standard { - NS_LOG_FUNCTION (this << giTunDevice << s1uSocket); + NS_LOG_FUNCTION (this << tunDevice << s1uSocket); m_s1uSocket->SetRecvCallback (MakeCallback (&EpcSgwPgwApplication::RecvFromS1uSocket, this)); } @@ -105,7 +105,7 @@ EpcSgwPgwApplication::ActivateS1Bearer (Ipv4Address ueAddr, Ipv4Address enbAddr, } bool -EpcSgwPgwApplication::RecvFromGiTunDevice (Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber) +EpcSgwPgwApplication::RecvFromTunDevice (Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber) { NS_LOG_FUNCTION (this << source << dest << packet << packet->GetSize ()); @@ -158,14 +158,14 @@ EpcSgwPgwApplication::RecvFromS1uSocket (Ptr socket) SocketAddressTag tag; packet->RemovePacketTag (tag); - SendToGiTunDevice (packet, teid); + SendToTunDevice (packet, teid); } void -EpcSgwPgwApplication::SendToGiTunDevice (Ptr packet, uint32_t teid) +EpcSgwPgwApplication::SendToTunDevice (Ptr packet, uint32_t teid) { NS_LOG_FUNCTION (this << packet << teid); - m_giTunDevice->Receive (packet, 0x0800, m_giTunDevice->GetAddress (), m_giTunDevice->GetAddress (), NetDevice::PACKET_HOST); + m_tunDevice->Receive (packet, 0x0800, m_tunDevice->GetAddress (), m_tunDevice->GetAddress (), NetDevice::PACKET_HOST); } void diff --git a/src/lte/model/epc-sgw-pgw-application.h b/src/lte/model/epc-sgw-pgw-application.h index 5bfe8e395..af6860597 100644 --- a/src/lte/model/epc-sgw-pgw-application.h +++ b/src/lte/model/epc-sgw-pgw-application.h @@ -55,12 +55,12 @@ public: /** * Constructor that binds the tap device to the callback methods. * - * \param giTunDevice TUN VirtualNetDevice used to tunnel IP packets from + * \param tunDevice TUN VirtualNetDevice used to tunnel IP packets from * the Gi interface of the PGW/SGW over the * internet over GTP-U/UDP/IP on the S1-U interface * \param s1uSocket socket used to send GTP-U packets to the eNBs */ - EpcSgwPgwApplication (const Ptr giTunDevice, const Ptr s1uSocket); + EpcSgwPgwApplication (const Ptr tunDevice, const Ptr s1uSocket); /** * Destructor @@ -95,7 +95,7 @@ public: * \param protocolNumber * \return true always */ - bool RecvFromGiTunDevice (Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber); + bool RecvFromTunDevice (Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber); /** @@ -112,7 +112,7 @@ public: * * \param packet */ - void SendToGiTunDevice (Ptr packet, uint32_t teid); + void SendToTunDevice (Ptr packet, uint32_t teid); /** @@ -172,7 +172,7 @@ private: * TUN VirtualNetDevice used for tunneling/detunneling IP packets * from/to the internet over GTP-U/UDP/IP on the S1 interface */ - Ptr m_giTunDevice; + Ptr m_tunDevice; /** * Map telling for each UE address what is the corresponding eNB address @@ -185,6 +185,9 @@ private: */ std::map m_enbInfoMap; + /** + * UDP port to be used for GTP + */ uint16_t m_gtpuUdpPort; }; diff --git a/src/lte/test/epc-test-s1u-downlink.cc b/src/lte/test/epc-test-s1u-downlink.cc index e9a2fb325..6a94650fd 100644 --- a/src/lte/test/epc-test-s1u-downlink.cc +++ b/src/lte/test/epc-test-s1u-downlink.cc @@ -38,13 +38,17 @@ #include "ns3/uinteger.h" -using namespace ns3; + +namespace ns3 { + + +NS_LOG_COMPONENT_DEFINE ("EpcTestS1uDownlink"); -struct UeTestData +struct UeDlTestData { - UeTestData (uint32_t n, uint32_t s); + UeDlTestData (uint32_t n, uint32_t s); uint32_t numPkts; uint32_t pktSize; @@ -53,42 +57,42 @@ struct UeTestData Ptr clientApp; }; -UeTestData::UeTestData (uint32_t n, uint32_t s) +UeDlTestData::UeDlTestData (uint32_t n, uint32_t s) : numPkts (n), pktSize (s) { } -struct EnbTestData +struct EnbDlTestData { - std::vector ues; + std::vector ues; }; -class EpcS1uTestCase : public TestCase +class EpcS1uDlTestCase : public TestCase { public: - EpcS1uTestCase (std::string name, std::vector v); - virtual ~EpcS1uTestCase (); + EpcS1uDlTestCase (std::string name, std::vector v); + virtual ~EpcS1uDlTestCase (); private: virtual void DoRun (void); - std::vector m_enbTestData; + std::vector m_enbDlTestData; }; -EpcS1uTestCase::EpcS1uTestCase (std::string name, std::vector v) +EpcS1uDlTestCase::EpcS1uDlTestCase (std::string name, std::vector v) : TestCase (name), - m_enbTestData (v) + m_enbDlTestData (v) { } -EpcS1uTestCase::~EpcS1uTestCase () +EpcS1uDlTestCase::~EpcS1uDlTestCase () { } void -EpcS1uTestCase::DoRun () +EpcS1uDlTestCase::DoRun () { Ptr epcHelper = CreateObject (); Ptr pgw = epcHelper->GetPgwNode (); @@ -119,8 +123,8 @@ EpcS1uTestCase::DoRun () NodeContainer enbs; - for (std::vector::iterator enbit = m_enbTestData.begin (); - enbit < m_enbTestData.end (); + for (std::vector::iterator enbit = m_enbDlTestData.begin (); + enbit < m_enbDlTestData.end (); ++enbit) { Ptr enb = CreateObject (); @@ -190,11 +194,11 @@ EpcS1uTestCase::DoRun () Simulator::Run (); - for (std::vector::iterator enbit = m_enbTestData.begin (); - enbit < m_enbTestData.end (); + for (std::vector::iterator enbit = m_enbDlTestData.begin (); + enbit < m_enbDlTestData.end (); ++enbit) { - for (std::vector::iterator ueit = enbit->ues.begin (); + for (std::vector::iterator ueit = enbit->ues.begin (); ueit < enbit->ues.end (); ++ueit) { @@ -212,60 +216,57 @@ EpcS1uTestCase::DoRun () /** * Test that the S1-U interface implementation works correctly */ -class EpcS1uTestSuite : public TestSuite +class EpcS1uDlTestSuite : public TestSuite { public: - EpcS1uTestSuite (); + EpcS1uDlTestSuite (); -} g_epcS1uTestSuiteInstance; +} g_epcS1uDlTestSuiteInstance; -EpcS1uTestSuite::EpcS1uTestSuite () +EpcS1uDlTestSuite::EpcS1uDlTestSuite () : TestSuite ("epc-s1u-downlink", SYSTEM) { - std::vector v1; - EnbTestData e1; - UeTestData f1 (1, 100); + std::vector v1; + EnbDlTestData e1; + UeDlTestData f1 (1, 100); e1.ues.push_back (f1); v1.push_back (e1); - AddTestCase (new EpcS1uTestCase ("1 eNB, 1UE", v1)); + AddTestCase (new EpcS1uDlTestCase ("1 eNB, 1UE", v1)); - std::vector v2; - EnbTestData e2; - UeTestData f2_1 (1, 100); + std::vector v2; + EnbDlTestData e2; + UeDlTestData f2_1 (1, 100); e2.ues.push_back (f2_1); - UeTestData f2_2 (2, 200); + UeDlTestData f2_2 (2, 200); e2.ues.push_back (f2_2); v2.push_back (e2); - AddTestCase (new EpcS1uTestCase ("1 eNB, 2UEs", v2)); + AddTestCase (new EpcS1uDlTestCase ("1 eNB, 2UEs", v2)); - std::vector v3; + std::vector v3; v3.push_back (e1); v3.push_back (e2); - AddTestCase (new EpcS1uTestCase ("2 eNBs", v3)); + AddTestCase (new EpcS1uDlTestCase ("2 eNBs", v3)); - EnbTestData e3; - UeTestData f3_1 (3, 50); + EnbDlTestData e3; + UeDlTestData f3_1 (3, 50); e3.ues.push_back (f3_1); - UeTestData f3_2 (5, 1472); + UeDlTestData f3_2 (5, 1472); e3.ues.push_back (f3_2); - UeTestData f3_3 (1, 1); + UeDlTestData f3_3 (1, 1); e3.ues.push_back (f3_2); - std::vector v4; + std::vector v4; v4.push_back (e3); v4.push_back (e1); v4.push_back (e2); - AddTestCase (new EpcS1uTestCase ("3 eNBs", v4)); + AddTestCase (new EpcS1uDlTestCase ("3 eNBs", v4)); - - - - - - - } + + +} // namespace ns3 + diff --git a/src/lte/test/epc-test-s1u-uplink.cc b/src/lte/test/epc-test-s1u-uplink.cc new file mode 100644 index 000000000..8dee90747 --- /dev/null +++ b/src/lte/test/epc-test-s1u-uplink.cc @@ -0,0 +1,498 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007,2008,2009 INRIA, UDCAST + * 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 + * + * The original version of UdpClient is by Amine Ismail + * + * The rest of the code (including modifying UdpClient into + * LteMacTagUdpClient) is by Nicola Baldo + */ + + + +#include "ns3/simulator.h" +#include "ns3/log.h" +#include "ns3/test.h" +#include "ns3/epc-helper.h" +#include "ns3/packet-sink-helper.h" +#include "ns3/udp-client-server-helper.h" +#include "ns3/point-to-point-helper.h" +#include "ns3/csma-helper.h" +#include "ns3/internet-stack-helper.h" +#include "ns3/ipv4-address-helper.h" +#include "ns3/inet-socket-address.h" +#include "ns3/packet-sink.h" +#include +#include +#include +#include +#include "ns3/seq-ts-header.h" +#include "ns3/lte-mac-tag.h" +#include "ns3/arp-cache.h" +#include "ns3/boolean.h" +#include "ns3/uinteger.h" + + +namespace ns3 { + + + +NS_LOG_COMPONENT_DEFINE ("EpcTestS1uUplink"); + +/* + * A Udp client. Sends UDP packet carrying sequence number and time + * stamp but also including the LteMacTag. This tag is normally + * generated by the LteEnbNetDevice when forwarding packet in the + * uplink. But in this test we don't have the LteEnbNetDevice, because + * we test the S1-U interface with simpler devices to make sure it + * just works. + * + */ +class LteMacTagUdpClient : public Application +{ +public: + static TypeId + GetTypeId (void); + + LteMacTagUdpClient (); + LteMacTagUdpClient (uint16_t rnti, uint8_t lcid); + + virtual ~LteMacTagUdpClient (); + + /** + * \brief set the remote address and port + * \param ip remote IP address + * \param port remote port + */ + void SetRemote (Ipv4Address ip, uint16_t port); + +protected: + virtual void DoDispose (void); + +private: + + virtual void StartApplication (void); + virtual void StopApplication (void); + + void ScheduleTransmit (Time dt); + void Send (void); + + uint32_t m_count; + Time m_interval; + uint32_t m_size; + + uint32_t m_sent; + Ptr m_socket; + Ipv4Address m_peerAddress; + uint16_t m_peerPort; + EventId m_sendEvent; + + uint16_t m_rnti; + uint8_t m_lcid; + +}; + + + +TypeId +LteMacTagUdpClient::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::LteMacTagUdpClient") + .SetParent () + .AddConstructor () + .AddAttribute ("MaxPackets", + "The maximum number of packets the application will send", + UintegerValue (100), + MakeUintegerAccessor (&LteMacTagUdpClient::m_count), + MakeUintegerChecker ()) + .AddAttribute ("Interval", + "The time to wait between packets", TimeValue (Seconds (1.0)), + MakeTimeAccessor (&LteMacTagUdpClient::m_interval), + MakeTimeChecker ()) + .AddAttribute ( + "RemoteAddress", + "The destination Ipv4Address of the outbound packets", + Ipv4AddressValue (), + MakeIpv4AddressAccessor (&LteMacTagUdpClient::m_peerAddress), + MakeIpv4AddressChecker ()) + .AddAttribute ("RemotePort", "The destination port of the outbound packets", + UintegerValue (100), + MakeUintegerAccessor (&LteMacTagUdpClient::m_peerPort), + MakeUintegerChecker ()) + .AddAttribute ("PacketSize", + "Size of packets generated. The minimum packet size is 12 bytes which is the size of the header carrying the sequence number and the time stamp.", + UintegerValue (1024), + MakeUintegerAccessor (&LteMacTagUdpClient::m_size), + MakeUintegerChecker (12,1500)) + ; + return tid; +} + +LteMacTagUdpClient::LteMacTagUdpClient () + : m_rnti (0), + m_lcid (0) +{ + NS_LOG_FUNCTION_NOARGS (); + m_sent = 0; + m_socket = 0; + m_sendEvent = EventId (); +} + +LteMacTagUdpClient::LteMacTagUdpClient (uint16_t rnti, uint8_t lcid) + : m_rnti (rnti), + m_lcid (lcid) +{ + NS_LOG_FUNCTION_NOARGS (); + m_sent = 0; + m_socket = 0; + m_sendEvent = EventId (); +} + +LteMacTagUdpClient::~LteMacTagUdpClient () +{ + NS_LOG_FUNCTION_NOARGS (); +} + +void +LteMacTagUdpClient::SetRemote (Ipv4Address ip, uint16_t port) +{ + m_peerAddress = ip; + m_peerPort = port; +} + +void +LteMacTagUdpClient::DoDispose (void) +{ + NS_LOG_FUNCTION_NOARGS (); + Application::DoDispose (); +} + +void +LteMacTagUdpClient::StartApplication (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + if (m_socket == 0) + { + TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory"); + m_socket = Socket::CreateSocket (GetNode (), tid); + m_socket->Bind (); + m_socket->Connect (InetSocketAddress (m_peerAddress, m_peerPort)); + } + + m_socket->SetRecvCallback (MakeNullCallback > ()); + m_sendEvent = Simulator::Schedule (Seconds (0.0), &LteMacTagUdpClient::Send, this); +} + +void +LteMacTagUdpClient::StopApplication () +{ + NS_LOG_FUNCTION_NOARGS (); + Simulator::Cancel (m_sendEvent); +} + +void +LteMacTagUdpClient::Send (void) +{ + NS_LOG_FUNCTION_NOARGS (); + NS_ASSERT (m_sendEvent.IsExpired ()); + SeqTsHeader seqTs; + seqTs.SetSeq (m_sent); + Ptr p = Create (m_size-(8+4)); // 8+4 : the size of the seqTs header + p->AddHeader (seqTs); + + LteMacTag tag (m_rnti, m_lcid); + p->AddPacketTag (tag); + + if ((m_socket->Send (p)) >= 0) + { + ++m_sent; + NS_LOG_INFO ("TraceDelay TX " << m_size << " bytes to " + << m_peerAddress << " Uid: " << p->GetUid () + << " Time: " << (Simulator::Now ()).GetSeconds ()); + + } + else + { + NS_LOG_INFO ("Error while sending " << m_size << " bytes to " + << m_peerAddress); + } + + if (m_sent < m_count) + { + m_sendEvent = Simulator::Schedule (m_interval, &LteMacTagUdpClient::Send, this); + } +} + + + +struct UeUlTestData +{ + UeUlTestData (uint32_t n, uint32_t s, uint16_t r, uint8_t l); + + uint32_t numPkts; + uint32_t pktSize; + uint16_t rnti; + uint8_t lcid; + + Ptr serverApp; + Ptr clientApp; +}; + + UeUlTestData::UeUlTestData (uint32_t n, uint32_t s, uint16_t r, uint8_t l) + : numPkts (n), + pktSize (s), + rnti (r), + lcid (l) +{ +} + +struct EnbUlTestData +{ + std::vector ues; +}; + + +class EpcS1uUlTestCase : public TestCase +{ +public: + EpcS1uUlTestCase (std::string name, std::vector v); + virtual ~EpcS1uUlTestCase (); + +private: + virtual void DoRun (void); + std::vector m_enbUlTestData; +}; + + +EpcS1uUlTestCase::EpcS1uUlTestCase (std::string name, std::vector v) + : TestCase (name), + m_enbUlTestData (v) +{ +} + +EpcS1uUlTestCase::~EpcS1uUlTestCase () +{ +} + +void +EpcS1uUlTestCase::DoRun () +{ + Ptr epcHelper = CreateObject (); + Ptr pgw = epcHelper->GetPgwNode (); + + // Create a single RemoteHost + NodeContainer remoteHostContainer; + remoteHostContainer.Create (1); + Ptr remoteHost = remoteHostContainer.Get (0); + InternetStackHelper internet; + internet.Install (remoteHostContainer); + + // Create the internet + PointToPointHelper p2ph; + NetDeviceContainer internetDevices = p2ph.Install (pgw, remoteHost); + Ipv4AddressHelper ipv4h; + ipv4h.SetBase ("1.0.0.0", "255.0.0.0"); + Ipv4InterfaceContainer internetNodesIpIfaceContainer = ipv4h.Assign (internetDevices); + + // setup default gateway for the remote hosts + Ipv4StaticRoutingHelper ipv4RoutingHelper; + Ptr remoteHostStaticRouting = ipv4RoutingHelper.GetStaticRouting (remoteHost->GetObject ()); + + // hardcoded UE addresses for now + remoteHostStaticRouting->AddNetworkRouteTo (Ipv4Address ("7.0.0.0"), Ipv4Mask ("255.255.255.0"), 1); + + + + uint16_t udpSinkPort = 1234; + + NodeContainer enbs; + + for (std::vector::iterator enbit = m_enbUlTestData.begin (); + enbit < m_enbUlTestData.end (); + ++enbit) + { + Ptr enb = CreateObject (); + enbs.Add (enb); + + // we test EPC without LTE, hence we use: + // 1) a CSMA network to simulate the cell + // 2) a raw socket opened on the CSMA device to simulate the LTE socket + + NodeContainer ues; + ues.Create (enbit->ues.size ()); + + NodeContainer cell; + cell.Add (ues); + cell.Add (enb); + + CsmaHelper csmaCell; + NetDeviceContainer cellDevices = csmaCell.Install (cell); + + // the eNB's CSMA NetDevice acting as an LTE NetDevice. + Ptr lteEnbNetDevice = cellDevices.Get (cellDevices.GetN () - 1); + + // Note that the EpcEnbApplication won't care of the actual NetDevice type + epcHelper->AddEnb (enb, lteEnbNetDevice); + + // we install the IP stack on UEs only + InternetStackHelper internet; + internet.Install (ues); + + // assign IP address to UEs, and install applications + for (uint32_t u = 0; u < ues.GetN (); ++u) + { + Ptr ueLteDevice = cellDevices.Get (u); + Ipv4InterfaceContainer ueIpIface = epcHelper->AssignUeIpv4Address (NetDeviceContainer (ueLteDevice)); + + Ptr ue = ues.Get (u); + + // disable IP Forwarding on the UE. This is because we use + // CSMA broadcast MAC addresses for this test. The problem + // won't happen with a LteUeNetDevice. + Ptr ueIpv4 = ue->GetObject (); + ueIpv4->SetAttribute ("IpForward", BooleanValue (false)); + + // tell the UE to route all packets to the GW + Ptr ueStaticRouting = ipv4RoutingHelper.GetStaticRouting (ueIpv4); + Ipv4Address gwAddr = epcHelper->GetUeDefaultGatewayAddress (); + NS_LOG_INFO ("GW address: " << gwAddr); + ueStaticRouting->SetDefaultRoute (gwAddr, 1); + + // since the UEs in this test use CSMA with IP enabled, and + // the eNB uses CSMA but without IP, we fool the UE's ARP + // cache into thinking that the IP address of the GW can be + // reached by sending a CSMA packet to the broadcast + // address, so the eNB will get it. + int32_t ueLteIpv4IfIndex = ueIpv4->GetInterfaceForDevice (ueLteDevice); + Ptr ueIpv4L3Protocol = ue->GetObject (); + Ptr ueLteIpv4Iface = ueIpv4L3Protocol->GetInterface (ueLteIpv4IfIndex); + Ptr ueArpCache = ueLteIpv4Iface->GetArpCache (); + ueArpCache->SetAliveTimeout (Seconds (1000)); + ArpCache::Entry* arpCacheEntry = ueArpCache->Add (gwAddr); + arpCacheEntry->MarkWaitReply(0); + arpCacheEntry->MarkAlive (Mac48Address::GetBroadcast ()); + + + PacketSinkHelper packetSinkHelper ("ns3::UdpSocketFactory", + InetSocketAddress (Ipv4Address::GetAny (), udpSinkPort)); + ApplicationContainer sinkApp = packetSinkHelper.Install (remoteHost); + sinkApp.Start (Seconds (1.0)); + sinkApp.Stop (Seconds (10.0)); + enbit->ues[u].serverApp = sinkApp.Get (0)->GetObject (); + + Time interPacketInterval = Seconds (0.01); + Ptr client = CreateObject (enbit->ues[u].rnti, enbit->ues[u].lcid); + client->SetAttribute ("RemoteAddress", Ipv4AddressValue (internetNodesIpIfaceContainer.GetAddress (1))); + client->SetAttribute ("RemotePort", UintegerValue (udpSinkPort)); + client->SetAttribute ("MaxPackets", UintegerValue (enbit->ues[u].numPkts)); + client->SetAttribute ("Interval", TimeValue (interPacketInterval)); + client->SetAttribute ("PacketSize", UintegerValue (enbit->ues[u].pktSize)); + ue->AddApplication (client); + ApplicationContainer clientApp; + clientApp.Add (client); + clientApp.Start (Seconds (2.0)); + clientApp.Stop (Seconds (10.0)); + enbit->ues[u].clientApp = client; + + uint16_t rnti = u+1; + uint16_t lcid = 1; + epcHelper->ActivateEpsBearer (ueLteDevice, lteEnbNetDevice, LteTft::Default (), rnti, lcid); + + // need this since all sinks are installed in the same node + ++udpSinkPort; + } + + } + + Simulator::Run (); + + for (std::vector::iterator enbit = m_enbUlTestData.begin (); + enbit < m_enbUlTestData.end (); + ++enbit) + { + for (std::vector::iterator ueit = enbit->ues.begin (); + ueit < enbit->ues.end (); + ++ueit) + { + NS_TEST_ASSERT_MSG_EQ (ueit->serverApp->GetTotalRx (), (ueit->numPkts) * (ueit->pktSize), "wrong total received bytes"); + } + } + + Simulator::Destroy (); +} + + + + + +/** + * Test that the S1-U interface implementation works correctly + */ +class EpcS1uUlTestSuite : public TestSuite +{ +public: + EpcS1uUlTestSuite (); + +} g_epcS1uUlTestSuiteInstance; + +EpcS1uUlTestSuite::EpcS1uUlTestSuite () + : TestSuite ("epc-s1u-uplink", SYSTEM) +{ + std::vector v1; + EnbUlTestData e1; + UeUlTestData f1 (1, 100, 1, 1); + e1.ues.push_back (f1); + v1.push_back (e1); + AddTestCase (new EpcS1uUlTestCase ("1 eNB, 1UE", v1)); + + + std::vector v2; + EnbUlTestData e2; + UeUlTestData f2_1 (1, 100, 1, 1); + e2.ues.push_back (f2_1); + UeUlTestData f2_2 (2, 200, 2, 1); + e2.ues.push_back (f2_2); + v2.push_back (e2); + AddTestCase (new EpcS1uUlTestCase ("1 eNB, 2UEs", v2)); + + + std::vector v3; + v3.push_back (e1); + v3.push_back (e2); + AddTestCase (new EpcS1uUlTestCase ("2 eNBs", v3)); + + + EnbUlTestData e3; + UeUlTestData f3_1 (3, 50, 1, 1); + e3.ues.push_back (f3_1); + UeUlTestData f3_2 (5, 1472, 2, 1); + e3.ues.push_back (f3_2); + UeUlTestData f3_3 (1, 1, 3, 1); + e3.ues.push_back (f3_2); + std::vector v4; + v4.push_back (e3); + v4.push_back (e1); + v4.push_back (e2); + AddTestCase (new EpcS1uUlTestCase ("3 eNBs", v4)); + +} + + + +} // namespace ns3 + diff --git a/src/lte/wscript b/src/lte/wscript index 2e9826761..650e1a052 100644 --- a/src/lte/wscript +++ b/src/lte/wscript @@ -81,6 +81,7 @@ def build(bld): 'test/epc-test-gtpu.cc', 'test/test-eps-tft-classifier.cc', 'test/epc-test-s1u-downlink.cc', + 'test/epc-test-s1u-uplink.cc', ] headers = bld.new_task_gen('ns3header')