diff --git a/src/lte/examples/lena-x2-handover.cc b/src/lte/examples/lena-x2-handover.cc new file mode 100644 index 000000000..cf999912a --- /dev/null +++ b/src/lte/examples/lena-x2-handover.cc @@ -0,0 +1,158 @@ +/* -*- 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); + + // Attach all UEs to the first eNodeB + for (uint16_t i = 0; i < numberOfUes; i++) + { + lteHelper->Attach (ueLteDevs.Get(i), enbLteDevs.Get(0)); + } + + // 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); + } + + // Activate an EPS Bearer (including Radio Bearer) between UEs and its eNB + lteHelper->ActivateEpsBearer (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/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.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/wscript b/src/lte/wscript index 1cdc6bb19..88f05e770 100644 --- a/src/lte/wscript +++ b/src/lte/wscript @@ -61,6 +61,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' @@ -157,6 +160,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',