diff --git a/src/lte/examples/lena-x2-handover.cc b/src/lte/examples/lena-x2-handover.cc new file mode 100644 index 000000000..84024e337 --- /dev/null +++ b/src/lte/examples/lena-x2-handover.cc @@ -0,0 +1,160 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2012 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: Manuel Requena + */ + +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/internet-module.h" +#include "ns3/mobility-module.h" +#include "ns3/lte-module.h" +#include "ns3/applications-module.h" +#include "ns3/point-to-point-module.h" +#include "ns3/config-store.h" +//#include "ns3/gtk-config-store.h" + +using namespace ns3; + +/** + * Sample simulation script for a X2-based handover. + * It instantiates two eNodeB, attaches one UE to the 'source' eNB and + * triggers a handover of the UE towards the 'target' eNB. + */ +NS_LOG_COMPONENT_DEFINE ("EpcX2HandoverExample"); +int +main (int argc, char *argv[]) +{ + LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_ALL); + + LogComponentEnable ("LteHelper", logLevel); + LogComponentEnable ("EpcHelper", logLevel); + LogComponentEnable ("EpcEnbApplication", logLevel); + LogComponentEnable ("EpcX2", logLevel); + LogComponentEnable ("EpcSgwPgwApplication", logLevel); + + LogComponentEnable ("LteEnbRrc", logLevel); + LogComponentEnable ("LteEnbNetDevice", logLevel); + LogComponentEnable ("LteUeRrc", logLevel); + LogComponentEnable ("LteUeNetDevice", logLevel); + + uint16_t numberOfUes = 1; + uint16_t numberOfEnbs = 2; + double simTime = 4.0; + double distance = 60.0; + + // Command line arguments + CommandLine cmd; + cmd.AddValue("numberOfUes", "Number of UEs", numberOfUes); + cmd.AddValue("numberOfEnbs", "Number of eNodeBs", numberOfEnbs); + cmd.AddValue("simTime", "Total duration of the simulation (in seconds)",simTime); + cmd.Parse(argc, argv); + + + Ptr lteHelper = CreateObject (); + Ptr epcHelper = CreateObject (); + lteHelper->SetEpcHelper (epcHelper); + lteHelper->SetSchedulerType("ns3::RrFfMacScheduler"); + + 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; + p2ph.SetDeviceAttribute ("DataRate", DataRateValue (DataRate ("100Gb/s"))); + p2ph.SetDeviceAttribute ("Mtu", UintegerValue (1500)); + p2ph.SetChannelAttribute ("Delay", TimeValue (Seconds (0.010))); + NetDeviceContainer internetDevices = p2ph.Install (pgw, remoteHost); + Ipv4AddressHelper ipv4h; + ipv4h.SetBase ("1.0.0.0", "255.0.0.0"); + Ipv4InterfaceContainer internetIpIfaces = ipv4h.Assign (internetDevices); + + // Routing of the Internet Host (towards the LTE network) + Ipv4StaticRoutingHelper ipv4RoutingHelper; + Ptr remoteHostStaticRouting = ipv4RoutingHelper.GetStaticRouting (remoteHost->GetObject ()); + // interface 0 is localhost, 1 is the p2p device + remoteHostStaticRouting->AddNetworkRouteTo (Ipv4Address ("7.0.0.0"), Ipv4Mask ("255.0.0.0"), 1); + + NodeContainer ueNodes; + NodeContainer enbNodes; + enbNodes.Create(numberOfEnbs); + ueNodes.Create(numberOfUes); + + // Install Mobility Model + Ptr positionAlloc = CreateObject (); + for (uint16_t i = 0; i < numberOfEnbs; i++) + { + positionAlloc->Add (Vector(distance * i, 0, 0)); + } + MobilityHelper mobility; + mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel"); + mobility.SetPositionAllocator(positionAlloc); + mobility.Install(enbNodes); + mobility.Install(ueNodes); + + // Install LTE Devices in eNB and UEs + 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 ueNode = ueNodes.Get (u); + // Set the default gateway for the UE + Ptr ueStaticRouting = ipv4RoutingHelper.GetStaticRouting (ueNode->GetObject ()); + ueStaticRouting->SetDefaultRoute (epcHelper->GetUeDefaultGatewayAddress (), 1); + } + + + // Attach all UEs to the first eNodeB + for (uint16_t i = 0; i < numberOfUes; i++) + { + lteHelper->Attach (ueLteDevs.Get(i), enbLteDevs.Get(0)); + } + + // Activate a dedicated EPS Bearer (including Radio Bearer) between UEs and its eNB + // (note that the default EPS bearer will already have been activated) + // lteHelper->ActivateDedicatedEpsBearer (ueLteDevs, EpsBearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT), EpcTft::Default ()); + + + // Add X2 inteface + lteHelper->AddX2Interface (enbNodes); + + // X2-based Handover + lteHelper->HandoverRequest (Seconds (2.0), ueNodes.Get (0), enbNodes.Get (0), enbNodes.Get (1)); + + + Simulator::Stop(Seconds(simTime)); + Simulator::Run(); + + // GtkConfigStore config; + // config.ConfigureAttributes(); + + Simulator::Destroy(); + return 0; + +} diff --git a/src/lte/examples/wscript b/src/lte/examples/wscript index 533094580..66e9e2d17 100644 --- a/src/lte/examples/wscript +++ b/src/lte/examples/wscript @@ -34,4 +34,7 @@ def build(bld): obj = bld.create_ns3_program('lena-simple-epc', ['lte']) obj.source = 'lena-simple-epc.cc' + obj = bld.create_ns3_program('lena-x2-handover', + ['lte']) + obj.source = 'lena-x2-handover.cc' diff --git a/src/lte/helper/epc-helper.cc b/src/lte/helper/epc-helper.cc index 40c3e32a9..7c1de80b1 100644 --- a/src/lte/helper/epc-helper.cc +++ b/src/lte/helper/epc-helper.cc @@ -32,6 +32,10 @@ #include #include +#include +#include +#include + namespace ns3 { @@ -39,8 +43,10 @@ NS_LOG_COMPONENT_DEFINE ("EpcHelper"); NS_OBJECT_ENSURE_REGISTERED (EpcHelper); + EpcHelper::EpcHelper () - : m_gtpuUdpPort (2152) // fixed by the standard + : m_gtpuUdpPort (2152), // fixed by the standard + m_x2cUdpPort (4444) // fixed by the standard TODO { NS_LOG_FUNCTION (this); @@ -49,6 +55,8 @@ EpcHelper::EpcHelper () // (remember that net broadcast and null address are not valid) m_s1uIpv4AddressHelper.SetBase ("10.0.0.0", "255.255.255.252"); + m_x2Ipv4AddressHelper.SetBase ("12.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"); @@ -191,7 +199,82 @@ EpcHelper::AddEnb (Ptr enb, Ptr lteEnbNetDevice) 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)); + + NS_LOG_INFO ("Create EpcX2 entity"); + Ptr x2 = CreateObject (); + enb->AggregateObject (x2); + +} + + +void +EpcHelper::AddX2Interface (Ptr enb1, Ptr enb2) +{ + NS_LOG_FUNCTION (this << enb1 << enb2); + + // Create a point to point link between the two eNBs with + // the corresponding new NetDevices on each side + NodeContainer enbNodes; + enbNodes.Add (enb1); + enbNodes.Add (enb2); + PointToPointHelper p2ph; +// TODO Add m_x2Link*** parameters in epc.helper.h +// TODO Create Make***Accessor functions +// p2ph.SetDeviceAttribute ("DataRate", DataRateValue (m_x2LinkDataRate)); +// p2ph.SetDeviceAttribute ("Mtu", UintegerValue (m_x2LinkMtu)); +// p2ph.SetChannelAttribute ("Delay", TimeValue (m_x2LinkDelay)); + NetDeviceContainer enbDevices = p2ph.Install (enb1, enb2); + NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB #1 after installing p2p dev: " << enb1->GetObject ()->GetNInterfaces ()); + NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB #2 after installing p2p dev: " << enb2->GetObject ()->GetNInterfaces ()); + Ptr enb1Dev = enbDevices.Get (0); + Ptr enb2Dev = enbDevices.Get (1); + + m_x2Ipv4AddressHelper.NewNetwork (); + Ipv4InterfaceContainer enbIpIfaces = m_x2Ipv4AddressHelper.Assign (enbDevices); + NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB #1 after assigning Ipv4 addr to X2 dev: " << enb1->GetObject ()->GetNInterfaces ()); + NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB #2 after assigning Ipv4 addr to X2 dev: " << enb2->GetObject ()->GetNInterfaces ()); + + Ipv4Address enb1Address = enbIpIfaces.GetAddress (0); + Ipv4Address enb2Address = enbIpIfaces.GetAddress (1); + + // Create X2-C socket for the eNB1 + Ptr enb1X2cSocket = Socket::CreateSocket (enb1, TypeId::LookupByName ("ns3::UdpSocketFactory")); + int retval = enb1X2cSocket->Bind (InetSocketAddress (enb1Address, m_x2cUdpPort)); + NS_ASSERT (retval == 0); + + // Create X2-C socket for the eNB2 + Ptr enb2X2cSocket = Socket::CreateSocket (enb2, TypeId::LookupByName ("ns3::UdpSocketFactory")); + retval = enb2X2cSocket->Bind (InetSocketAddress (enb2Address, m_x2cUdpPort)); + NS_ASSERT (retval == 0); + + + // Add X2 interface to the eNB1's X2 entity + Ptr enb1X2 = enb1->GetObject (); + Ptr enb1LteDev = enb1->GetDevice (0)->GetObject (); + uint16_t enb1CellId = enb1LteDev->GetCellId (); + NS_LOG_LOGIC ("LteEnbNetDevice #1 = " << enb1LteDev << " - CellId = " << enb1CellId); + + // Add X2 interface to the eNB2's X2 entity + Ptr enb2X2 = enb2->GetObject (); + Ptr enb2LteDev = enb2->GetDevice (0)->GetObject (); + uint16_t enb2CellId = enb2LteDev->GetCellId (); + NS_LOG_LOGIC ("LteEnbNetDevice #2 = " << enb2LteDev << " - CellId = " << enb2CellId); + + enb1X2->AddX2Interface (enb1CellId, enb1X2cSocket, enb2CellId, enb2X2cSocket); + enb2X2->AddX2Interface (enb2CellId, enb2X2cSocket, enb1CellId, enb1X2cSocket); + +} + + +void +EpcHelper::SendHandoverRequest (Ptr ueNode, Ptr sourceEnbNode, Ptr targetEnbNode) +{ + NS_LOG_FUNCTION (this << ueNode << sourceEnbNode << targetEnbNode); + + Ptr sourceRrc = sourceEnbNode->GetDevice (0)->GetObject ()->GetRrc (); + + sourceRrc->SendHandoverRequest (ueNode, sourceEnbNode, targetEnbNode); } diff --git a/src/lte/helper/epc-helper.h b/src/lte/helper/epc-helper.h index f405ca125..7753981bd 100644 --- a/src/lte/helper/epc-helper.h +++ b/src/lte/helper/epc-helper.h @@ -34,6 +34,7 @@ class Node; class NetDevice; class VirtualNetDevice; class EpcSgwPgwApplication; +class EpcX2; /** * \brief Helper class to handle the creation of the EPC entities and protocols. @@ -81,6 +82,17 @@ public: */ void AttachUe (Ptr ueLteDevice, uint64_t imsi, Ptr enbDevice); + /** + * Add an X2 interface between two eNB + * + * \param enbNode1 one eNB peer of the X2 interface + * \param enbNode2 the other eNB peer of the X2 interface + */ + void AddX2Interface (Ptr enbNode1, Ptr enbNode2); + + void SendHandoverRequest (Ptr ueNode, Ptr sourceEnbNode, Ptr targetEnbNode); + + /** * Activate an EPS bearer, setting up the corresponding S1-U tunnel. * @@ -124,12 +136,10 @@ public: private: - - /** - * helper to assign addresses to S1-U - * NetDevices + + /** + * SGW-PGW network element */ - Ipv4AddressHelper m_s1uIpv4AddressHelper; /** * helper to assign addresses to UE devices as well as to the TUN device of the SGW/PGW @@ -139,6 +149,16 @@ private: Ptr m_sgwPgw; Ptr m_sgwPgwApp; Ptr m_tunDevice; + + + /** + * S1-U interfaces + */ + + /** + * helper to assign addresses to S1-U NetDevices + */ + Ipv4AddressHelper m_s1uIpv4AddressHelper; DataRate m_s1uLinkDataRate; Time m_s1uLinkDelay; @@ -154,6 +174,20 @@ private: * */ std::map > m_imsiEnbDeviceMap; + + /** + * helper to assign addresses to X2 NetDevices + */ + Ipv4AddressHelper m_x2Ipv4AddressHelper; + + DataRate m_x2LinkDataRate; + Time m_x2LinkDelay; + uint16_t m_x2LinkMtu; + + /** + * UDP port where the GTP-U Socket is bound, fixed by the standard as 2152 TODO Check value in the spec + */ + uint16_t m_x2cUdpPort; }; diff --git a/src/lte/helper/lte-helper.cc b/src/lte/helper/lte-helper.cc index 0d019d149..65da2a9d5 100644 --- a/src/lte/helper/lte-helper.cc +++ b/src/lte/helper/lte-helper.cc @@ -51,7 +51,7 @@ #include #include #include - +#include NS_LOG_COMPONENT_DEFINE ("LteHelper"); @@ -403,9 +403,14 @@ LteHelper::InstallSingleEnbDevice (Ptr n) Ptr enbApp = n->GetApplication (0)->GetObject (); NS_ASSERT_MSG (enbApp != 0, "cannot retrieve EpcEnbApplication"); - // EPC SAPS + // S1 SAPs rrc->SetS1SapProvider (enbApp->GetS1SapProvider ()); enbApp->SetS1SapUser (rrc->GetS1SapUser ()); + + // X2 SAPs + Ptr x2 = n->GetObject (); + x2->SetEpcX2SapUser (rrc->GetEpcX2SapUser ()); + rrc->SetEpcX2SapProvider (x2->GetEpcX2SapProvider ()); } return dev; @@ -572,6 +577,55 @@ LteHelper::ActivateDataRadioBearer (Ptr ueDevice, EpsBearer bearer) enbRrc->GetS1SapUser ()->DataRadioBearerSetupRequest (params); } +void +LteHelper::AddX2Interface (NodeContainer enbNodes) +{ + NS_LOG_FUNCTION (this); + + for (NodeContainer::Iterator i = enbNodes.Begin (); i != enbNodes.End (); ++i) + { + for (NodeContainer::Iterator j = i + 1; j != enbNodes.End (); ++j) + { + AddX2Interface (*i, *j); + } + } +} + +void +LteHelper::AddX2Interface (Ptr enbNode1, Ptr enbNode2) +{ + NS_LOG_FUNCTION (this); + NS_LOG_INFO ("setting up the X2 interface"); + + m_epcHelper->AddX2Interface (enbNode1, enbNode2); +} + +void +LteHelper::HandoverRequest (Time hoTime, Ptr ueNode, Ptr sourceEnbNode, Ptr targetEnbNode) +{ + NS_LOG_FUNCTION (this << ueNode << sourceEnbNode << targetEnbNode); + Simulator::Schedule (hoTime, &LteHelper::DoHandoverRequest, this, ueNode, sourceEnbNode, targetEnbNode); +} + +void +LteHelper::DoHandoverRequest (Ptr ueNode, Ptr sourceEnbNode, Ptr targetEnbNode) +{ + NS_LOG_FUNCTION (this << ueNode << sourceEnbNode << targetEnbNode); + + m_epcHelper->SendHandoverRequest (ueNode, sourceEnbNode, targetEnbNode); + + // lteHelper->Attach (ueNode, targetEnbNode); + // lteHelper->ActivateEpsBearer (ueNode, *); + + // lteHelper->DeactivateEpsBearer (ueNode, *); + // lteHelper->Deattach (ueNode, sourceEnbNode); + +} + + + + + void LteHelper::ActivateDataRadioBearer (NetDeviceContainer ueDevices, EpsBearer bearer) { diff --git a/src/lte/helper/lte-helper.h b/src/lte/helper/lte-helper.h index 26bc5e2d2..8560195f0 100644 --- a/src/lte/helper/lte-helper.h +++ b/src/lte/helper/lte-helper.h @@ -225,6 +225,33 @@ public: */ void ActivateDedicatedEpsBearer (Ptr ueDevice, EpsBearer bearer, Ptr tft); + + /** + * Create an X2 interface between all the eNBs in a given set + * + * \param enbNodes the set of eNB nodes + */ + void AddX2Interface (NodeContainer enbNodes); + + /** + * Create an X2 interface between two eNBs + * + * \param enbNode1 one eNB of the X2 interface + * \param enbNode2 the other eNB of the X2 interface + */ + void AddX2Interface (Ptr enbNode1, Ptr enbNode2); + + /** + * Trigger an X2-based handover of a UE between two eNBs + * + * \param hoTime when the Handover is initiated + * \param ueNode the UE that hands off + * \param enbNode1 source eNB, originally the UE is attached to this eNB + * \param enbNode2 target eNB, the UE is finally connected to this eNB + */ + void HandoverRequest (Time hoTime, Ptr ueNode, Ptr sourceEnbNode, Ptr targetEnbNode); + + /** * Activate a Data Radio Bearer for a simplified LTE-only simulation * without EPC. @@ -333,6 +360,8 @@ private: Ptr InstallSingleEnbDevice (Ptr n); Ptr InstallSingleUeDevice (Ptr n); + void DoHandoverRequest (Ptr ueNode, Ptr sourceEnbNode, Ptr targetEnbNode); + Ptr m_downlinkChannel; Ptr m_uplinkChannel; diff --git a/src/lte/model/epc-x2-header.cc b/src/lte/model/epc-x2-header.cc new file mode 100644 index 000000000..3b4e46553 --- /dev/null +++ b/src/lte/model/epc-x2-header.cc @@ -0,0 +1,305 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2012 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: Manuel Requena + */ + +#include "ns3/log.h" +// #include "ns3/packet.h" +#include "ns3/epc-x2-header.h" + +NS_LOG_COMPONENT_DEFINE ("EpcX2Header"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (EpcX2Header); + +EpcX2Header::EpcX2Header () + : m_messageType (0xfa), + m_procedureCode (0xfa) +{ +} + +EpcX2Header::~EpcX2Header () +{ + m_messageType = 0xfb; + m_procedureCode = 0xfb; +} + +TypeId +EpcX2Header::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::EpcX2Header") + .SetParent
() + .AddConstructor () + ; + return tid; +} + +TypeId +EpcX2Header::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +uint32_t +EpcX2Header::GetSerializedSize (void) const +{ + return 2; +} + +void +EpcX2Header::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + + i.WriteU8 (m_messageType); + i.WriteU8 (m_procedureCode); +} + +uint32_t +EpcX2Header::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + + m_messageType = i.ReadU8 (); + m_procedureCode = i.ReadU8 (); + + return GetSerializedSize (); +} + +void +EpcX2Header::Print (std::ostream &os) const +{ + os << "MessageType=" << (uint32_t) m_messageType; + os << " ProcedureCode=" << (uint32_t) m_procedureCode; +} + +uint8_t +EpcX2Header::GetMessageType () const +{ + return m_messageType; +} + +void +EpcX2Header::SetMessageType (uint8_t messageType) +{ + this->m_messageType = messageType; +} + +uint8_t +EpcX2Header::GetProcedureCode () const +{ + return m_procedureCode; +} + +void +EpcX2Header::SetProcedureCode (uint8_t procedureCode) +{ + this->m_procedureCode = procedureCode; +} + +///////////////////////////////////////////////////////////////////// + +NS_OBJECT_ENSURE_REGISTERED (EpcX2HandoverRequestHeader); + +EpcX2HandoverRequestHeader::EpcX2HandoverRequestHeader () + : m_oldEnbUeX2apId (0xfffa), + m_cause (0xfffa), + m_targetCellId (0xfffa) +{ +} + +EpcX2HandoverRequestHeader::~EpcX2HandoverRequestHeader () +{ + m_oldEnbUeX2apId = 0xfffb; + m_cause = 0xfffb; + m_targetCellId = 0xfffb; + m_erabsList.clear (); // TODO Clearing of a list +} + +TypeId +EpcX2HandoverRequestHeader::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::EpcX2HandoverRequestHeader") + .SetParent
() + .AddConstructor () + ; + return tid; +} + +TypeId +EpcX2HandoverRequestHeader::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +uint32_t +EpcX2HandoverRequestHeader::GetSerializedSize (void) const +{ + return 6; +} + +void +EpcX2HandoverRequestHeader::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + + i.WriteHtonU16 (m_oldEnbUeX2apId); + i.WriteHtonU16 (m_cause); + i.WriteHtonU16 (m_targetCellId); +} + +uint32_t +EpcX2HandoverRequestHeader::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + + m_oldEnbUeX2apId = i.ReadNtohU16 (); + m_cause = i.ReadNtohU16 (); + m_targetCellId = i.ReadNtohU16 (); + + return GetSerializedSize (); +} + +void +EpcX2HandoverRequestHeader::Print (std::ostream &os) const +{ + os << "Cause=" << m_cause; + os << " TargetCellId=" << m_targetCellId; +} + +uint16_t +EpcX2HandoverRequestHeader::GetCause () const +{ + return m_cause; +} + +void +EpcX2HandoverRequestHeader::SetCause (uint16_t cause) +{ + this->m_cause = cause; +} + +uint16_t +EpcX2HandoverRequestHeader::GetTargetCellId () const +{ + return m_targetCellId; +} + +void +EpcX2HandoverRequestHeader::SetTargetCellId (uint16_t targetCellId) +{ + this->m_targetCellId = targetCellId; +} + +///////////////////////////////////////////////////////////////////// + +NS_OBJECT_ENSURE_REGISTERED (EpcX2HandoverRequestAckHeader); + +EpcX2HandoverRequestAckHeader::EpcX2HandoverRequestAckHeader () + : m_oldEnbUeX2apId (0xfffa), + m_cause (0xfffa), + m_targetCellId (0xfffa) +{ +} + +EpcX2HandoverRequestAckHeader::~EpcX2HandoverRequestAckHeader () +{ + m_oldEnbUeX2apId = 0xfffb; + m_cause = 0xfffb; + m_targetCellId = 0xfffb; + m_erabsList.clear (); // TODO Clearing of a list +} + +TypeId +EpcX2HandoverRequestAckHeader::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::EpcX2HandoverRequestAckHeader") + .SetParent
() + .AddConstructor () + ; + return tid; +} + +TypeId +EpcX2HandoverRequestAckHeader::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +uint32_t +EpcX2HandoverRequestAckHeader::GetSerializedSize (void) const +{ + return 6; +} + +void +EpcX2HandoverRequestAckHeader::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + + i.WriteHtonU16 (m_oldEnbUeX2apId); + i.WriteHtonU16 (m_cause); + i.WriteHtonU16 (m_targetCellId); +} + +uint32_t +EpcX2HandoverRequestAckHeader::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + + m_oldEnbUeX2apId = i.ReadNtohU16 (); + m_cause = i.ReadNtohU16 (); + m_targetCellId = i.ReadNtohU16 (); + + return GetSerializedSize (); +} + +void +EpcX2HandoverRequestAckHeader::Print (std::ostream &os) const +{ + os << "Cause=" << m_cause; + os << " TargetCellId=" << m_targetCellId; +} + +uint16_t +EpcX2HandoverRequestAckHeader::GetCause () const +{ + return m_cause; +} + +void +EpcX2HandoverRequestAckHeader::SetCause (uint16_t cause) +{ + this->m_cause = cause; +} + +uint16_t +EpcX2HandoverRequestAckHeader::GetTargetCellId () const +{ + return m_targetCellId; +} + +void +EpcX2HandoverRequestAckHeader::SetTargetCellId (uint16_t targetCellId) +{ + this->m_targetCellId = targetCellId; +} + + +} // namespace ns3 diff --git a/src/lte/model/epc-x2-header.h b/src/lte/model/epc-x2-header.h new file mode 100644 index 000000000..84e934ceb --- /dev/null +++ b/src/lte/model/epc-x2-header.h @@ -0,0 +1,123 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2012 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: Manuel Requena + */ + +#ifndef EPC_X2_HEADER_H +#define EPC_X2_HEADER_H + +#include "ns3/header.h" + +namespace ns3 { + +class EpcX2Header : public Header +{ +public: + EpcX2Header (); + virtual ~EpcX2Header (); + + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (Buffer::Iterator start) const; + virtual uint32_t Deserialize (Buffer::Iterator start); + virtual void Print (std::ostream &os) const; + + + uint8_t GetMessageType () const; + void SetMessageType (uint8_t messageType); + + uint8_t GetProcedureCode () const; + void SetProcedureCode (uint8_t procedureCode); + + + enum ProcedureCode_t { + HANDOVER_PREPARATION_TYPE = 0 + }; + + enum TypeOfMessage_t { + INITIATING_MESSAGE = 0, + SUCCESSFUL_OUTCOME = 1, + UNSUCCESSFUL_OUTCOME = 2 + }; + +private: + uint8_t m_messageType; + uint8_t m_procedureCode; +}; + + +class EpcX2HandoverRequestHeader : public Header +{ +public: + EpcX2HandoverRequestHeader (); + virtual ~EpcX2HandoverRequestHeader (); + + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (Buffer::Iterator start) const; + virtual uint32_t Deserialize (Buffer::Iterator start); + virtual void Print (std::ostream &os) const; + + + uint16_t GetCause () const; + void SetCause (uint16_t cause); + + uint16_t GetTargetCellId () const; + void SetTargetCellId (uint16_t targetCellId); + +private: + uint16_t m_oldEnbUeX2apId; // TODO MRE When and why this is used? + uint16_t m_cause; + uint16_t m_targetCellId; + std::list m_erabsList; +}; + + +class EpcX2HandoverRequestAckHeader : public Header +{ +public: + EpcX2HandoverRequestAckHeader (); + virtual ~EpcX2HandoverRequestAckHeader (); + + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (Buffer::Iterator start) const; + virtual uint32_t Deserialize (Buffer::Iterator start); + virtual void Print (std::ostream &os) const; + + + uint16_t GetCause () const; + void SetCause (uint16_t cause); + + uint16_t GetTargetCellId () const; + void SetTargetCellId (uint16_t targetCellId); + +private: + uint16_t m_oldEnbUeX2apId; // TODO MRE When and why this is used? + uint16_t m_cause; + uint16_t m_targetCellId; + std::list m_erabsList; +}; + + +} // namespace ns3 + +#endif // EPC_X2_HEADER_H diff --git a/src/lte/model/epc-x2-sap.cc b/src/lte/model/epc-x2-sap.cc new file mode 100644 index 000000000..d8ad89615 --- /dev/null +++ b/src/lte/model/epc-x2-sap.cc @@ -0,0 +1,34 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2012 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: Manuel Requena + */ + +#include "ns3/epc-x2-sap.h" + +namespace ns3 { + + +EpcX2SapProvider::~EpcX2SapProvider () +{ +} + +EpcX2SapUser::~EpcX2SapUser () +{ +} + +} // namespace ns3 diff --git a/src/lte/model/epc-x2-sap.h b/src/lte/model/epc-x2-sap.h new file mode 100644 index 000000000..ea34cda09 --- /dev/null +++ b/src/lte/model/epc-x2-sap.h @@ -0,0 +1,211 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2012 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: Manuel Requena + */ + +#ifndef EPC_X2_SAP_H +#define EPC_X2_SAP_H + +#include "ns3/packet.h" + +namespace ns3 { + + +class Node; +class Packet; + + +class EpcX2SapProvider +{ +public: + virtual ~EpcX2SapProvider (); + + /** + * Parameters of the API primitives + */ + + struct HandoverRequestParams + { + uint16_t cause; + uint16_t sourceCellId; + uint16_t targetCellId; + std::list bearers; + Ptr rrcContext; + }; + + struct HandoverRequestAckParams + { + uint16_t cause; + uint16_t sourceCellId; + uint16_t targetCellId; + std::list bearers; + Ptr rrcContext; + }; + + /** + * SAP primitives + */ + + virtual void SendHandoverRequest (HandoverRequestParams params) = 0; + + virtual void SendHandoverRequestAck (HandoverRequestAckParams params) = 0; + +// TODO +// virtual void SendSnStatusTransfer (const struct SnStatusTransfer& params) = 0; +// +// virtual void SendUeContextRelease (const struct UeContextRelease& params) = 0; +}; + + +class EpcX2SapUser +{ +public: + virtual ~EpcX2SapUser (); + + /** + * Parameters of the API primitives + */ + + struct HandoverRequestParams + { + uint16_t cause; + uint16_t sourceCellId; + uint16_t targetCellId; + std::list bearers; + Ptr rrcContext; + }; + + struct HandoverRequestAckParams + { + uint16_t cause; + uint16_t sourceCellId; + uint16_t targetCellId; + std::list bearers; + Ptr rrcContext; + }; + + /** + * SAP primitives + */ + + virtual void RecvHandoverRequest (HandoverRequestParams params) = 0; + + virtual void RecvHandoverRequestAck (HandoverRequestAckParams params) = 0; + +// TODO +// virtual void RecvSnStatusTransfer (const struct SnStatusTransfer& params) = 0; +// +// virtual void RecvUeContextRelease (const struct UeContextRelease& params) = 0; +}; + +/////////////////////////////////////// + +template +class EpcX2SpecificEpcX2SapProvider : public EpcX2SapProvider +{ +public: + EpcX2SpecificEpcX2SapProvider (C* x2); + + // + // Interface implemented from EpcX2SapProvider + // + + virtual void SendHandoverRequest (HandoverRequestParams params); + + virtual void SendHandoverRequestAck (HandoverRequestAckParams params); + +private: + EpcX2SpecificEpcX2SapProvider (); + C* m_x2; +}; + +template +EpcX2SpecificEpcX2SapProvider::EpcX2SpecificEpcX2SapProvider (C* x2) + : m_x2 (x2) +{ +} + +template +EpcX2SpecificEpcX2SapProvider::EpcX2SpecificEpcX2SapProvider () +{ +} + +template +void +EpcX2SpecificEpcX2SapProvider::SendHandoverRequest (HandoverRequestParams params) +{ + m_x2->DoSendHandoverRequest (params); +} + +template +void +EpcX2SpecificEpcX2SapProvider::SendHandoverRequestAck (HandoverRequestAckParams params) +{ + m_x2->DoSendHandoverRequestAck (params); +} + +/////////////////////////////////////// + +template +class EpcX2SpecificEpcX2SapUser : public EpcX2SapUser +{ +public: + EpcX2SpecificEpcX2SapUser (C* rrc); + + // + // Interface implemented from EpcX2SapUser + // + + virtual void RecvHandoverRequest (HandoverRequestParams params); + + virtual void RecvHandoverRequestAck (HandoverRequestAckParams params); + +private: + EpcX2SpecificEpcX2SapUser (); + C* m_rrc; +}; + +template +EpcX2SpecificEpcX2SapUser::EpcX2SpecificEpcX2SapUser (C* rrc) + : m_rrc (rrc) +{ +} + +template +EpcX2SpecificEpcX2SapUser::EpcX2SpecificEpcX2SapUser () +{ +} + +template +void +EpcX2SpecificEpcX2SapUser::RecvHandoverRequest (HandoverRequestParams params) +{ + m_rrc->DoRecvHandoverRequest (params); +} + +template +void +EpcX2SpecificEpcX2SapUser::RecvHandoverRequestAck (HandoverRequestAckParams params) +{ + m_rrc->DoRecvHandoverRequestAck (params); +} + + +} // namespace ns3 + +#endif // EPC_X2_SAP_H diff --git a/src/lte/model/epc-x2.cc b/src/lte/model/epc-x2.cc new file mode 100644 index 000000000..43d297192 --- /dev/null +++ b/src/lte/model/epc-x2.cc @@ -0,0 +1,288 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2012 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: Manuel Requena + */ + +#include "ns3/log.h" +#include "ns3/inet-socket-address.h" +#include "ns3/packet.h" +#include "ns3/node.h" +#include "ns3/lte-enb-net-device.h" + +#include "ns3/epc-x2-header.h" +#include "ns3/epc-x2.h" + +NS_LOG_COMPONENT_DEFINE ("EpcX2"); + +namespace ns3 { + + +X2IfaceInfo::X2IfaceInfo (Ptr localSocket, Ipv4Address remoteIpAddr) +{ + m_localSocket = localSocket; + m_remoteIpAddr = remoteIpAddr; +} + +X2IfaceInfo::~X2IfaceInfo (void) +{ +} + +X2IfaceInfo& +X2IfaceInfo::operator= (const X2IfaceInfo& value) +{ + NS_LOG_FUNCTION (this); + m_localSocket = value.m_localSocket; + m_remoteIpAddr = value.m_remoteIpAddr; + return *this; +} + +/////////////////////////////////////////// + +X2CellInfo::X2CellInfo (uint16_t localCellId, uint16_t remoteCellId) +{ + m_localCellId = localCellId; + m_remoteCellId = remoteCellId; +} + +X2CellInfo::~X2CellInfo (void) +{ +} + +X2CellInfo& +X2CellInfo::operator= (const X2CellInfo& value) +{ + NS_LOG_FUNCTION (this); + m_localCellId = value.m_localCellId; + m_remoteCellId = value.m_remoteCellId; + return *this; +} + +/////////////////////////////////////////// + +NS_OBJECT_ENSURE_REGISTERED (EpcX2); + +EpcX2::EpcX2 () + : m_x2cUdpPort (4444) +{ + NS_LOG_FUNCTION (this); + + m_x2SapProvider = new EpcX2SpecificEpcX2SapProvider (this); +} + +TypeId +EpcX2::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::EpcX2") + .SetParent (); + return tid; +} + +EpcX2::~EpcX2 (void) +{ + NS_LOG_FUNCTION (this); + delete m_x2SapProvider; +} + +void +EpcX2::SetEpcX2SapUser (EpcX2SapUser * s) +{ + NS_LOG_FUNCTION (this << s); + m_x2SapUser = s; +} + +EpcX2SapProvider* +EpcX2::GetEpcX2SapProvider () +{ + NS_LOG_FUNCTION (this); + return m_x2SapProvider; +} + + +void +EpcX2::AddX2Interface (uint16_t enb1CellId, Ptr enb1X2cSocket, uint16_t enb2CellId, Ptr enb2X2cSocket) +{ + NS_LOG_FUNCTION (this << enb1CellId << enb1X2cSocket << enb2CellId << enb2X2cSocket); + + Address addr; + int retval; + + retval = enb1X2cSocket->GetSockName (addr); + NS_ASSERT (retval == 0); + InetSocketAddress localInetAddr = InetSocketAddress::ConvertFrom (addr); + NS_LOG_LOGIC ("local IP address = " << localInetAddr.GetIpv4 ()); + + retval = enb2X2cSocket->GetSockName (addr); + NS_ASSERT (retval == 0); + InetSocketAddress remoteInetAddr = InetSocketAddress::ConvertFrom (addr); + NS_LOG_LOGIC ("remote IP address = " << remoteInetAddr.GetIpv4 ()); + + enb1X2cSocket->SetRecvCallback (MakeCallback (&EpcX2::RecvFromX2cSocket, this)); + + NS_ASSERT_MSG (m_x2InterfaceSockets.find (enb2CellId) == m_x2InterfaceSockets.end (), + "Mapping for remoteCellId = " << enb2CellId << " is already known"); + m_x2InterfaceSockets [enb2CellId] = Create (enb1X2cSocket, remoteInetAddr.GetIpv4 ()); + + NS_ASSERT_MSG (m_x2InterfaceCellIds.find (enb1X2cSocket) == m_x2InterfaceCellIds.end (), + "Mapping for localSocket = " << enb1X2cSocket << " is already known"); + m_x2InterfaceCellIds [enb1X2cSocket] = Create (enb1CellId, enb2CellId); +} + + +void +EpcX2::RecvFromX2cSocket (Ptr socket) +{ + NS_LOG_FUNCTION (this << socket); + + NS_LOG_LOGIC ("Recv X2 message: from Socket"); + Ptr packet = socket->Recv (); + NS_LOG_LOGIC ("packetLen = " << packet->GetSize ()); + + EpcX2Header x2Header; + packet->RemoveHeader (x2Header); + + uint8_t messageType = x2Header.GetMessageType (); + uint8_t procedureCode = x2Header.GetProcedureCode (); + + NS_LOG_LOGIC ("messageType = " << (uint32_t)messageType); + NS_LOG_LOGIC ("procedureCode = " << (uint32_t)procedureCode); + + if (procedureCode == EpcX2Header::HANDOVER_PREPARATION_TYPE) + { + if (messageType == EpcX2Header::INITIATING_MESSAGE) + { + NS_LOG_LOGIC ("Recv X2 message: HANDOVER REQUEST"); + + EpcX2HandoverRequestHeader x2HoReqHeader; + packet->RemoveHeader (x2HoReqHeader); + + NS_ASSERT_MSG (m_x2InterfaceCellIds.find (socket) != m_x2InterfaceCellIds.end (), + "Missing infos of local and remote CellId"); + Ptr cellsInfo = m_x2InterfaceCellIds [socket]; + + EpcX2SapUser::HandoverRequestParams params; + params.cause = x2HoReqHeader.GetCause (); + params.sourceCellId = cellsInfo->m_remoteCellId; + params.targetCellId = x2HoReqHeader.GetTargetCellId (); + NS_ASSERT_MSG (params.targetCellId == cellsInfo->m_localCellId, + "TargetCellId mismatches with localCellId"); + + m_x2SapUser->RecvHandoverRequest (params); + } + else // messageType == SUCCESSFUL_OUTCOME + { + NS_LOG_LOGIC ("Recv X2 message: HANDOVER REQUEST ACK"); + + EpcX2HandoverRequestAckHeader x2HoReqAckHeader; + packet->RemoveHeader (x2HoReqAckHeader); + + NS_ASSERT_MSG (m_x2InterfaceCellIds.find (socket) != m_x2InterfaceCellIds.end (), + "Missing infos of local and remote CellId"); + Ptr cellsInfo = m_x2InterfaceCellIds [socket]; + + EpcX2SapUser::HandoverRequestAckParams params; + params.cause = x2HoReqAckHeader.GetCause (); + params.sourceCellId = cellsInfo->m_localCellId; + params.targetCellId = cellsInfo->m_remoteCellId; + + m_x2SapUser->RecvHandoverRequestAck (params); + } + } + +} + +// +// Implementation of the X2 SAP Provider +// +void +EpcX2::DoSendHandoverRequest (EpcX2SapProvider::HandoverRequestParams params) +{ + NS_LOG_FUNCTION (this); + + NS_LOG_LOGIC ("sourceCellId = " << params.sourceCellId); + NS_LOG_LOGIC ("targetCellId = " << params.targetCellId); + + NS_ASSERT_MSG (m_x2InterfaceSockets.find (params.targetCellId) != m_x2InterfaceSockets.end (), + "Missing infos for targetCellId = " << params.targetCellId); + Ptr socketInfo = m_x2InterfaceSockets [params.targetCellId]; + Ptr sourceSocket = socketInfo->m_localSocket; + Ipv4Address targetIpAddr = socketInfo->m_remoteIpAddr; + + NS_LOG_LOGIC ("sourceSocket = " << sourceSocket); + NS_LOG_LOGIC ("targetIpAddr = " << targetIpAddr); + + NS_LOG_INFO ("Send X2 message: HANDOVER REQUEST"); + + // Build the X2 message + EpcX2Header x2Header; + x2Header.SetMessageType (EpcX2Header::INITIATING_MESSAGE); + x2Header.SetProcedureCode (EpcX2Header::HANDOVER_PREPARATION_TYPE); + + EpcX2HandoverRequestHeader x2HoReqHeader; + x2HoReqHeader.SetCause (1111); + x2HoReqHeader.SetTargetCellId (params.targetCellId); + + // Build the X2 packet + Ptr packet = Create (); + packet->AddHeader (x2HoReqHeader); + packet->AddHeader (x2Header); + NS_LOG_INFO ("packetLen = " << packet->GetSize ()); + + // Send the X2 message through the socket + sourceSocket->SendTo (packet, 0, InetSocketAddress (targetIpAddr, m_x2cUdpPort)); + +} + + +void +EpcX2::DoSendHandoverRequestAck (EpcX2SapProvider::HandoverRequestAckParams params) +{ + NS_LOG_FUNCTION (this); + + NS_LOG_LOGIC ("sourceCellId = " << params.sourceCellId); + NS_LOG_LOGIC ("targetCellId = " << params.targetCellId); + + NS_ASSERT_MSG (m_x2InterfaceSockets.find (params.sourceCellId) != m_x2InterfaceSockets.end (), + "Socket infos not defined for sourceCellId = " << params.sourceCellId); + + Ptr localSocket = m_x2InterfaceSockets [params.sourceCellId]->m_localSocket; + Ipv4Address remoteIpAddr = m_x2InterfaceSockets [params.sourceCellId]->m_remoteIpAddr; + + NS_LOG_LOGIC ("localSocket = " << localSocket); + NS_LOG_LOGIC ("remoteIpAddr = " << remoteIpAddr); + + // Build the X2 message + EpcX2Header x2Header; + x2Header.SetMessageType (EpcX2Header::SUCCESSFUL_OUTCOME); + x2Header.SetProcedureCode (EpcX2Header::HANDOVER_PREPARATION_TYPE); + + EpcX2HandoverRequestAckHeader x2HoReqHeader; + x2HoReqHeader.SetCause (2222); + x2HoReqHeader.SetTargetCellId (params.targetCellId); + + // Build the X2 packet + Ptr packet = Create (); + packet->AddHeader (x2HoReqHeader); + packet->AddHeader (x2Header); + + NS_LOG_INFO ("Send X2 message: HANDOVER REQUEST ACK"); + + localSocket->SendTo (packet, 0, InetSocketAddress (remoteIpAddr, m_x2cUdpPort)); +} + + +} // namespace ns3 diff --git a/src/lte/model/epc-x2.h b/src/lte/model/epc-x2.h new file mode 100644 index 000000000..a0b04c535 --- /dev/null +++ b/src/lte/model/epc-x2.h @@ -0,0 +1,143 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2012 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: Manuel Requena + */ + +#ifndef EPC_X2_H +#define EPC_X2_H + +#include "ns3/socket.h" +#include "ns3/callback.h" +#include "ns3/ptr.h" +#include "ns3/object.h" + +#include "ns3/epc-x2-sap.h" + +namespace ns3 { + + +class X2IfaceInfo : public SimpleRefCount +{ +public: + X2IfaceInfo (Ptr localSocket, Ipv4Address remoteIpAddr); + virtual ~X2IfaceInfo (void); + + X2IfaceInfo& operator= (const X2IfaceInfo &); + +public: + Ptr m_localSocket; + Ipv4Address m_remoteIpAddr; +}; + + +class X2CellInfo : public SimpleRefCount +{ +public: + X2CellInfo (uint16_t localCellId, uint16_t remoteCellId); + virtual ~X2CellInfo (void); + + X2CellInfo& operator= (const X2CellInfo &); + +public: + uint16_t m_localCellId; + uint16_t m_remoteCellId; +}; + + +/** + * \ingroup lte + * + * This entity is installed inside an eNB and provides the functionality for the X2 interface + */ +class EpcX2 : public Object +{ + friend class EpcX2SpecificEpcX2SapProvider; + +public: + /** + * Constructor + */ + EpcX2 (); + + /** + * Destructor + */ + virtual ~EpcX2 (void); + + static TypeId GetTypeId (void); + + + /** + * \param s the X2 SAP User to be used by this EPC X2 entity + */ + void SetEpcX2SapUser (EpcX2SapUser * s); + + /** + * \param s the X2 SAP Provider interface offered by this EPC X2 entity + */ + EpcX2SapProvider* GetEpcX2SapProvider (); + + + /** + * \param s the X2 SAP Provider interface offered by this EPC X2 entity + */ + void AddX2Interface (uint16_t enb1CellId, Ptr enb1X2cSocket, uint16_t enb2CellId, Ptr enb2X2cSocket); + + + /** + * Method to be assigned to the recv callback of the X2 socket. + * It is called when the eNB receives a packet from the peer eNB of the X2 interface + * + * \param socket socket of the X2 interface + */ + void RecvFromX2cSocket (Ptr socket); + + +protected: + // Interface provided by LteRlcSapProvider + virtual void DoSendHandoverRequest (EpcX2SapProvider::HandoverRequestParams params); + virtual void DoSendHandoverRequestAck (EpcX2SapProvider::HandoverRequestAckParams params); + + EpcX2SapUser* m_x2SapUser; + EpcX2SapProvider* m_x2SapProvider; + + +private: + + /** + * Map the targetCellId to the corresponding (sourceSocket, remoteIpAddr) to be used + * to send the X2 message + */ + std::map < uint16_t, Ptr > m_x2InterfaceSockets; + + /** + * Map the localSocket (the one receiving the X2 message) + * to the corresponding (sourceCellId, targetCellId) associated with the X2 interface + */ + std::map < Ptr, Ptr > m_x2InterfaceCellIds; + + /** + * UDP port to be used for the X2 interface + */ + uint16_t m_x2cUdpPort; + +}; + +} //namespace ns3 + +#endif // EPC_X2_H diff --git a/src/lte/model/lte-enb-rrc.cc b/src/lte/model/lte-enb-rrc.cc index be64e8d13..bcec30e93 100644 --- a/src/lte/model/lte-enb-rrc.cc +++ b/src/lte/model/lte-enb-rrc.cc @@ -17,20 +17,22 @@ * * Author: Nicola Baldo * Marco Miozzo + * Manuel Requena */ -#include -#include -#include +#include "ns3/fatal-error.h" +#include "ns3/log.h" +#include "ns3/abort.h" #include "ns3/pointer.h" #include "ns3/object-map.h" #include "ns3/object-factory.h" -#include "lte-enb-rrc.h" -#include "lte-rlc.h" -#include "lte-pdcp.h" -#include "lte-pdcp-sap.h" -#include "lte-radio-bearer-info.h" +#include "ns3/lte-enb-rrc.h" +#include "ns3/lte-enb-net-device.h" +#include "ns3/lte-rlc.h" +#include "ns3/lte-pdcp.h" +#include "ns3/lte-pdcp-sap.h" +#include "ns3/lte-radio-bearer-info.h" #include "lte-radio-bearer-tag.h" #include "ff-mac-csched-sap.h" #include "epc-enb-s1-sap.h" @@ -51,9 +53,6 @@ NS_LOG_COMPONENT_DEFINE ("LteEnbRrc"); namespace ns3 { - - - // /////////////////////////// // CMAC SAP forwarder // /////////////////////////// @@ -184,7 +183,8 @@ UeInfo::RemoveRadioBearer (uint8_t lcid) NS_OBJECT_ENSURE_REGISTERED (LteEnbRrc); LteEnbRrc::LteEnbRrc () - : m_cmacSapProvider (0), + : m_x2SapProvider (0), + m_cmacSapProvider (0), m_ffMacSchedSapProvider (0), m_macSapProvider (0), m_s1SapProvider (0), @@ -195,6 +195,7 @@ LteEnbRrc::LteEnbRrc () NS_LOG_FUNCTION (this); m_cmacSapUser = new EnbRrcMemberLteEnbCmacSapUser (this); m_pdcpSapUser = new LtePdcpSpecificLtePdcpSapUser (this); + m_x2SapUser = new EpcX2SpecificEpcX2SapUser (this); m_s1SapUser = new MemberEpcEnbS1SapUser (this); m_cphySapUser = new MemberLteEnbCphySapUser (this); } @@ -212,6 +213,7 @@ LteEnbRrc::DoDispose () NS_LOG_FUNCTION (this); delete m_cmacSapUser; delete m_pdcpSapUser; + delete m_x2SapUser; delete m_s1SapUser; delete m_cphySapUser; } @@ -283,6 +285,21 @@ LteEnbRrc::GetLteEnbCphySapUser () return m_cphySapUser; } +void +LteEnbRrc::SetEpcX2SapProvider (EpcX2SapProvider * s) +{ + NS_LOG_FUNCTION (this << s); + m_x2SapProvider = s; +} + +EpcX2SapUser* +LteEnbRrc::GetEpcX2SapUser () +{ + NS_LOG_FUNCTION (this); + return m_x2SapUser; +} + + void LteEnbRrc::SetLteEnbCmacSapProvider (LteEnbCmacSapProvider * s) { @@ -525,6 +542,60 @@ LteEnbRrc::SetForwardUpCallback (Callback > cb) } +// +// User API +// +void +LteEnbRrc::SendHandoverRequest (Ptr ueNode, Ptr sourceEnbNode, Ptr targetEnbNode) +{ + NS_LOG_FUNCTION (this << ueNode << sourceEnbNode << targetEnbNode); + NS_LOG_LOGIC ("Request to send HANDOVER REQUEST"); + + EpcX2SapProvider::HandoverRequestParams params; + params.sourceCellId = sourceEnbNode->GetDevice (0)->GetObject ()->GetCellId (); + params.targetCellId = targetEnbNode->GetDevice (0)->GetObject ()->GetCellId (); + + NS_LOG_LOGIC ("sourceCellId = " << params.sourceCellId); + NS_LOG_LOGIC ("targetCellId = " << params.targetCellId); + + m_x2SapProvider->SendHandoverRequest (params); +} + + +// +// X2 User SAP +// +void +LteEnbRrc::DoRecvHandoverRequest (EpcX2SapUser::HandoverRequestParams params) +{ + NS_LOG_FUNCTION (this); + + NS_LOG_LOGIC ("Recv X2 message: HANDOVER REQUEST"); + + NS_LOG_LOGIC ("sourceCellId = " << params.sourceCellId); + NS_LOG_LOGIC ("targetCellId = " << params.targetCellId); + + NS_LOG_LOGIC ("Send X2 message: HANDOVER REQUEST ACK"); + + EpcX2SapProvider::HandoverRequestAckParams ackParams; + ackParams.sourceCellId = params.sourceCellId; + ackParams.targetCellId = params.targetCellId; + + m_x2SapProvider->SendHandoverRequestAck (ackParams); +} + +void +LteEnbRrc::DoRecvHandoverRequestAck (EpcX2SapUser::HandoverRequestAckParams params) +{ + NS_LOG_FUNCTION (this); + + NS_LOG_LOGIC ("Recv X2 message: HANDOVER REQUEST ACK"); + + NS_LOG_LOGIC ("sourceCellId = " << params.sourceCellId); + NS_LOG_LOGIC ("targetCellId = " << params.targetCellId); +} + + void LteEnbRrc::DoReceiveRrcPdu (LtePdcpSapUser::ReceiveRrcPduParameters params) { diff --git a/src/lte/model/lte-enb-rrc.h b/src/lte/model/lte-enb-rrc.h index b553446e4..1555ca678 100644 --- a/src/lte/model/lte-enb-rrc.h +++ b/src/lte/model/lte-enb-rrc.h @@ -16,16 +16,19 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Nicola Baldo + * Manuel Requena */ #ifndef LTE_ENB_RRC_H #define LTE_ENB_RRC_H -#include -#include -#include -#include -#include +#include "ns3/object.h" +#include "ns3/packet.h" +#include "ns3/lte-enb-cmac-sap.h" +#include "ns3/lte-mac-sap.h" +#include "ns3/ff-mac-sched-sap.h" +#include "ns3/lte-pdcp-sap.h" +#include "ns3/epc-x2-sap.h" #include #include @@ -33,11 +36,7 @@ namespace ns3 { -class FfMacSchedSapProvider; -class LteMacSapProvider; class LteRadioBearerInfo; -class LtePdcpSapUser; -class LtePdcpSapProvider; class EpcEnbS1SapUser; class EpcEnbS1SapProvider; class LteUeRrc; @@ -102,6 +101,7 @@ class LteEnbRrc : public Object friend class EnbRrcMemberLteEnbCmacSapUser; friend class LtePdcpSpecificLtePdcpSapUser; friend class MemberEpcEnbS1SapUser; + friend class EpcX2SpecificEpcX2SapUser; public: /** @@ -121,6 +121,19 @@ public: static TypeId GetTypeId (void); + /** + * Set the X2 SAP this RRC should interact with + * \param s the X2 SAP Provider to be used by this RRC entity + */ + void SetEpcX2SapProvider (EpcX2SapProvider* s); + + /** + * Get the X2 SAP offered by this RRC + * \return s the X2 SAP User interface offered to the X2 entity by this RRC entity + */ + EpcX2SapUser* GetEpcX2SapUser (); + + /** * set the CMAC SAP this RRC should interact with * @@ -266,6 +279,11 @@ public: */ void SetForwardUpCallback (Callback > cb); + /** + * Send a HandoverRequest through the X2 SAP interface + */ + void SendHandoverRequest (Ptr ueNode, Ptr sourceEnbNode, Ptr targetEnbNode); + /** * Identifies how EPS Bearer parameters are mapped to different RLC types * @@ -275,6 +293,8 @@ public: RLC_AM_ALWAYS = 3, PER_BASED = 4}; private: + void DoRecvHandoverRequest (EpcX2SapUser::HandoverRequestParams params); + void DoRecvHandoverRequestAck (EpcX2SapUser::HandoverRequestAckParams params); LtePdcpSapProvider* GetLtePdcpSapProvider (uint16_t rnti, uint8_t lcid); @@ -301,6 +321,9 @@ private: Callback > m_forwardUpCallback; + EpcX2SapUser* m_x2SapUser; + EpcX2SapProvider* m_x2SapProvider; + LteEnbCmacSapUser* m_cmacSapUser; LteEnbCmacSapProvider* m_cmacSapProvider; diff --git a/src/lte/model/lte-ue-net-device.cc b/src/lte/model/lte-ue-net-device.cc index 668d6b404..923a7aadc 100644 --- a/src/lte/model/lte-ue-net-device.cc +++ b/src/lte/model/lte-ue-net-device.cc @@ -31,7 +31,7 @@ #include "ns3/trace-source-accessor.h" #include "ns3/pointer.h" #include "ns3/enum.h" -#include "lte-enb-net-device.h" +#include "ns3/lte-enb-net-device.h" #include "lte-ue-net-device.h" #include "lte-ue-mac.h" #include "lte-ue-rrc.h" diff --git a/src/lte/wscript b/src/lte/wscript index e18c31c05..52185363f 100644 --- a/src/lte/wscript +++ b/src/lte/wscript @@ -63,6 +63,9 @@ def build(bld): 'model/trace-fading-loss-model.cc', 'model/epc-enb-application.cc', 'model/epc-sgw-pgw-application.cc', + 'model/epc-x2-sap.cc', + 'model/epc-x2-header.cc', + 'model/epc-x2.cc', 'model/epc-tft.cc', 'model/epc-tft-classifier.cc', 'model/lte-mi-error-model.cc', @@ -164,6 +167,9 @@ def build(bld): 'model/epc-gtpu-header.h', 'model/epc-enb-application.h', 'model/epc-sgw-pgw-application.h', + 'model/epc-x2-sap.h', + 'model/epc-x2-header.h', + 'model/epc-x2.h', 'model/epc-tft.h', 'model/epc-tft-classifier.h', 'model/lte-mi-error-model.h',