diff --git a/src/lte/examples/inter-cell-interference.cc b/src/lte/examples/inter-cell-interference.cc index 954fba072..467722ef8 100644 --- a/src/lte/examples/inter-cell-interference.cc +++ b/src/lte/examples/inter-cell-interference.cc @@ -116,8 +116,8 @@ int main (int argc, char *argv[]) // Activate an EPS bearer on all UEs enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE; EpsBearer bearer (q); - lena->ActivateEpsBearer (ueDevs1, bearer); - lena->ActivateEpsBearer (ueDevs2, bearer); + lena->ActivateEpsBearer (ueDevs1, bearer, LteTft::Default ()); + lena->ActivateEpsBearer (ueDevs2, bearer, LteTft::Default ()); Simulator::Stop (Seconds (10)); diff --git a/src/lte/examples/lena-first-sim.cc b/src/lte/examples/lena-first-sim.cc index cebaac34d..23640fd29 100644 --- a/src/lte/examples/lena-first-sim.cc +++ b/src/lte/examples/lena-first-sim.cc @@ -80,7 +80,7 @@ int main (int argc, char *argv[]) // Activate an EPS bearer enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE; EpsBearer bearer (q); - lena->ActivateEpsBearer (ueDevs, bearer); + lena->ActivateEpsBearer (ueDevs, bearer, LteTft::Default ()); Simulator::Stop (Seconds (0.010)); diff --git a/src/lte/examples/lena-rlc-calculator.cc b/src/lte/examples/lena-rlc-calculator.cc index 48bbe5fca..87f9befdd 100644 --- a/src/lte/examples/lena-rlc-calculator.cc +++ b/src/lte/examples/lena-rlc-calculator.cc @@ -71,7 +71,7 @@ int main (int argc, char *argv[]) // Activate an EPS bearer enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE; EpsBearer bearer (q); - lena->ActivateEpsBearer (ueDevs, bearer); + lena->ActivateEpsBearer (ueDevs, bearer, LteTft::Default ()); Simulator::Stop (Seconds (5)); diff --git a/src/lte/examples/profiling-reference.cc b/src/lte/examples/profiling-reference.cc index 5819eae33..f6fad1def 100644 --- a/src/lte/examples/profiling-reference.cc +++ b/src/lte/examples/profiling-reference.cc @@ -117,7 +117,7 @@ int main (int argc, char *argv[]) lena->Attach (ueDev, enbDevs.Get (i)); enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE; EpsBearer bearer (q); - lena->ActivateEpsBearer (ueDev, bearer); + lena->ActivateEpsBearer (ueDev, bearer, LteTft::Default ()); } diff --git a/src/lte/helper/epc-helper.cc b/src/lte/helper/epc-helper.cc index 45aa9828b..074876965 100644 --- a/src/lte/helper/epc-helper.cc +++ b/src/lte/helper/epc-helper.cc @@ -21,9 +21,17 @@ #include #include -#include "ns3/inet-socket-address.h" -#include "ns3/mac48-address.h" -#include "ns3/epc-gtpu-tunnel-endpoint.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ns3 { @@ -33,30 +41,49 @@ NS_LOG_COMPONENT_DEFINE ("EpcHelper"); NS_OBJECT_ENSURE_REGISTERED (EpcHelper); EpcHelper::EpcHelper () + : m_gtpuUdpPort (2152) // fixed by the standard { NS_LOG_FUNCTION (this); // since we use point-to-point links for all S1-U links, // we use a /30 subnet which can hold exactly two addresses // (remember that net broadcast and null address are not valid) - m_s1uIpv4AddressHelper.SetBase ("10.7.0.0", "255.255.255.252"); + m_s1uIpv4AddressHelper.SetBase ("10.0.0.0", "255.255.255.252"); + + // we use a /8 net for all UEs + m_ueAddressHelper.SetBase ("7.0.0.0", "255.0.0.0"); // create SgwPgwNode m_sgwPgw = CreateObject (); + InternetStackHelper internet; + internet.Install (m_sgwPgw); + // create S1-U socket Ptr sgwPgwS1uSocket = Socket::CreateSocket (m_sgwPgw, TypeId::LookupByName ("ns3::UdpSocketFactory")); - sgwPgwS1uSocket->Bind (InetSocketAddress (Ipv4Address::GetAny (), m_gtpuUdpPort)); + int retval = sgwPgwS1uSocket->Bind (InetSocketAddress (Ipv4Address::GetAny (), m_gtpuUdpPort)); + NS_ASSERT (retval == 0); - // create SgwPgwApplication + // create TUN device implementing tunneling of user data over GTP-U/UDP/IP + Ptr giTunDevice = CreateObject (); - // create WAN NetDevice? + // yes we need this + giTunDevice->SetAddress (Mac48Address::Allocate ()); - // create virtual net device + m_sgwPgw->AddDevice (giTunDevice); + NetDeviceContainer giTunDeviceContainer; + giTunDeviceContainer.Add (giTunDevice); - // interface SgwPgwApplication and virtual net device for tunneling + // 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); - // set up static routes appropriately + // create EpcSgwPgwApplication + m_sgwPgwApp = CreateObject (giTunDevice, sgwPgwS1uSocket); + m_sgwPgw->AddApplication (m_sgwPgwApp); + // connect SgwPgwApplication and virtual net device for tunneling + giTunDevice->SetSendCallback (MakeCallback (&EpcSgwPgwApplication::RecvFromGiTunDevice, m_sgwPgwApp)); } @@ -71,10 +98,6 @@ EpcHelper::GetTypeId (void) static TypeId tid = TypeId ("ns3::EpcHelper") .SetParent () .AddConstructor () - .AddAttribute ("", "The IP address to assign to the tap device, when in ConfigureLocal mode. " - Ipv4AddressValue ("255.255.255.255"), - MakeIpv4AddressAccessor (&TapBridge::m_tapIp), - MakeIpv4AddressChecker ()) .AddAttribute ("S1uLinkDataRate", "The data rate to be used for the next S1-U link to be created", DataRateValue (DataRate ("10Gb/s")), @@ -83,31 +106,24 @@ EpcHelper::GetTypeId (void) .AddAttribute ("S1uLinkDelay", "The delay to be used for the next S1-U link to be created", TimeValue (Seconds (0)), - MakeTimeAccessor (&EpcHelper::m_m_s1uLinkDelay), + MakeTimeAccessor (&EpcHelper::m_s1uLinkDelay), MakeTimeChecker ()) - .AddAttribute("GtpuPort", - "UDP Port to be used for GTP-U", - UintegerValue (2152), - MakeUintegerAccessor (&EpcHelper::m_gtpuUdpPort), - MakeUintegerChecker ()) ; return tid; } -void -EpcHelper::CreateSgwPgw () -{ - -} - void EpcHelper::AddEnb (Ptr enb, Ptr lteEnbNetDevice) { + NS_LOG_FUNCTION (this << enb << lteEnbNetDevice); + + NS_ASSERT (enb == lteEnbNetDevice->GetNode ()); // add an IPv4 stack to the previously created eNB InternetStackHelper internet; internet.Install (enb); + NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB after node creation: " << enb->GetObject ()->GetNInterfaces ()); // create a point to point link between the new eNB and the SGW with // the corresponding new NetDevices on each side @@ -118,82 +134,104 @@ EpcHelper::AddEnb (Ptr enb, Ptr lteEnbNetDevice) p2ph.SetDeviceAttribute ("DataRate", DataRateValue (m_s1uLinkDataRate)); p2ph.SetChannelAttribute ("Delay", TimeValue (m_s1uLinkDelay)); NetDeviceContainer enbSgwDevices = p2ph.Install (enb, m_sgwPgw); + NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB after installing p2p dev: " << enb->GetObject ()->GetNInterfaces ()); Ptr enbDev = enbSgwDevices.Get (0); Ptr sgwDev = enbSgwDevices.Get (1); m_s1uIpv4AddressHelper.NewNetwork (); - Ipv4InterfaceContainer enbSgwIpIfaces m_s1uIpv4AddressHelper.Assign (enbSgwDevices); + Ipv4InterfaceContainer enbSgwIpIfaces = m_s1uIpv4AddressHelper.Assign (enbSgwDevices); + NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB after assigning Ipv4 addr to S1 dev: " << enb->GetObject ()->GetNInterfaces ()); + Ipv4Address enbAddress = enbSgwIpIfaces.GetAddress (0); Ipv4Address sgwAddress = enbSgwIpIfaces.GetAddress (1); // create S1-U socket for the ENB Ptr enbS1uSocket = Socket::CreateSocket (enb, TypeId::LookupByName ("ns3::UdpSocketFactory")); - enbS1uSocket->Bind (InetSocketAddress (enbAddress, m_gtpuUdpPort)); + int retval = enbS1uSocket->Bind (InetSocketAddress (enbAddress, m_gtpuUdpPort)); + NS_ASSERT (retval == 0); + + // give PacketSocket powers to the eNB + //PacketSocketHelper packetSocket; + //packetSocket.Install (enb); + // create LTE socket for the ENB - PacketSocketAddress enbLteSocketAddr; - enbLteSocketAddr.SetSingleDevice (lteEnbNetDevice->GetIfIndex ()); - // do we need the following? - //enbLteSocketAddr.SetPhysicalAddress (devices.Get (1)->GetAddress ()); - //enbLteSocketAddr.SetProtocol (1); - Ptr enbLteSocket = Socket::CreateSocket (enb, TypeId::LookupByName ("ns3::PacketSocketFactory")); - enbLteSocket->Bind (enbLteSocketAddr); - - // create EpcEnbApplication - Ptr = CreateObject (enbLteSocket, enbS1uSocket, sgwAddress); + PacketSocketAddress enbLteSocketBindAddress; + enbLteSocketBindAddress.SetSingleDevice (lteEnbNetDevice->GetIfIndex ()); + retval = enbLteSocket->Bind (enbLteSocketBindAddress); + NS_ASSERT (retval == 0); + PacketSocketAddress enbLteSocketConnectAddress; + enbLteSocketConnectAddress.SetPhysicalAddress (Mac48Address::GetBroadcast ()); + enbLteSocketConnectAddress.SetProtocol (Ipv4L3Protocol::PROT_NUMBER); + retval = enbLteSocket->Connect (enbLteSocketConnectAddress); + NS_ASSERT (retval == 0); + + NS_LOG_INFO ("create EpcEnbApplication"); + Ptr enbApp = CreateObject (enbLteSocket, enbS1uSocket, sgwAddress); + enb->AddApplication (enbApp); + NS_ASSERT (enb->GetNApplications () == 1); + NS_ASSERT_MSG (enb->GetApplication (0)->GetObject () != 0, "cannot retrieve EpcEnbApplication"); + NS_LOG_LOGIC ("enb: " << enb << ", enb->GetApplication (0): " << enb->GetApplication (0)); } void -EpcHelper::ActivateEpsBearer () +EpcHelper::ActivateEpsBearer (Ptr ueLteDevice, Ptr enbLteDevice, Ptr tft, uint16_t rnti, uint8_t lcid) { - // add tunnel at EpcSgwPgwApplication - // add tunnel at EpcEnbApplication + Ptr ueNode = ueLteDevice->GetNode (); + Ptr ueIpv4 = ueNode->GetObject (); + int32_t interface = ueIpv4->GetInterfaceForDevice (ueLteDevice); + NS_ASSERT (interface >= 0); + NS_ASSERT (ueIpv4->GetNAddresses (interface) == 1); + Ipv4Address ueAddr = ueIpv4->GetAddress (interface, 0).GetLocal (); + NS_LOG_LOGIC (" UE IP address: " << ueAddr); + + // NOTE: unlike ueLteDevice, enbLteDevice is NOT an Ipv4 enabled + // device. In fact we are interested in the S1 device of the eNB. + // We find it by relying on the assumption that the S1 device is the + // only Ipv4 enabled device of the eNB besides the localhost interface. + Ptr enbNode = enbLteDevice->GetNode (); + NS_ASSERT (enbNode != 0); + Ptr enbIpv4 = enbNode->GetObject (); + NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB: " << enbIpv4->GetNInterfaces ()); + // two ifaces total: loopback + the S1-U interface + NS_ASSERT (enbIpv4->GetNInterfaces () == 2); + NS_ASSERT (ueIpv4->GetNAddresses (1) == 1); + // iface index 0 is loopback, index 1 is the S1-U interface + Ipv4Address enbAddr = enbIpv4->GetAddress (1, 0).GetLocal (); + NS_LOG_LOGIC (" ENB IP address: " << enbAddr); + + // setup S1 bearer at EpcSgwPgwApplication + uint32_t teid = m_sgwPgwApp->ActivateS1Bearer (ueAddr, enbAddr, tft); + + // setup S1 bearer at EpcEnbApplication + NS_LOG_LOGIC ("enb: " << enbNode << ", enb->GetApplication (0): " << enbNode->GetApplication (0)); + NS_ASSERT (enbNode->GetNApplications () == 1); + Ptr app = enbNode->GetApplication (0); + NS_ASSERT (app != 0); + Ptr epcEnbApp = app->GetObject (); + NS_ASSERT (epcEnbApp != 0); + epcEnbApp->ErabSetupRequest (teid, rnti, lcid); + + } Ptr -EpcHelper::GetSgwPgwNode () +EpcHelper::GetPgwNode () { return m_sgwPgw; } -void -EpcHelper::InstallGtpu (Ptr n) +Ipv4InterfaceContainer +EpcHelper::AssignUeIpv4Address (NetDeviceContainer ueDevices) { - InstallGtpu (n, m_ipv4.NewAddress ()); + return m_ueAddressHelper.Assign (ueDevices); } -void -EpcHelper::InstallGtpu (Ptr n, Ipv4Address addr) -{ - NS_LOG_FUNCTION (this); - // UDP socket creation and configuration - Ptr m_socket = Socket::CreateSocket (n, TypeId::LookupByName ("ns3::UdpSocketFactory")); - m_socket->Bind (InetSocketAddress (Ipv4Address::GetAny (), m_udpPort)); - - // tap device creation and configuration - Ptr m_tap = CreateObject (); - m_tap->SetAddress (Mac48Address::Allocate ()); - - n->AddDevice (m_tap); - Ptr ipv4 = n->GetObject (); - uint32_t i = ipv4->AddInterface (m_tap); - ipv4->AddAddress (i, Ipv4InterfaceAddress (addr, m_mask)); - ipv4->SetUp (i); - Ptr tunnel = CreateObject (m_tap, m_socket); - m_gtpuEndpoint[n] = tunnel; -} - -void -EpcHelper::CreateGtpuTunnel (Ptr n, Ipv4Address nAddr, Ptr m, Ipv4Address mAddr) -{ - uint32_t teid = m_gtpuEndpoint[n]->CreateGtpuTunnel (mAddr); - m_gtpuEndpoint[m]->CreateGtpuTunnel (nAddr, teid); -} } // namespace ns3 diff --git a/src/lte/helper/epc-helper.h b/src/lte/helper/epc-helper.h index bb352c259..406568061 100644 --- a/src/lte/helper/epc-helper.h +++ b/src/lte/helper/epc-helper.h @@ -16,20 +16,23 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Jaume Nin + * Nicola Baldo */ #ifndef EPC_HELPER_H #define EPC_HELPER_H #include - - +#include +#include +#include namespace ns3 { class Node; class NetDevice; +class EpcSgwPgwApplication; /** * \brief Helper class to handle the creation of the EPC entities and protocols. @@ -54,7 +57,7 @@ public: virtual ~EpcHelper (); // inherited from Object - TypeId GetTypeId (void); + static TypeId GetTypeId (void); /** @@ -70,8 +73,15 @@ public: /** * Activate an EPS bearer, setting up the corresponding S1-U tunnel. * + * + * + * \param ueLteDevice the Ipv4-enabled device of the UE, normally connected via the LTE radio interface + * \param enbLteDevice the non-Ipv4-enabled device of the eNB + * \param tft the Traffic Flow Template of the new bearer + * \param rnti the Radio Network Temporary Identifier that identifies the UE + * \param lcid the Logical Channel IDentifier of the corresponding RadioBearer */ - void ActivateEpsBearer (); + void ActivateEpsBearer (Ptr ueLteDevice, Ptr enbLteDevice, Ptr tft, uint16_t rnti, uint8_t lcid); /** @@ -84,14 +94,34 @@ public: */ Ptr GetPgwNode (); + /** + * Assign IPv4 addresses to UE devices + * + * \param ueDevices the set of UE devices + * + * \return the interface container, \see Ipv4AddressHelper::Assign() which has similar semantics + */ + Ipv4InterfaceContainer AssignUeIpv4Address (NetDeviceContainer ueDevices); + + + private: + /** + * helper to assign addresses to S1-U + * NetDevices + */ + Ipv4AddressHelper m_s1uIpv4AddressHelper; - Ipv4AddressHelper m_s1uIpv4AddressHelper; /**< helper to assign - addresses to S1-U - NetDevices */ + /** + * helper to assign addresses to UE devices as well as to the TUN device of the SGW/PGW + */ + Ipv4AddressHelper m_ueAddressHelper; - Ptr m_sgwPgw; /**< the SGW/PGW node */ + + Ptr m_sgwPgw; + + Ptr m_sgwPgwApp; DataRate m_s1uLinkDataRate; Time m_s1uLinkDelay; diff --git a/src/lte/helper/lena-helper.cc b/src/lte/helper/lena-helper.cc index edf6e4341..579d042f2 100644 --- a/src/lte/helper/lena-helper.cc +++ b/src/lte/helper/lena-helper.cc @@ -318,28 +318,33 @@ LenaHelper::Attach (Ptr ueDevice, Ptr enbDevice) } + void -LenaHelper::ActivateEpsBearer (NetDeviceContainer ueDevices, EpsBearer bearer) +LenaHelper::ActivateEpsBearer (NetDeviceContainer ueDevices, EpsBearer bearer, Ptr tft) { for (NetDeviceContainer::Iterator i = ueDevices.Begin (); i != ueDevices.End (); ++i) { - ActivateEpsBearer (*i, bearer); + ActivateEpsBearer (*i, bearer, tft); } } void -LenaHelper::ActivateEpsBearer (Ptr ueDevice, EpsBearer bearer) +LenaHelper::ActivateEpsBearer (Ptr ueDevice, EpsBearer bearer, Ptr tft) { + // setup RadioBearer first Ptr enbDevice = ueDevice->GetObject ()->GetTargetEnb (); Ptr enbRrc = enbDevice->GetObject ()->GetRrc (); Ptr ueRrc = ueDevice->GetObject ()->GetRrc (); uint16_t rnti = ueRrc->GetRnti (); uint8_t lcid = enbRrc->SetupRadioBearer (rnti, bearer); ueRrc->SetupRadioBearer (rnti, bearer, lcid); + + // then setup S1 Bearer } + void LenaHelper::EnableLogComponents (void) { @@ -380,7 +385,6 @@ LenaHelper::EnableRlcTraces (void) { EnableDlRlcTraces (); EnableUlRlcTraces (); - } diff --git a/src/lte/helper/lena-helper.h b/src/lte/helper/lena-helper.h index 1ec4e69f7..9db2aea61 100644 --- a/src/lte/helper/lena-helper.h +++ b/src/lte/helper/lena-helper.h @@ -32,6 +32,7 @@ #include #include #include +#include namespace ns3 { @@ -106,20 +107,22 @@ public: void Attach (Ptr ueDevice, Ptr enbDevice); /** - * Activate an EPS bearer on a given set of UE devices + * Activate a dedicated EPS bearer on a given set of UE devices * * \param ueDevices the set of UE devices * \param bearer the characteristics of the bearer to be activated + * \param tft the Traffic Flow Template that identifies the traffic to go on this bearer */ - void ActivateEpsBearer (NetDeviceContainer ueDevices, EpsBearer bearer); + void ActivateEpsBearer (NetDeviceContainer ueDevices, EpsBearer bearer, Ptr tft); /** - * Activate an EPS bearer on a given UE device + * Activate a dedicated EPS bearer on a given UE device * * \param ueDevices the set of UE devices * \param bearer the characteristics of the bearer to be activated + * \param tft the Traffic Flow Template that identifies the traffic to go on this bearer */ - void ActivateEpsBearer (Ptr ueDevice, EpsBearer bearer); + void ActivateEpsBearer (Ptr ueDevice, EpsBearer bearer, Ptr tft); /** * diff --git a/src/lte/model/epc-enb-application.cc b/src/lte/model/epc-enb-application.cc index 600798647..8379d6f6b 100644 --- a/src/lte/model/epc-enb-application.cc +++ b/src/lte/model/epc-enb-application.cc @@ -25,38 +25,48 @@ #include "ns3/mac48-address.h" #include "ns3/ipv4.h" #include "ns3/inet-socket-address.h" +#include "ns3/uinteger.h" +#include "ns3/epc-gtpu-header.h" +#include "ns3/lte-mac-tag.h" namespace ns3 { NS_LOG_COMPONENT_DEFINE ("EpcEnbApplication"); -uint16_t EpcEnbApplication::m_teidCounter = 0; -uint32_t EpcEnbApplication::m_indexCounter = 0; - TypeId EpcEnbApplication::GetTypeId (void) { static TypeId tid = TypeId ("ns3::EpcEnbApplication") - .SetParent () - .AddAttribute("GtpuPort", - "UDP Port to be used for GTP-U", - UintegerValue (2152), - MakeUintegerAccessor (&EpcEnbApplication::m_updPort), - MakeUintegerChecker ()); + .SetParent (); return tid; } -EpcEnbApplication::EpcEnbApplication (Address sgwAddress) +EpcEnbApplication::EpcEnbApplication (Ptr lteSocket, Ptr s1uSocket, Ipv4Address sgwAddress) + : m_lteSocket (lteSocket), + m_s1uSocket (s1uSocket), + m_sgwAddress (sgwAddress) { NS_LOG_FUNCTION (this); + m_s1uSocket->SetRecvCallback (MakeCallback (&EpcEnbApplication::RecvFromS1uSocket, this)); + m_lteSocket->SetRecvCallback (MakeCallback (&EpcEnbApplication::RecvFromLteSocket, this)); } EpcEnbApplication::~EpcEnbApplication (void) { + NS_LOG_FUNCTION (this); } +void +EpcEnbApplication::ErabSetupRequest (uint32_t teid, uint16_t rnti, uint8_t lcid) +{ + NS_LOG_FUNCTION (this << teid << rnti << (uint16_t) lcid); + LteFlowId_t rbid (rnti, lcid); + // side effect: create entries if not exist + m_rbidTeidMap[rbid] = teid; + m_teidRbidMap[teid] = rbid; +} void EpcEnbApplication::RecvFromLteSocket (Ptr socket) @@ -64,99 +74,61 @@ EpcEnbApplication::RecvFromLteSocket (Ptr socket) NS_LOG_FUNCTION (this); NS_ASSERT (socket == m_lteSocket); Ptr packet = socket->Recv (); - GtpuHeader gtpu; - // TODO: should determine the TEID based on the Radio Bearer ID - // which should be conveyed by means of a Packet Tag - uint32_t teid = 0; + LteMacTag tag; + bool found = packet->RemovePacketTag (tag); + NS_ASSERT (found); + LteFlowId_t flowId; + flowId.m_rnti = tag.GetRnti (); + flowId.m_lcId = tag.GetLcid (); + std::map::iterator it = m_rbidTeidMap.find (flowId); + NS_ASSERT (it != m_rbidTeidMap.end ()); + uint32_t teid = it->second; SendToS1uSocket (packet, teid); } void EpcEnbApplication::RecvFromS1uSocket (Ptr socket) { - NS_LOG_FUNCTION (this); + NS_LOG_FUNCTION (this << socket); NS_ASSERT (socket == m_s1uSocket); Ptr packet = socket->Recv (); GtpuHeader gtpu; packet->RemoveHeader (gtpu); uint32_t teid = gtpu.GetTeid (); - uint32_t rbid = GetRbid (teid); - SendToLteSocket (packet, rbid); + std::map::iterator it = m_teidRbidMap.find (teid); + NS_ASSERT (it != m_teidRbidMap.end ()); + + // workaround for bug 231 https://www.nsnam.org/bugzilla/show_bug.cgi?id=231 + SocketAddressTag tag; + packet->RemovePacketTag (tag); + + SendToLteSocket (packet, it->second.m_rnti, it->second.m_lcId); } +void +EpcEnbApplication::SendToLteSocket (Ptr packet, uint16_t rnti, uint8_t lcid) +{ + NS_LOG_FUNCTION (this << packet << rnti << (uint16_t) lcid); + LteMacTag tag (rnti, lcid); + packet->AddPacketTag (tag); + int sentBytes = m_lteSocket->Send (packet); + NS_ASSERT (sentBytes > 0); +} + + void EpcEnbApplication::SendToS1uSocket (Ptr packet, uint32_t teid) { + NS_LOG_FUNCTION (this << packet << teid); + GtpuHeader gtpu; gtpu.SetTeid (teid); // From 3GPP TS 29.281 v10.0.0 Section 5.1 // Length of the payload + the non obligatory GTP-U header - gtpu.SetLength (p->GetSize () + h.GetSerializedSize () - 8); + gtpu.SetLength (packet->GetSize () + gtpu.GetSerializedSize () - 8); packet->AddHeader (gtpu); uint32_t flags = 0; m_s1uSocket->SendTo (packet, flags, m_sgwAddress); } -uint32_t -EpcEnbApplication::CreateGtpuTunnel (Ipv4Address destination) -{ - NS_LOG_FUNCTION (this); - if (m_teidCounter == 0xffffffff) - { - NS_FATAL_ERROR ("TEID space exhausted, please implement some TEID reuse mechanism"); - } - CreateGtpuTunnel (destination, ++m_teidCounter); - return m_teidCounter; -} - -void -EpcEnbApplication::CreateGtpuTunnel (Ipv4Address destination, uint32_t teid) -{ - NS_LOG_FUNCTION (this); - m_gtpuMap[m_indexCounter] = CreateObject (teid); - m_dstAddrMap[m_indexCounter] = destination; -} - -uint32_t -EpcEnbApplication::GetRbid (uint32_t teid) -{ - // since we don't have SRBs for now, we can just use the same identifiers - return teid; -} - -uint32_t -EpcEnbApplication::GetTeid (uint32_t rbid) -{ - // since we don't have SRBs for now, we can just use the same identifiers - return rbid; -} - -void -EpcEnbApplication::GtpuRecv (Ptr socket) -{ - NS_LOG_FUNCTION (this); - Ptr packet = socket->Recv (); - uint32_t index = 0; - m_gtpuMap[index]->RemoveHeader (packet); - m_tap->Receive (packet, 0x0800, m_tap->GetAddress (), m_tap->GetAddress (), NetDevice::PACKET_HOST); -} - -bool -EpcEnbApplication::GtpuSend (Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber) -{ - NS_LOG_FUNCTION (this << source << dest << packet << packet->GetSize ()); - // TODO: Instead of use always index 0 make use of the TFT classifier class, probably - // a mapping between the tunnel index (assigned during the tunnel creation) and the classifier - // index (assigned when the first packet is send through) should be maintained. - uint32_t index = 0; - packet = m_gtpuMap[index]->AddHeader (packet); - m_socket->SendTo (packet, 0, InetSocketAddress (m_dstAddrMap[index], m_udpPort)); - return true; -} - -EpcEnbApplication::~EpcEnbApplication () -{ - NS_LOG_FUNCTION_NOARGS (); -} - }; // namespace ns3 diff --git a/src/lte/model/epc-enb-application.h b/src/lte/model/epc-enb-application.h index ad3243847..52e1ae29e 100644 --- a/src/lte/model/epc-enb-application.h +++ b/src/lte/model/epc-enb-application.h @@ -22,14 +22,16 @@ #ifndef EPC_ENB_APPLICATION_H #define EPC_ENB_APPLICATION_H -#include "ns3/address.h" -#include "ns3/socket.h" -#include "ns3/virtual-net-device.h" -#include "ns3/epc-gtpu-l5-protocol.h" -#include "ns3/traced-callback.h" -#include "ns3/callback.h" -#include "ns3/ptr.h" -#include "ns3/object.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ns3 { @@ -37,35 +39,45 @@ namespace ns3 { /** * \ingroup lte * - * GTPv1-U endpoint for all the tunnels of a given node. It encapsulates all the tunnel logic for creating tunnels and encapsulating data through it + * This application is installed inside eNBs and provides the bridge functionality for user data plane packets between the radio interface and the S1-U interface. */ -class EpcEnbApplication : public Object +class EpcEnbApplication : public Application { public: + + // inherited from Object static TypeId GetTypeId (void); /** + * Constructor * - * - * \param radioSocket the socket to be used to send/receive packets to/from the LTE radio interface + * \param lteSocket the socket to be used to send/receive packets to/from the LTE radio interface * \param s1uSocket the socket to be used to send/receive packets * to/from the S1-U interface connected with the SGW * \param sgwAddress the IPv4 address at which this eNB will be able to reach its SGW * */ - EpcEnbApplication (Ptr radioSocket, Ptr s1uSocket, Address sgwAddress); + EpcEnbApplication (Ptr lteSocket, Ptr s1uSocket, Ipv4Address sgwAddress); /** - * destructor + * Destructor * */ virtual ~EpcEnbApplication (void); - void SetupS1Bearer () + /** + * This method is triggered after the eNB received + * a S1-AP message of type E-RAB Setup Request by the MME and the RadioBearer has already been created + * + * \param teid the Tunnel Endpoint IDentifier of the S1-bearer to be setup. + * \param rnti the unique ID of the UE on this eNB + * \param lcid the Logical Channel ID identifying the Radio Bearer + */ + void ErabSetupRequest (uint32_t teid, uint16_t rnti, uint8_t lcid); /** * Method to be assigned to the recv callback of the LTE socket. It is called when the eNB receives a data packet from the radio interface that is to be forwarded to the SGW. @@ -88,7 +100,7 @@ public: * \param packet t * \param rbid the Radio Bearer IDentifier */ - void SendToLteSocket (Ptr packet, uint32_t rbid); + void SendToLteSocket (Ptr packet, uint16_t rnti, uint8_t lcid); /** @@ -103,42 +115,6 @@ public: private: - /** - * Creates a GTPv1-U tunnel between the given destination and the enpoint - * using the specified TEID. - * \param destination IP address of the other end of the tunnel - * \param teid Tunnel Endpoint IDentifier to be assigned to the tunnel - */ - void CreateGtpuTunnel (Ipv4Address destination, uint32_t teid); - - /** - * Creates a GTPv1-U tunnel between the given destination and the enpoint. The - * TEID is automatically sellected. - * \param destination IP address of the other end of the tunnel - * \return the Tunnel Endpoint IDentifier (TEID) assigned to the tunnel - */ - uint32_t CreateGtpuTunnel (Ipv4Address destination); - - - /** - * this function implements the 1-to-1 mapping between S1 Bearers and Radio Bearers - * - * \param teid the Tunnel Endpoint IDentifier (TEID) that identifies an S1-bearer on this eNB - * - * \return the corresponding Radio Bearer Identifier - */ - uint32_t GetRbid (uint32_t teid); - - - /** - * this function implements the 1-to-1 mapping between Radio Bearers and S1 Bearers - * - * \param rbid the Radio Bearer Identifier - * - * \return the corresponding the Tunnel Endpoint IDentifier (TEID) that identifies an S1-bearer on this eNB - */ - uint32_t GetTeid (uint32_t rbid); - /** * raw packet socket to send and receive the packets to and from the LTE radio interface */ @@ -147,25 +123,25 @@ private: /** * UDP socket to send and receive GTP-U the packets to and from the S1-U interface */ - Ptr m_epcSocket; + Ptr m_s1uSocket; /** - * UDP port where the GTP-U Socket is bound, fixed by the standard as 2152 - */ - uint16_t m_udpPort; - - /** - * Map holding the GTP instances of the active tunnels on this endpoint - */ - std::map > m_gtpuMap; - - /** - * address of the SGW which terminates all tunnels + * address of the SGW which terminates all S1-U tunnels */ Ipv4Address m_sgwAddress; - static uint16_t m_teidCounter; - static uint32_t m_indexCounter; + /** + * map telling for each RadioBearer (RNTI,LCID) the corresponding S1-U TEID + * + */ + std::map m_rbidTeidMap; + + /** + * map telling for each S1-U TEID the corresponding RadioBearer (RNTI,LCID) + * + */ + std::map m_teidRbidMap; + }; } //namespace ns3 diff --git a/src/lte/model/epc-sgw-pgw-application.cc b/src/lte/model/epc-sgw-pgw-application.cc index 8592ccb9d..ce021d7ef 100644 --- a/src/lte/model/epc-sgw-pgw-application.cc +++ b/src/lte/model/epc-sgw-pgw-application.cc @@ -25,76 +25,162 @@ #include "ns3/mac48-address.h" #include "ns3/ipv4.h" #include "ns3/inet-socket-address.h" +#include "ns3/epc-gtpu-header.h" namespace ns3 { NS_LOG_COMPONENT_DEFINE ("EpcSgwPgwApplication"); -uint16_t EpcSgwPgwAplication::m_teidCounter = 0; -uint32_t EpcSgwPgwAplication::m_indexCounter = 0; + +///////////////////////// +// EnbInfo +///////////////////////// + + +EpcSgwPgwApplication::EnbInfo::EnbInfo () + : m_teidCounter (0) +{ + NS_LOG_FUNCTION (this); +} + +uint32_t +EpcSgwPgwApplication::EnbInfo::AddBearer (Ptr tft) +{ + NS_LOG_FUNCTION (this << tft); + return m_tftClassifier.Add (tft); +} + +uint32_t +EpcSgwPgwApplication::EnbInfo::Classify (Ptr p) +{ + NS_LOG_FUNCTION (this << p); + // we hardcode DOWNLINK direction since the PGW is espected to + // classify only downlink packets (uplink packets will go to the + // internet without any classification). + return m_tftClassifier.Classify (p, LteTft::DOWNLINK); +} + + +///////////////////////// +// EpcSgwPgwApplication +///////////////////////// TypeId -EpcSgwPgwAplication::GetTypeId (void) +EpcSgwPgwApplication::GetTypeId (void) { static TypeId tid = TypeId ("ns3::EpcSgwPgwApplication") .SetParent (); return tid; } -EpcSgwPgwAplication::EpcSgwPgwAplication (const Ptr tap, const Ptr s) - : m_udpPort (2152) + + +EpcSgwPgwApplication::EpcSgwPgwApplication (const Ptr giTunDevice, const Ptr s1uSocket) + : m_s1uSocket (s1uSocket), + m_giTunDevice (giTunDevice), + m_gtpuUdpPort (2152) // fixed by the standard { - NS_LOG_FUNCTION (this); - m_tap = tap; - m_tap->SetSendCallback (MakeCallback (&EpcSgwPgwAplication::GtpuSend, this)); - m_socket = s; - m_socket->SetRecvCallback (MakeCallback (&EpcSgwPgwAplication::GtpuRecv, this)); + NS_LOG_FUNCTION (this << giTunDevice << s1uSocket); + m_s1uSocket->SetRecvCallback (MakeCallback (&EpcSgwPgwApplication::RecvFromS1uSocket, this)); } -uint32_t -EpcSgwPgwAplication::CreateGtpuTunnel (Ipv4Address destination) -{ - NS_LOG_FUNCTION (this); - CreateGtpuTunnel (destination, ++m_teidCounter); - return m_teidCounter; -} - -void -EpcSgwPgwAplication::CreateGtpuTunnel (Ipv4Address destination, uint32_t teid) -{ - NS_LOG_FUNCTION (this); - m_gtpuMap[m_indexCounter] = CreateObject (teid); - m_dstAddrMap[m_indexCounter] = destination; -} - - -void -EpcSgwPgwAplication::GtpuRecv (Ptr socket) -{ - NS_LOG_FUNCTION (this); - Ptr packet = socket->Recv (65535, 0); - uint32_t index = 0; - m_gtpuMap[index]->RemoveHeader (packet); - m_tap->Receive (packet, 0x0800, m_tap->GetAddress (), m_tap->GetAddress (), NetDevice::PACKET_HOST); -} - -bool -EpcSgwPgwAplication::GtpuSend (Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber) -{ - NS_LOG_FUNCTION (this << source << dest << packet << packet->GetSize ()); - // TODO: Instead of use always index 0 make use of the TFT classifier class, probably - // a mapping between the tunnel index (assigned during the tunnel creation) and the classifier - // index (assigned when the first packet is send through) should be maintained. - uint32_t index = 0; - packet = m_gtpuMap[index]->AddHeader (packet); - m_socket->SendTo (packet, 0, InetSocketAddress (m_dstAddrMap[index], m_udpPort)); - return true; -} - -EpcSgwPgwAplication::~EpcSgwPgwAplication () + +EpcSgwPgwApplication::~EpcSgwPgwApplication () { NS_LOG_FUNCTION_NOARGS (); } + +uint32_t +EpcSgwPgwApplication::ActivateS1Bearer (Ipv4Address ueAddr, Ipv4Address enbAddr, Ptr tft) +{ + NS_LOG_FUNCTION (this << ueAddr << enbAddr << tft); + // side effect: add entry if not exists + m_ueAddrEnbAddrMap[ueAddr] = enbAddr; + + // side effect: create new EnbInfo if it does not exist + uint32_t teid = m_enbInfoMap[enbAddr].AddBearer (tft); + return teid; +} + +bool +EpcSgwPgwApplication::RecvFromGiTunDevice (Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber) +{ + NS_LOG_FUNCTION (this << source << dest << packet << packet->GetSize ()); + + // get IP address of UE + Ptr pCopy = packet->Copy (); + Ipv4Header ipv4Header; + pCopy->RemoveHeader (ipv4Header); + Ipv4Address ueAddr = ipv4Header.GetDestination (); + NS_LOG_LOGIC ("packet addressed to UE " << ueAddr); + + // find corresponding eNB address + std::map::iterator it1 = m_ueAddrEnbAddrMap.find (ueAddr); + if (it1 == m_ueAddrEnbAddrMap.end ()) + { + NS_LOG_WARN ("could not find corresponding eNB for UE address " << ueAddr) ; + } + else + { + Ipv4Address enbAddr = it1->second; + // lookup into TFT classifier for that eNB + std::map::iterator it2 = m_enbInfoMap.find (enbAddr); + NS_ASSERT (it2 != m_enbInfoMap.end ()); + uint32_t teid = it2->second.Classify (packet); + if (teid == 0) + { + NS_LOG_WARN ("no matching TEID for this packet"); + } + else + { + SendToS1uSocket (packet, enbAddr, teid); + } + } + // there is no reason why we should notify the Gi TUN + // VirtualNetDevice that he failed to send the packet + const bool succeeded = true; + return succeeded; +} + +void +EpcSgwPgwApplication::RecvFromS1uSocket (Ptr socket) +{ + NS_LOG_FUNCTION (this << socket); + NS_ASSERT (socket == m_s1uSocket); + Ptr packet = socket->Recv (); + GtpuHeader gtpu; + packet->RemoveHeader (gtpu); + uint32_t teid = gtpu.GetTeid (); + + // workaround for bug 231 https://www.nsnam.org/bugzilla/show_bug.cgi?id=231 + SocketAddressTag tag; + packet->RemovePacketTag (tag); + + SendToGiTunDevice (packet, teid); +} + +void +EpcSgwPgwApplication::SendToGiTunDevice (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); +} + +void +EpcSgwPgwApplication::SendToS1uSocket (Ptr packet, Ipv4Address enbAddr, uint32_t teid) +{ + NS_LOG_FUNCTION (this << packet << enbAddr << teid); + + GtpuHeader gtpu; + gtpu.SetTeid (teid); + // From 3GPP TS 29.281 v10.0.0 Section 5.1 + // Length of the payload + the non obligatory GTP-U header + gtpu.SetLength (packet->GetSize () + gtpu.GetSerializedSize () - 8); + packet->AddHeader (gtpu); + uint32_t flags = 0; + m_s1uSocket->SendTo (packet, flags, InetSocketAddress(enbAddr, m_gtpuUdpPort)); +} + }; // namespace ns3 diff --git a/src/lte/model/epc-sgw-pgw-application.h b/src/lte/model/epc-sgw-pgw-application.h index be7b8d7ee..5bfe8e395 100644 --- a/src/lte/model/epc-sgw-pgw-application.h +++ b/src/lte/model/epc-sgw-pgw-application.h @@ -22,14 +22,19 @@ #ifndef EPC_SGW_PGW_APPLICATION_H #define EPC_SGW_PGW_APPLICATION_H -#include "ns3/address.h" -#include "ns3/socket.h" -#include "ns3/virtual-net-device.h" -#include "ns3/epc-gtpu-l5-protocol.h" -#include "ns3/traced-callback.h" -#include "ns3/callback.h" -#include "ns3/ptr.h" -#include "ns3/object.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ns3 { @@ -37,73 +42,151 @@ namespace ns3 { /** * \ingroup lte * - * GTPv1-U endpoint for all the tunnels of a given node. It encapsulates all the tunnel logic for creating tunnels and encapsulating data through it + * This application implements the SGW/PGW functionality. */ -class EpcSgwPgwAplication : public Object +class EpcSgwPgwApplication : public Application { public: + + // inherited from Object static TypeId GetTypeId (void); - /** - * Method assigned to the send callback of the upper end of the tunnel. It adds - * the GTP header and sends it through the tunnel - */ - bool GtpuSend (Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber); - /** - * Method assigned to the receive callback of the upper end of the tunnel. It strips - * the GTP header and sends it up to the application - */ - void GtpuRecv (Ptr socket); - /** * Constructor that binds the tap device to the callback methods. - * \param tap VirtualNetDevice used to tunnel the packets - * \param s Socket used to send the tunneled packets + * + * \param giTunDevice 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 */ - EpcSgwPgwAplication (const Ptr tap, const Ptr s); - virtual ~EpcSgwPgwAplication (void); + EpcSgwPgwApplication (const Ptr giTunDevice, const Ptr s1uSocket); - /** - * Creates a GTPv1-U tunnel between the given destination and the enpoint - * using the specified TEID. - * \param destination IP address of the other end of the tunnel - * \param teid Tunnel Endpoint IDentifier to be assigned to the tunnel + /** + * Destructor */ - void CreateGtpuTunnel (Ipv4Address destination, uint32_t teid); + virtual ~EpcSgwPgwApplication (void); - /** - * Creates a GTPv1-U tunnel between the given destination and the enpoint. The - * TEID is automatically sellected. - * \param destination IP address of the other end of the tunnel - * \return teid Tunnel Endpoint IDentifier assigned to the tunnel + + /** + * Simulates the reception by the PGW of a GTP-C message of type + * CreateSessionRequest or BearerResourceCommand coming from the + * MME. This triggers the creation of a new EPS Bearer. + * + * \param bearer the specification of the EPS Bearer to be created + * \param enbS1uAddress the IPv4 address at which the SGW can reach + * the eNB via the S1-U interface + * \param tft the Traffic Flow Template related to this bearer + * + * \return the TunnelEndpointIdentifier of this EPS bearer */ - uint32_t CreateGtpuTunnel (Ipv4Address destination); + uint32_t ActivateS1Bearer (Ipv4Address ueAddr, Ipv4Address enbAddr, Ptr tft); + + + /** + * Method to be assigned to the callback of the Gi TUN VirtualNetDevice. It + * is called when the SGW/PGW receives a data packet from the + * internet (including IP headers) that is to be sent to the UE via + * its associated eNB, tunneling IP over GTP-U/UDP/IP. + * + * \param packet + * \param source + * \param dest + * \param protocolNumber + * \return true always + */ + bool RecvFromGiTunDevice (Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber); + + + /** + * Method to be assigned to the recv callback of the S1-U socket. It + * is called when the SGW/PGW receives a data packet from the eNB + * that is to be forwarded to the internet. + * + * \param socket pointer to the S1-U socket + */ + void RecvFromS1uSocket (Ptr socket); + + /** + * Send a packet to the internet via the Gi interface of the SGW/PGW + * + * \param packet + */ + void SendToGiTunDevice (Ptr packet, uint32_t teid); + + + /** + * Send a packet to the SGW via the S1-U interface + * + * \param packet packet to be sent + * \param enbS1uAddress the address of the eNB + * \param teid the Tunnel Enpoint IDentifier + */ + void SendToS1uSocket (Ptr packet, Ipv4Address enbS1uAddress, uint32_t teid); + + private: - /** - * UDP socket to send and receive the packets to and from the tunnel - */ - Ptr m_socket; - /** - * UDP port where the socket is bind, fixed by the standard as 2152 - */ - uint16_t m_udpPort; - /** - * VirtualNetDevice to create the tunnel - */ - Ptr m_tap; - /** - * Map holding the GTP instances of the active tunnels on this endpoint - */ - std::map > m_gtpuMap; - /** - * Map holding the destination address of the active tunnels on this endpoint - */ - std::map m_dstAddrMap; - static uint16_t m_teidCounter; - static uint32_t m_indexCounter; + + /** + * store info for each eNB connected to this SGW + * + */ + class EnbInfo + { + public: + EnbInfo (); + + /** + * + * \param tft the Traffic Flow Template of the new bearer to be added + * + * \return the TEID of the newly added bearer + */ + uint32_t AddBearer (Ptr tft); + + + /** + * + * + * \param p the IP packet from the internet to be classified + * + * \return the corresponding TEID > 0 if matched, or 0 if no match + */ + uint32_t Classify (Ptr p); + + + private: + uint32_t m_teidCounter; + EpsTftClassifier m_tftClassifier; + }; + + + /** + * UDP socket to send and receive GTP-U packets to and from the S1-U interface + */ + Ptr m_s1uSocket; + + /** + * TUN VirtualNetDevice used for tunneling/detunneling IP packets + * from/to the internet over GTP-U/UDP/IP on the S1 interface + */ + Ptr m_giTunDevice; + + /** + * Map telling for each UE address what is the corresponding eNB address + */ + std::map m_ueAddrEnbAddrMap; + + /** + * Map telling for each eNB address the corresponding eNB info (TFT + * classifier, etc.) + */ + std::map m_enbInfoMap; + + uint16_t m_gtpuUdpPort; + }; } //namespace ns3 diff --git a/src/lte/model/eps-tft-classifier.cc b/src/lte/model/eps-tft-classifier.cc index 0259ccf11..cc7092f0d 100644 --- a/src/lte/model/eps-tft-classifier.cc +++ b/src/lte/model/eps-tft-classifier.cc @@ -144,9 +144,12 @@ EpsTftClassifier::Classify (Ptr p, LteTft::Direction direction) << " tos=0x" << std::hex << tos); // now it is possible to classify the packet! - std::map >::const_iterator it; + // we use a reverse iterator since filter priority is not implemented properly. + // This way, since the default bearer is expected to be added first, it will be evaluated last. + std::map >::const_reverse_iterator it; NS_LOG_LOGIC ("TFT MAP size: " << m_tftMap.size ()); - for (it = m_tftMap.begin (); it != m_tftMap.end (); ++it) + + for (it = m_tftMap.rbegin (); it != m_tftMap.rend (); ++it) { NS_LOG_LOGIC ("TFT id: " << it->first ); NS_LOG_LOGIC (" Ptr: " << it->second); diff --git a/src/lte/model/lte-tft.cc b/src/lte/model/lte-tft.cc index a683409c4..bcdae983a 100644 --- a/src/lte/model/lte-tft.cc +++ b/src/lte/model/lte-tft.cc @@ -135,6 +135,17 @@ LteTft::PacketFilter::Matches (Direction d, return false; } + +Ptr +LteTft::Default () +{ + Ptr tft = Create (); + LteTft::PacketFilter defaultPacketFilter; + tft->Add (defaultPacketFilter); + return tft; +} + + LteTft::LteTft () : m_numFilters (0) { diff --git a/src/lte/model/lte-tft.h b/src/lte/model/lte-tft.h index 937798d9b..2f1ea4eaf 100644 --- a/src/lte/model/lte-tft.h +++ b/src/lte/model/lte-tft.h @@ -41,6 +41,14 @@ class LteTft : public SimpleRefCount { public: + + + /** + * creates a TFT matching any traffic + * + * \return a newly created TFT that will match any traffic + */ + static Ptr Default (); /** * Indicates the direction of the traffic that is to be classified. diff --git a/src/lte/test/epc-test-s1u-downlink.cc b/src/lte/test/epc-test-s1u-downlink.cc new file mode 100644 index 000000000..a295f1f88 --- /dev/null +++ b/src/lte/test/epc-test-s1u-downlink.cc @@ -0,0 +1,226 @@ +/* -*- 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: 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/uinteger.h" +#include "ns3/packet-sink.h" +#include +#include + +using namespace ns3; + + + +struct UeTestData +{ + UeTestData (uint32_t n, uint32_t s); + + uint32_t numPkts; + uint32_t pktSize; + + Ptr serverApp; + Ptr clientApp; +}; + +UeTestData::UeTestData (uint32_t n, uint32_t s) + : numPkts (n), + pktSize (s) +{ +} + +struct EnbTestData +{ + std::vector ues; +}; + + +class EpcS1uTestCase : public TestCase +{ +public: + EpcS1uTestCase (std::string name, std::vector v); + virtual ~EpcS1uTestCase (); + +private: + virtual void DoRun (void); + std::vector m_enbTestData; +}; + + +EpcS1uTestCase::EpcS1uTestCase (std::string name, std::vector v) + : TestCase (name), + m_enbTestData (v) +{ +} + +EpcS1uTestCase::~EpcS1uTestCase () +{ +} + +void +EpcS1uTestCase::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"); + 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); + + + + + NodeContainer enbs; + + for (std::vector::iterator enbit = m_enbTestData.begin (); + enbit < m_enbTestData.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); + + uint16_t port = 1234; + PacketSinkHelper packetSinkHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), port)); + ApplicationContainer apps = packetSinkHelper.Install (ue); + apps.Start (Seconds (1.0)); + apps.Stop (Seconds (10.0)); + enbit->ues[u].serverApp = apps.Get (0)->GetObject (); + + Time interPacketInterval = Seconds (0.01); + UdpClientHelper client (ueIpIface.GetAddress (0), port); + client.SetAttribute ("MaxPackets", UintegerValue (enbit->ues[u].numPkts)); + client.SetAttribute ("Interval", TimeValue (interPacketInterval)); + client.SetAttribute ("PacketSize", UintegerValue (enbit->ues[u].pktSize)); + apps = client.Install (remoteHost); + apps.Start (Seconds (2.0)); + apps.Stop (Seconds (10.0)); + enbit->ues[u].clientApp = apps.Get (0); + + uint16_t rnti = u+1; + uint16_t lcid = 1; + epcHelper->ActivateEpsBearer (ueLteDevice, lteEnbNetDevice, LteTft::Default (), rnti, lcid); + + } + + } + + Simulator::Run (); + + for (std::vector::iterator enbit = m_enbTestData.begin (); + enbit < m_enbTestData.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"); + } + } + + +} + + + + + +/** + * Test that the S1-U interface implementation works correctly + */ +class EpcS1uTestSuite : public TestSuite +{ +public: + EpcS1uTestSuite (); + +} g_epcS1uTestSuiteInstance; + +EpcS1uTestSuite::EpcS1uTestSuite () + : TestSuite ("epc-s1u-downlink", SYSTEM) +{ + + std::vector v1; + EnbTestData e1; + UeTestData f1 (1, 100); + e1.ues.push_back (f1); + v1.push_back (e1); + AddTestCase (new EpcS1uTestCase ("1 eNB, 1UE", v1)); +} + diff --git a/src/lte/test/lte-test-interference.cc b/src/lte/test/lte-test-interference.cc index 515870d25..287dbf865 100644 --- a/src/lte/test/lte-test-interference.cc +++ b/src/lte/test/lte-test-interference.cc @@ -160,8 +160,8 @@ LteInterferenceTestCase::DoRun (void) // Activate an EPS bearer enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE; EpsBearer bearer (q); - lena->ActivateEpsBearer (ueDevs1, bearer); - lena->ActivateEpsBearer (ueDevs2, bearer); + lena->ActivateEpsBearer (ueDevs1, bearer, LteTft::Default ()); + lena->ActivateEpsBearer (ueDevs2, bearer, LteTft::Default ()); // Use testing chunk processor in the PHY layer diff --git a/src/lte/test/lte-test-link-adaptation.cc b/src/lte/test/lte-test-link-adaptation.cc index ecaaff8d3..6a88fba43 100644 --- a/src/lte/test/lte-test-link-adaptation.cc +++ b/src/lte/test/lte-test-link-adaptation.cc @@ -188,10 +188,10 @@ LteLinkAdaptationTestCase::DoRun (void) // Attach a UE to a eNB lena->Attach (ueDevs, enbDevs.Get (0)); - // Activate an EPS bearer - enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE; + // Activate the default EPS bearer + enum EpsBearer::Qci q = EpsBearer::NGBR_VIDEO_TCP_DEFAULT; EpsBearer bearer (q); - lena->ActivateEpsBearer (ueDevs, bearer); + lena->ActivateEpsBearer (ueDevs, bearer, LteTft::Default ()); // Use testing chunk processor in the PHY layer // It will be used to test that the SNR is as intended diff --git a/src/lte/test/lte-test-pf-ff-mac-scheduler.cc b/src/lte/test/lte-test-pf-ff-mac-scheduler.cc index 03c4a0d63..f3d0d5d71 100644 --- a/src/lte/test/lte-test-pf-ff-mac-scheduler.cc +++ b/src/lte/test/lte-test-pf-ff-mac-scheduler.cc @@ -262,7 +262,7 @@ LenaPfFfMacSchedulerTestCase1::DoRun (void) // Activate an EPS bearer enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE; EpsBearer bearer (q); - lena->ActivateEpsBearer (ueDevs, bearer); + lena->ActivateEpsBearer (ueDevs, bearer, LteTft::Default ()); lena->SetAttribute ("PropagationModel", StringValue ("ns3::FriisSpectrumPropagationLossModel")); @@ -438,7 +438,7 @@ LenaPfFfMacSchedulerTestCase2::DoRun (void) // Activate an EPS bearer enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE; EpsBearer bearer (q); - lena->ActivateEpsBearer (ueDevs, bearer); + lena->ActivateEpsBearer (ueDevs, bearer, LteTft::Default ()); lena->SetAttribute ("PropagationModel", StringValue ("ns3::FriisSpectrumPropagationLossModel")); diff --git a/src/lte/test/lte-test-rr-ff-mac-scheduler.cc b/src/lte/test/lte-test-rr-ff-mac-scheduler.cc index 87665d5bc..0ae60eb08 100644 --- a/src/lte/test/lte-test-rr-ff-mac-scheduler.cc +++ b/src/lte/test/lte-test-rr-ff-mac-scheduler.cc @@ -250,7 +250,7 @@ LenaRrFfMacSchedulerTestCase::DoRun (void) // Activate an EPS bearer enum EpsBearer::Qci q = EpsBearer::GBR_CONV_VOICE; EpsBearer bearer (q); - lena->ActivateEpsBearer (ueDevs, bearer); + lena->ActivateEpsBearer (ueDevs, bearer, LteTft::Default ()); lena->SetAttribute ("PropagationModel", StringValue ("ns3::FriisSpectrumPropagationLossModel")); diff --git a/src/lte/test/test-eps-tft-classifier.cc b/src/lte/test/test-eps-tft-classifier.cc index 80997492a..66624a6bb 100644 --- a/src/lte/test/test-eps-tft-classifier.cc +++ b/src/lte/test/test-eps-tft-classifier.cc @@ -133,6 +133,12 @@ EpsTftClassifierTestSuite::EpsTftClassifierTestSuite () : TestSuite ("eps-tft-classifier", UNIT) { NS_LOG_FUNCTION (this); + + + /////////////////////////// + // check some TFT matches + /////////////////////////// + Ptr c1 = Create (); @@ -171,8 +177,6 @@ EpsTftClassifierTestSuite::EpsTftClassifierTestSuite () c1->Add (tft1_2); - - // ------------------------------------classifier---direction--------------src address---------------dst address---src port--dst port--ToS--TFT id // test IP addresses @@ -199,6 +203,82 @@ EpsTftClassifierTestSuite::EpsTftClassifierTestSuite () AddTestCase (new EpsTftClassifierTestCase (c1, LteTft::UPLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 3456, 6, 0, 2)); AddTestCase (new EpsTftClassifierTestCase (c1, LteTft::DOWNLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 3461, 3461, 0, 2)); AddTestCase (new EpsTftClassifierTestCase (c1, LteTft::DOWNLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 9, 3489, 0, 2)); + + + + /////////////////////////// + // check default TFT + /////////////////////////// + + Ptr c2 = Create (); + c2->Add (LteTft::Default ()); + + // ------------------------------------classifier---direction--------------src address---------------dst address---src port--dst port--ToS--TFT id + + // test IP addresses + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::UPLINK, Ipv4Address ("2.2.3.4"), Ipv4Address ("1.1.1.1"), 4, 1234, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::UPLINK, Ipv4Address ("2.2.3.4"), Ipv4Address ("1.0.0.0"), 2, 123, 5, 1)); + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::UPLINK, Ipv4Address ("6.2.3.4"), Ipv4Address ("1.1.1.1"), 4, 1234, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::DOWNLINK, Ipv4Address ("3.3.3.4"), Ipv4Address ("4.4.4.1"), 4, 1234, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::DOWNLINK, Ipv4Address ("3.3.4.4"), Ipv4Address ("4.4.4.1"), 4, 1234, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::UPLINK, Ipv4Address ("3.3.3.4"), Ipv4Address ("4.4.2.1"), 4, 1234, 0, 1)); + + // test remote port + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::UPLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 1024, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::UPLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 1025, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::UPLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 1035, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::UPLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 1234, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::DOWNLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 1024, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::DOWNLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 1025, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::DOWNLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 1035, 0, 1)); + + // test local port + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::UPLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 3456, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::UPLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 3457, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::UPLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 3489, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::UPLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 3456, 6, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::DOWNLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 3461, 3461, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c2, LteTft::DOWNLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 9, 3489, 0, 1)); + + + + /////////////////////////////////////////// + // check default TFT plus dedicated ones + /////////////////////////////////////////// + + Ptr c3 = Create (); + c3->Add (LteTft::Default ()); + c3->Add (tft1_1); + c3->Add (tft1_2); + + // ------------------------------------classifier---direction--------------src address---------------dst address---src port--dst port--ToS--TFT id + + // test IP addresses + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::UPLINK, Ipv4Address ("2.2.3.4"), Ipv4Address ("1.1.1.1"), 4, 1234, 0, 2)); + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::UPLINK, Ipv4Address ("2.2.3.4"), Ipv4Address ("1.0.0.0"), 2, 123, 5, 2)); + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::UPLINK, Ipv4Address ("6.2.3.4"), Ipv4Address ("1.1.1.1"), 4, 1234, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::DOWNLINK, Ipv4Address ("3.3.3.4"), Ipv4Address ("4.4.4.1"), 4, 1234, 0, 2)); + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::DOWNLINK, Ipv4Address ("3.3.4.4"), Ipv4Address ("4.4.4.1"), 4, 1234, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::UPLINK, Ipv4Address ("3.3.3.4"), Ipv4Address ("4.4.2.1"), 4, 1234, 0, 1)); + + // test remote port + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::UPLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 1024, 0, 3)); + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::UPLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 1025, 0, 3)); + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::UPLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 1035, 0, 3)); + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::UPLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 1234, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::DOWNLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 1024, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::DOWNLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 1025, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::DOWNLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 1035, 0, 1)); + + // test local port + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::UPLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 3456, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::UPLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 3457, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::UPLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 4, 3489, 0, 1)); + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::UPLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 3456, 6, 0, 3)); + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::DOWNLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 3461, 3461, 0, 3)); + AddTestCase (new EpsTftClassifierTestCase (c3, LteTft::DOWNLINK, Ipv4Address ("9.1.1.1"), Ipv4Address ("8.1.1.1"), 9, 3489, 0, 3)); + + } diff --git a/src/lte/wscript b/src/lte/wscript index f6ee4945b..2e9826761 100644 --- a/src/lte/wscript +++ b/src/lte/wscript @@ -2,7 +2,7 @@ def build(bld): - module = bld.create_ns3_module('lte', ['core', 'network', 'spectrum', 'stats', 'virtual-net-device']) + module = bld.create_ns3_module('lte', ['core', 'network', 'spectrum', 'stats', 'virtual-net-device','point-to-point','applications','internet','csma']) module.source = [ 'model/lte-common.cc', 'model/lte-spectrum-phy.cc', @@ -80,6 +80,7 @@ def build(bld): 'test/lte-test-rlc-um-transmitter.cc', 'test/epc-test-gtpu.cc', 'test/test-eps-tft-classifier.cc', + 'test/epc-test-s1u-downlink.cc', ] headers = bld.new_task_gen('ns3header') diff --git a/src/network/utils/packet-socket.cc b/src/network/utils/packet-socket.cc index 5308ca9fa..d785c7cb7 100644 --- a/src/network/utils/packet-socket.cc +++ b/src/network/utils/packet-socket.cc @@ -356,7 +356,7 @@ PacketSocket::SendTo (Ptr p, uint32_t flags, const Address &address) } else { - return 0; + return p->GetSize (); } }