--- a/src/lte/examples/wscript Tue Jun 19 13:58:18 2012 +0200
+++ b/src/lte/examples/wscript Wed Jun 27 16:58:33 2012 +0200
@@ -34,4 +34,7 @@
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'
--- a/src/lte/helper/epc-helper.cc Tue Jun 19 13:58:18 2012 +0200
+++ b/src/lte/helper/epc-helper.cc Wed Jun 27 16:58:33 2012 +0200
@@ -32,6 +32,10 @@
#include <ns3/epc-enb-application.h>
#include <ns3/epc-sgw-pgw-application.h>
+#include <ns3/lte-enb-rrc.h>
+#include <ns3/epc-x2.h>
+#include <ns3/lte-enb-net-device.h>
+
namespace ns3 {
@@ -39,8 +43,14 @@
NS_OBJECT_ENSURE_REGISTERED (EpcHelper);
+
+// TODO For now, the X2 entities are created here statically
+// TODO std::vector< Ptr<EpcX2> > g_epcHelperEnbX2;
+
+
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 +59,8 @@
// (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 +203,96 @@
NS_ASSERT (enb->GetNApplications () == 1);
NS_ASSERT_MSG (enb->GetApplication (0)->GetObject<EpcEnbApplication> () != 0, "cannot retrieve EpcEnbApplication");
NS_LOG_LOGIC ("enb: " << enb << ", enb->GetApplication (0): " << enb->GetApplication (0));
+
+ NS_LOG_INFO ("Create EpcX2 entity");
+ Ptr<EpcX2> x2 = CreateObject<EpcX2> ();
+ NS_LOG_INFO ("Connect EpcX2 and LteEnbRrc entities");
+ Ptr<LteEnbRrc> rrc = lteEnbNetDevice->GetObject<LteEnbNetDevice> ()->GetRrc ();
+ x2->SetEpcX2SapUser (rrc->GetEpcX2SapUser ());
+ rrc->SetEpcX2SapProvider (x2->GetEpcX2SapProvider ());
+
+// TODO g_epcHelperEnbX2.push_back (x2);
+
+ enb->AggregateObject (x2);
+
+}
+
+
+void
+EpcHelper::AddX2Interface (Ptr<Node> enb1, Ptr<Node> 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<Ipv4> ()->GetNInterfaces ());
+ NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB #2 after installing p2p dev: " << enb2->GetObject<Ipv4> ()->GetNInterfaces ());
+ Ptr<NetDevice> enb1Dev = enbDevices.Get (0);
+ Ptr<NetDevice> 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<Ipv4> ()->GetNInterfaces ());
+ NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB #2 after assigning Ipv4 addr to X2 dev: " << enb2->GetObject<Ipv4> ()->GetNInterfaces ());
+
+ Ipv4Address enb1Address = enbIpIfaces.GetAddress (0);
+ Ipv4Address enb2Address = enbIpIfaces.GetAddress (1);
+
+ // Create X2-C socket for the eNB1
+ Ptr<Socket> 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<Socket> 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<EpcX2> enb1X2 = enb1->GetObject<EpcX2> ();
+// TODO Ptr<EpcX2> enb1X2 = g_epcHelperEnbX2[0];
+ Ptr<LteEnbNetDevice> enb1LteDev = enb1->GetDevice (0)->GetObject<LteEnbNetDevice> ();
+ uint16_t enb1CellId = enb1LteDev->GetCellId ();
+ NS_LOG_LOGIC ("LteEnbNetDevice #1 = " << enb1LteDev << " - CellId = " << enb1CellId);
+
+ // Add X2 interface to the eNB2's X2 entity
+ Ptr<EpcX2> enb2X2 = enb2->GetObject<EpcX2> ();
+// TODO Ptr<EpcX2> enb2X2 = g_epcHelperEnbX2[1];
+ Ptr<LteEnbNetDevice> enb2LteDev = enb2->GetDevice (0)->GetObject<LteEnbNetDevice> ();
+ 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);
+
+
+ // TODO To remove
+// EpcX2NodePeers x2NodePeers (enb1, enb2);
+// EpcX2ApplicationPairs x2ApplicationPairs (enb1X2, enb2X2);
+// m_x2Interfaces [x2NodePeers] = x2ApplicationPairs;
+}
+
+
+void
+EpcHelper::SendHandoverRequest (Ptr<Node> ueNode, Ptr<Node> sourceEnbNode, Ptr<Node> targetEnbNode)
+{
+ NS_LOG_FUNCTION (this << ueNode << sourceEnbNode << targetEnbNode);
+
+ Ptr<LteEnbRrc> sourceRrc = sourceEnbNode->GetDevice (0)->GetObject<LteEnbNetDevice> ()->GetRrc ();
+
+ sourceRrc->SendHandoverRequest (ueNode, sourceEnbNode, targetEnbNode);
}
@@ -260,4 +361,56 @@
}
+
+EpcHelper::EpcX2NodePeers::EpcX2NodePeers (Ptr<Node> enbPeer1, Ptr<Node> enbPeer2)
+{
+ NS_LOG_FUNCTION (this);
+ m_enbPeer1 = enbPeer1;
+ m_enbPeer2 = enbPeer2;
+}
+
+EpcHelper::EpcX2NodePeers::~EpcX2NodePeers ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+bool
+EpcHelper::EpcX2NodePeers::operator< (const EpcX2NodePeers& value) const
+{
+ NS_LOG_FUNCTION (this);
+ return ((m_enbPeer1 < value.m_enbPeer1) &&
+ (m_enbPeer2 < value.m_enbPeer2));
+}
+
+
+EpcHelper::EpcX2ApplicationPairs::EpcX2ApplicationPairs ()
+{
+ NS_LOG_FUNCTION (this);
+ m_x2AppPair1 = 0;
+ m_x2AppPair2 = 0;
+}
+
+EpcHelper::EpcX2ApplicationPairs::EpcX2ApplicationPairs (Ptr<EpcX2> x2AppPair1, Ptr<EpcX2> x2AppPair2)
+{
+ NS_LOG_FUNCTION (this);
+
+ m_x2AppPair1 = x2AppPair1;
+ m_x2AppPair2 = x2AppPair2;
+}
+
+EpcHelper::EpcX2ApplicationPairs::~EpcX2ApplicationPairs ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+EpcHelper::EpcX2ApplicationPairs&
+EpcHelper::EpcX2ApplicationPairs::operator= (const EpcX2ApplicationPairs& value)
+{
+ NS_LOG_FUNCTION (this);
+ m_x2AppPair1 = value.m_x2AppPair1;
+ m_x2AppPair2 = value.m_x2AppPair2;
+ return *this;
+}
+
+
} // namespace ns3
--- a/src/lte/helper/epc-helper.h Tue Jun 19 13:58:18 2012 +0200
+++ b/src/lte/helper/epc-helper.h Wed Jun 27 16:58:33 2012 +0200
@@ -34,6 +34,7 @@
class NetDevice;
class VirtualNetDevice;
class EpcSgwPgwApplication;
+class EpcX2;
/**
* \brief Helper class to handle the creation of the EPC entities and protocols.
@@ -73,6 +74,17 @@
/**
+ * 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<Node> enbNode1, Ptr<Node> enbNode2);
+
+ void SendHandoverRequest (Ptr<Node> ueNode, Ptr<Node> sourceEnbNode, Ptr<Node> targetEnbNode);
+
+
+ /**
* Activate an EPS bearer, setting up the corresponding S1-U tunnel.
*
*
@@ -115,12 +127,10 @@
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
@@ -130,17 +140,78 @@
Ptr<Node> m_sgwPgw;
Ptr<EpcSgwPgwApplication> m_sgwPgwApp;
Ptr<VirtualNetDevice> m_tunDevice;
+
+
+ /**
+ * S1-U interfaces
+ */
+
+ /**
+ * helper to assign addresses to S1-U NetDevices
+ */
+ Ipv4AddressHelper m_s1uIpv4AddressHelper;
DataRate m_s1uLinkDataRate;
Time m_s1uLinkDelay;
uint16_t m_s1uLinkMtu;
-
/**
* UDP port where the GTP-U Socket is bound, fixed by the standard as 2152
*/
uint16_t m_gtpuUdpPort;
+
+ /**
+ * X2 interfaces
+ * TODO To separate between X2-U interfaces and X2-C interfaces
+ */
+
+ /**
+ * 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;
+
+
+ /**
+ * X2 Applications
+ */
+ class EpcX2NodePeers : public SimpleRefCount<EpcX2NodePeers>
+ {
+ public:
+ EpcX2NodePeers (Ptr<Node> enbPeer1, Ptr<Node> enbPeer2);
+ virtual ~EpcX2NodePeers (void);
+
+ bool operator< (const EpcX2NodePeers &) const;
+
+ Ptr<Node> m_enbPeer1;
+ Ptr<Node> m_enbPeer2;
+ };
+
+ class EpcX2ApplicationPairs : public SimpleRefCount<EpcX2ApplicationPairs>
+ {
+ public:
+ EpcX2ApplicationPairs ();
+ EpcX2ApplicationPairs (Ptr<EpcX2> m_x2AppPair1, Ptr<EpcX2> m_x2AppPair2);
+ virtual ~EpcX2ApplicationPairs (void);
+
+ EpcX2ApplicationPairs& operator= (const EpcX2ApplicationPairs &);
+
+ Ptr<EpcX2> m_x2AppPair1;
+ Ptr<EpcX2> m_x2AppPair2;
+ };
+
+ std::map < EpcX2NodePeers, EpcX2ApplicationPairs > m_x2Interfaces;
+
};
--- a/src/lte/helper/lte-helper.cc Tue Jun 19 13:58:18 2012 +0200
+++ b/src/lte/helper/lte-helper.cc Wed Jun 27 16:58:33 2012 +0200
@@ -570,6 +570,54 @@
}
}
+
+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<Node> enbNode1, Ptr<Node> enbNode2)
+{
+ NS_LOG_FUNCTION (this);
+ NS_LOG_INFO ("setting up the X2 interface");
+
+ m_epcHelper->AddX2Interface (enbNode1, enbNode2);
+}
+
+void
+LteHelper::HandoverRequest (Time hoTime, Ptr<Node> ueNode, Ptr<Node> sourceEnbNode, Ptr<Node> targetEnbNode)
+{
+ NS_LOG_FUNCTION (this << ueNode << sourceEnbNode << targetEnbNode);
+ Simulator::Schedule (hoTime, &LteHelper::DoHandoverRequest, this, ueNode, sourceEnbNode, targetEnbNode);
+}
+
+void
+LteHelper::DoHandoverRequest (Ptr<Node> ueNode, Ptr<Node> sourceEnbNode, Ptr<Node> 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);
+
+}
+
+
+
TypeId
LteHelper::GetRlcType (EpsBearer bearer)
{
--- a/src/lte/helper/lte-helper.h Tue Jun 19 13:58:18 2012 +0200
+++ b/src/lte/helper/lte-helper.h Wed Jun 27 16:58:33 2012 +0200
@@ -219,6 +219,33 @@
*/
void ActivateEpsBearer (Ptr<NetDevice> ueDevice, EpsBearer bearer, Ptr<EpcTft> 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<Node> enbNode1, Ptr<Node> 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<Node> ueNode, Ptr<Node> sourceEnbNode, Ptr<Node> targetEnbNode);
+
+
/**
*
* \param bearer the specification of an EPS bearer
@@ -320,6 +347,8 @@
Ptr<NetDevice> InstallSingleEnbDevice (Ptr<Node> n);
Ptr<NetDevice> InstallSingleUeDevice (Ptr<Node> n);
+ void DoHandoverRequest (Ptr<Node> ueNode, Ptr<Node> sourceEnbNode, Ptr<Node> targetEnbNode);
+
Ptr<SpectrumChannel> m_downlinkChannel;
Ptr<SpectrumChannel> m_uplinkChannel;