Merge branch 'backhaul-update' into 'master'
lte: New customizable backhaul See merge request nsnam/ns-3-dev!68
This commit is contained in:
@@ -4299,6 +4299,9 @@ sequence diagram of Distributed Fractional Frequency Reuse Scheme.
|
||||
|
||||
\clearpage
|
||||
|
||||
|
||||
.. _sec-carrier-aggregation:
|
||||
|
||||
--------------------
|
||||
Carrier Aggregation
|
||||
--------------------
|
||||
@@ -4703,7 +4706,6 @@ Helpers
|
||||
Two helper objects are used to setup simulations and configure the
|
||||
various components. These objects are:
|
||||
|
||||
|
||||
* ``LteHelper``, which takes care of the configuration of the LTE radio access network,
|
||||
as well as of coordinating the setup and release of EPS bearers. The ``LteHelper`` class
|
||||
provides both the API definition and its implementation.
|
||||
@@ -4711,6 +4713,9 @@ various components. These objects are:
|
||||
``EpcHelper`` class is an abstract base class, which only provides the API definition;
|
||||
the implementation is delegated to the child classes in order to allow for different
|
||||
EPC network models.
|
||||
|
||||
A third helper object is used to configure the :ref:`_sec-carrier-aggregation` functionality:
|
||||
|
||||
* ``CcHelper``, which takes care of the configuration of the ``LteEnbComponentCarrierMap``,
|
||||
basically, it creates a user specified number of ``LteEnbComponentCarrier``.
|
||||
``LteUeComponentCarrierMap`` is currently created starting from the
|
||||
|
||||
@@ -178,13 +178,17 @@ Supposing your simulation program is called
|
||||
``src/lte/examples/lte-sim-with-input``, you can now pass these
|
||||
settings to the simulation program in the following way::
|
||||
|
||||
./waf --command-template="%s --ns3::ConfigStore::Filename=input-defaults.txt --ns3::ConfigStore::Mode=Load --ns3::ConfigStore::FileFormat=RawText" --run src/lte/examples/lte-sim-with-input
|
||||
./waf --command-template="%s --ns3::ConfigStore::Filename=input-defaults.txt
|
||||
--ns3::ConfigStore::Mode=Load --ns3::ConfigStore::FileFormat=RawText"
|
||||
--run src/lte/examples/lte-sim-with-input
|
||||
|
||||
|
||||
Furthermore, you can generate a template input file with the following
|
||||
command::
|
||||
|
||||
./waf --command-template="%s --ns3::ConfigStore::Filename=input-defaults.txt --ns3::ConfigStore::Mode=Save --ns3::ConfigStore::FileFormat=RawText" --run src/lte/examples/lte-sim-with-input
|
||||
./waf --command-template="%s --ns3::ConfigStore::Filename=input-defaults.txt
|
||||
--ns3::ConfigStore::Mode=Save --ns3::ConfigStore::FileFormat=RawText"
|
||||
--run src/lte/examples/lte-sim-with-input
|
||||
|
||||
note that the above will put in the file ``input-defaults.txt`` *all*
|
||||
the default values that are registered in your particular build of the
|
||||
@@ -830,7 +834,7 @@ to the PGW via a point-to-point link::
|
||||
|
||||
Ptr<Node> pgw = epcHelper->GetPgwNode ();
|
||||
|
||||
// Create a single RemoteHost
|
||||
// Create a single RemoteHost
|
||||
NodeContainer remoteHostContainer;
|
||||
remoteHostContainer.Create (1);
|
||||
Ptr<Node> remoteHost = remoteHostContainer.Get (0);
|
||||
@@ -841,8 +845,8 @@ to the PGW via a point-to-point link::
|
||||
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);
|
||||
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);
|
||||
@@ -851,8 +855,10 @@ to the PGW via a point-to-point link::
|
||||
|
||||
|
||||
Ipv4StaticRoutingHelper ipv4RoutingHelper;
|
||||
Ptr<Ipv4StaticRouting> remoteHostStaticRouting = ipv4RoutingHelper.GetStaticRouting (remoteHost->GetObject<Ipv4> ());
|
||||
remoteHostStaticRouting->AddNetworkRouteTo (epcHelper->GetEpcIpv4NetworkAddress (), Ipv4Mask ("255.255.0.0"), 1);
|
||||
Ptr<Ipv4StaticRouting> remoteHostStaticRouting;
|
||||
remoteHostStaticRouting = ipv4RoutingHelper.GetStaticRouting (remoteHost->GetObject<Ipv4> ());
|
||||
remoteHostStaticRouting->AddNetworkRouteTo (epcHelper->GetEpcIpv4NetworkAddress (),
|
||||
Ipv4Mask ("255.255.0.0"), 1);
|
||||
|
||||
Now, you should go on and create LTE eNBs and UEs as explained in the
|
||||
previous sections. You can of course configure other LTE aspects such
|
||||
@@ -860,52 +866,55 @@ as pathloss and fading models. Right after you created the UEs, you
|
||||
should also configure them for IP networking. This is done as
|
||||
follows. We assume you have a container for UE and eNodeB nodes like this::
|
||||
|
||||
NodeContainer ueNodes;
|
||||
NodeContainer enbNodes;
|
||||
|
||||
NodeContainer ueNodes;
|
||||
NodeContainer enbNodes;
|
||||
|
||||
to configure an LTE-only simulation, you would then normally do
|
||||
something like this::
|
||||
|
||||
NetDeviceContainer ueLteDevs = lteHelper->InstallUeDevice (ueNodes);
|
||||
lteHelper->Attach (ueLteDevs, enbLteDevs.Get (0));
|
||||
NetDeviceContainer ueLteDevs = lteHelper->InstallUeDevice (ueNodes);
|
||||
lteHelper->Attach (ueLteDevs, enbLteDevs.Get (0));
|
||||
|
||||
in order to configure the UEs for IP networking, you just need to
|
||||
additionally do like this::
|
||||
|
||||
// we install the IP stack on the UEs
|
||||
InternetStackHelper internet;
|
||||
internet.Install (ueNodes);
|
||||
// we install the IP stack on the UEs
|
||||
InternetStackHelper internet;
|
||||
internet.Install (ueNodes);
|
||||
|
||||
// assign IP address to UEs
|
||||
for (uint32_t u = 0; u < ueNodes.GetN (); ++u)
|
||||
{
|
||||
Ptr<Node> ue = ueNodes.Get (u);
|
||||
Ptr<NetDevice> ueLteDevice = ueLteDevs.Get (u);
|
||||
Ipv4InterfaceContainer ueIpIface = epcHelper->AssignUeIpv4Address (NetDeviceContainer (ueLteDevice));
|
||||
// set the default gateway for the UE
|
||||
Ptr<Ipv4StaticRouting> ueStaticRouting = ipv4RoutingHelper.GetStaticRouting (ue->GetObject<Ipv4> ());
|
||||
ueStaticRouting->SetDefaultRoute (epcHelper->GetUeDefaultGatewayAddress (), 1);
|
||||
}
|
||||
// assign IP address to UEs
|
||||
for (uint32_t u = 0; u < ueNodes.GetN (); ++u)
|
||||
{
|
||||
Ptr<Node> ue = ueNodes.Get (u);
|
||||
Ptr<NetDevice> ueLteDevice = ueLteDevs.Get (u);
|
||||
Ipv4InterfaceContainer ueIpIface;
|
||||
ueIpIface = epcHelper->AssignUeIpv4Address (NetDeviceContainer (ueLteDevice));
|
||||
// set the default gateway for the UE
|
||||
Ptr<Ipv4StaticRouting> ueStaticRouting;
|
||||
ueStaticRouting = ipv4RoutingHelper.GetStaticRouting (ue->GetObject<Ipv4> ());
|
||||
ueStaticRouting->SetDefaultRoute (epcHelper->GetUeDefaultGatewayAddress (), 1);
|
||||
}
|
||||
|
||||
The activation of bearers is done in a slightly different way with
|
||||
respect to what done for an LTE-only simulation. First, the method
|
||||
ActivateDataRadioBearer is not to be used when the EPC is
|
||||
used. Second, when EPC is used, the default EPS bearer will be
|
||||
activated automatically when you call LteHelper::Attach (). Third, if
|
||||
activated automatically when you call ``LteHelper::Attach ()``. Third, if
|
||||
you want to setup dedicated EPS bearer, you can do so using the method
|
||||
LteHelper::ActivateDedicatedEpsBearer (). This method takes as a
|
||||
``LteHelper::ActivateDedicatedEpsBearer ()``. This method takes as a
|
||||
parameter the Traffic Flow Template (TFT), which is a struct that
|
||||
identifies the type of traffic that will be mapped to the dedicated
|
||||
EPS bearer. Here is an example for how to setup a dedicated bearer
|
||||
for an application at the UE communicating on port 1234::
|
||||
|
||||
Ptr<EpcTft> tft = Create<EpcTft> ();
|
||||
EpcTft::PacketFilter pf;
|
||||
pf.localPortStart = 1234;
|
||||
pf.localPortEnd = 1234;
|
||||
tft->Add (pf);
|
||||
lteHelper->ActivateDedicatedEpsBearer (ueLteDevs, EpsBearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT), tft);
|
||||
Ptr<EpcTft> tft = Create<EpcTft> ();
|
||||
EpcTft::PacketFilter pf;
|
||||
pf.localPortStart = 1234;
|
||||
pf.localPortEnd = 1234;
|
||||
tft->Add (pf);
|
||||
lteHelper->ActivateDedicatedEpsBearer (ueLteDevs,
|
||||
EpsBearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT),
|
||||
tft);
|
||||
|
||||
you can of course use custom EpsBearer and EpcTft configurations,
|
||||
please refer to the doxygen documentation for how to do it.
|
||||
@@ -918,18 +927,18 @@ remoteHost, here is how to setup downlink communication, with an
|
||||
UdpClient application on the remote host, and a PacketSink on the LTE UE
|
||||
(using the same variable names of the previous code snippets) ::
|
||||
|
||||
uint16_t dlPort = 1234;
|
||||
PacketSinkHelper packetSinkHelper ("ns3::UdpSocketFactory",
|
||||
InetSocketAddress (Ipv4Address::GetAny (), dlPort));
|
||||
ApplicationContainer serverApps = packetSinkHelper.Install (ue);
|
||||
serverApps.Start (Seconds (0.01));
|
||||
UdpClientHelper client (ueIpIface.GetAddress (0), dlPort);
|
||||
ApplicationContainer clientApps = client.Install (remoteHost);
|
||||
clientApps.Start (Seconds (0.01));
|
||||
uint16_t dlPort = 1234;
|
||||
PacketSinkHelper packetSinkHelper ("ns3::UdpSocketFactory",
|
||||
InetSocketAddress (Ipv4Address::GetAny (), dlPort));
|
||||
ApplicationContainer serverApps = packetSinkHelper.Install (ue);
|
||||
serverApps.Start (Seconds (0.01));
|
||||
UdpClientHelper client (ueIpIface.GetAddress (0), dlPort);
|
||||
ApplicationContainer clientApps = client.Install (remoteHost);
|
||||
clientApps.Start (Seconds (0.01));
|
||||
|
||||
That's all! You can now start your simulation as usual::
|
||||
|
||||
Simulator::Stop (Seconds (10.0));
|
||||
Simulator::Stop (Seconds (10.0));
|
||||
Simulator::Run ();
|
||||
|
||||
|
||||
@@ -951,8 +960,8 @@ First of all we build ns-3 appropriately::
|
||||
|
||||
# configure
|
||||
./waf configure --enable-sudo --enable-modules=lte,fd-net-device --enable-examples
|
||||
|
||||
# build
|
||||
|
||||
# build
|
||||
./waf
|
||||
|
||||
|
||||
@@ -960,26 +969,27 @@ Then we setup two virtual ethernet interfaces, and start wireshark to look at th
|
||||
|
||||
|
||||
# note: you need to be root
|
||||
|
||||
|
||||
# create two paired veth devices
|
||||
ip link add name veth0 type veth peer name veth1
|
||||
ip link show
|
||||
|
||||
|
||||
# enable promiscuous mode
|
||||
ip link set veth0 promisc on
|
||||
ip link set veth1 promisc on
|
||||
|
||||
|
||||
# bring interfaces up
|
||||
ip link set veth0 up
|
||||
ip link set veth1 up
|
||||
|
||||
|
||||
# start wireshark and capture on veth0
|
||||
wireshark &
|
||||
|
||||
|
||||
|
||||
We can now run the example program with the simulated clock::
|
||||
|
||||
./waf --run lena-simple-epc-emu --command="%s --ns3::EmuEpcHelper::sgwDeviceName=veth0 --ns3::EmuEpcHelper::enbDeviceName=veth1"
|
||||
./waf --run lena-simple-epc-emu --command="%s --ns3::EmuEpcHelper::sgwDeviceName=veth0
|
||||
--ns3::EmuEpcHelper::enbDeviceName=veth1"
|
||||
|
||||
|
||||
Using wireshark, you should see ARP resolution first, then some GTP
|
||||
@@ -987,7 +997,8 @@ packets exchanged both in uplink and downlink.
|
||||
|
||||
The default setting of the example program is 1 eNB and 1UE. You can change this via command line parameters, e.g.::
|
||||
|
||||
./waf --run lena-simple-epc-emu --command="%s --ns3::EmuEpcHelper::sgwDeviceName=veth0 --ns3::EmuEpcHelper::enbDeviceName=veth1 --nEnbs=2 --nUesPerEnb=2"
|
||||
./waf --run lena-simple-epc-emu --command="%s --ns3::EmuEpcHelper::sgwDeviceName=veth0
|
||||
--ns3::EmuEpcHelper::enbDeviceName=veth1 --nEnbs=2 --nUesPerEnb=2"
|
||||
|
||||
|
||||
To get a list of the available parameters::
|
||||
@@ -1003,12 +1014,16 @@ with the BestEffort mode is not a good idea: something can go wrong
|
||||
So you need a decent hardware and the optimized build with statically
|
||||
linked modules::
|
||||
|
||||
./waf configure -d optimized --enable-static --enable-modules=lte --enable-examples --enable-sudo
|
||||
./waf configure -d optimized --enable-static --enable-modules=lte --enable-examples
|
||||
--enable-sudo
|
||||
|
||||
|
||||
Then run the example program like this::
|
||||
|
||||
./waf --run lena-simple-epc-emu --command="%s --ns3::EmuEpcHelper::sgwDeviceName=veth0 --ns3::EmuEpcHelper::enbDeviceName=veth1 --simulatorImplementationType=ns3::RealtimeSimulatorImpl --ns3::RealtimeSimulatorImpl::SynchronizationMode=HardLimit"
|
||||
./waf --run lena-simple-epc-emu --command="%s --ns3::EmuEpcHelper::sgwDeviceName=veth0
|
||||
--ns3::EmuEpcHelper::enbDeviceName=veth1
|
||||
--SimulatorImplementationType=ns3::RealtimeSimulatorImpl
|
||||
--ns3::RealtimeSimulatorImpl::SynchronizationMode=HardLimit"
|
||||
|
||||
|
||||
note the HardLimit setting, which will cause the program to terminate
|
||||
@@ -1021,6 +1036,111 @@ transport network.
|
||||
|
||||
|
||||
|
||||
.. _sec-custom-backhaul:
|
||||
|
||||
Custom Backhaul
|
||||
---------------
|
||||
|
||||
In the previous sections, :ref:`sec-evolved-packet-core`, we explained how to write a simulation
|
||||
program using EPC with a predefined backhaul network between the RAN and the EPC. We used the
|
||||
``PointToPointEpcHelper``. This ``EpcHelper`` creates point-to-point links between the eNBs and the SGW.
|
||||
|
||||
We now explain how to write a simulation program that allows the simulator user to create any kind
|
||||
of backhaul network in the simulation program.
|
||||
|
||||
First of all, in addition to ``LteHelper``, you need to use the ``NoBackhaulEpcHelper`` class, which
|
||||
implements an EPC but without connecting the eNBs with the core network. It just creates the network
|
||||
elements of the core network::
|
||||
|
||||
Ptr<LteHelper> lteHelper = CreateObject<LteHelper> ();
|
||||
Ptr<NoBackhaulEpcHelper> epcHelper = CreateObject<NoBackhaulEpcHelper> ();
|
||||
|
||||
|
||||
Then, as usual, you need to tell the LTE helper that the EPC will be used::
|
||||
|
||||
lteHelper->SetEpcHelper (epcHelper);
|
||||
|
||||
|
||||
Now, you should create the backhaul network. Here we create point-to-point links as it is done
|
||||
by the ``PointToPointEpcHelper``. We assume you have a container for eNB nodes like this::
|
||||
|
||||
NodeContainer enbNodes;
|
||||
|
||||
We get the SGW node::
|
||||
|
||||
Ptr<Node> sgw = epcHelper->GetSgwNode ();
|
||||
|
||||
And we connect every eNB from the container with the SGW with a point-to-point link. We also assign
|
||||
IPv4 addresses to the interfaces of eNB and SGW with ``s1uIpv4AddressHelper.Assign (sgwEnbDevices)``
|
||||
and finally we tell the EpcHelper that this ``enb`` has a new S1 interface with
|
||||
``epcHelper->AddS1Interface (enb, enbS1uAddress, sgwS1uAddress)``, where ``enbS1uAddress`` and
|
||||
``sgwS1uAddress`` are the IPv4 addresses of the eNB and the SGW, respectively::
|
||||
|
||||
Ipv4AddressHelper s1uIpv4AddressHelper;
|
||||
|
||||
// Create networks of the S1 interfaces
|
||||
s1uIpv4AddressHelper.SetBase ("10.0.0.0", "255.255.255.252");
|
||||
|
||||
for (uint16_t i = 0; i < enbNodes.GetN (); ++i)
|
||||
{
|
||||
Ptr<Node> enb = enbNodes.Get (i);
|
||||
|
||||
// Create a point to point link between the eNB and the SGW with
|
||||
// the corresponding new NetDevices on each side
|
||||
PointToPointHelper p2ph;
|
||||
DataRate s1uLinkDataRate = DataRate ("10Gb/s");
|
||||
uint16_t s1uLinkMtu = 2000;
|
||||
Time s1uLinkDelay = Time (0);
|
||||
p2ph.SetDeviceAttribute ("DataRate", DataRateValue (s1uLinkDataRate));
|
||||
p2ph.SetDeviceAttribute ("Mtu", UintegerValue (s1uLinkMtu));
|
||||
p2ph.SetChannelAttribute ("Delay", TimeValue (s1uLinkDelay));
|
||||
NetDeviceContainer sgwEnbDevices = p2ph.Install (sgw, enb);
|
||||
|
||||
Ipv4InterfaceContainer sgwEnbIpIfaces = s1uIpv4AddressHelper.Assign (sgwEnbDevices);
|
||||
s1uIpv4AddressHelper.NewNetwork ();
|
||||
|
||||
Ipv4Address sgwS1uAddress = sgwEnbIpIfaces.GetAddress (0);
|
||||
Ipv4Address enbS1uAddress = sgwEnbIpIfaces.GetAddress (1);
|
||||
|
||||
// Create S1 interface between the SGW and the eNB
|
||||
epcHelper->AddS1Interface (enb, enbS1uAddress, sgwS1uAddress);
|
||||
}
|
||||
|
||||
This is just an example how to create a custom backhaul network. In this other example, we connect
|
||||
all eNBs and the SGW to the same CSMA network::
|
||||
|
||||
// Create networks of the S1 interfaces
|
||||
s1uIpv4AddressHelper.SetBase ("10.0.0.0", "255.255.255.0");
|
||||
|
||||
NodeContainer sgwEnbNodes;
|
||||
sgwEnbNodes.Add (sgw);
|
||||
sgwEnbNodes.Add (enbNodes);
|
||||
|
||||
CsmaHelper csmah;
|
||||
NetDeviceContainer sgwEnbDevices = csmah.Install (sgwEnbNodes);
|
||||
Ptr<NetDevice> sgwDev = sgwEnbDevices.Get (0);
|
||||
|
||||
Ipv4InterfaceContainer sgwEnbIpIfaces = s1uIpv4AddressHelper.Assign (sgwEnbDevices);
|
||||
Ipv4Address sgwS1uAddress = sgwEnbIpIfaces.GetAddress (0);
|
||||
|
||||
for (uint16_t i = 0; i < enbNodes.GetN (); ++i)
|
||||
{
|
||||
Ptr<Node> enb = enbNodes.Get (i);
|
||||
Ipv4Address enbS1uAddress = sgwEnbIpIfaces.GetAddress (i + 1);
|
||||
|
||||
// Create S1 interface between the SGW and the eNB
|
||||
epcHelper->AddS1Interface (enb, enbS1uAddress, sgwS1uAddress);
|
||||
}
|
||||
|
||||
As you can see, apart from how you create the backhaul network, i.e. the point-to-point links or
|
||||
the CSMA network, the important point is to tell the ``EpcHelper`` that an ``eNB`` has a new S1 interface.
|
||||
|
||||
Now, you should continue configuring your simulation program as it is explained in
|
||||
:ref:`sec-evolved-packet-core` subsection. This configuration includes: the internet, installing the LTE eNBs
|
||||
and possibly configuring other LTE aspects, installing the LTE UEs and configuring them as IP nodes,
|
||||
activation of the dedicated EPS bearers and installing applications on the LTE UEs and on the remote hosts.
|
||||
|
||||
|
||||
|
||||
.. _sec-network-attachment:
|
||||
|
||||
|
||||
248
src/lte/examples/lena-simple-epc-backhaul.cc
Normal file
248
src/lte/examples/lena-simple-epc-backhaul.cc
Normal file
@@ -0,0 +1,248 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2019 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
|
||||
*
|
||||
* Authors: Manuel Requena <manuel.requena@cttc.es>
|
||||
*/
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/network-module.h"
|
||||
#include "ns3/point-to-point-module.h"
|
||||
#include "ns3/internet-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/mobility-module.h"
|
||||
#include "ns3/config-store-module.h"
|
||||
#include "ns3/lte-module.h"
|
||||
// #include "ns3/gtk-config-store.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
/**
|
||||
* Sample simulation script for LTE+EPC with different backhauls.
|
||||
*
|
||||
* The purpose of this example is to compare:
|
||||
*
|
||||
* (1) how the simulation user can use a pre-existing EpcHelper that builds
|
||||
* a predefined backhaul network (e.g. the PointToPointEpcHelper) and
|
||||
*
|
||||
* (2) how the simulation user can build its custom backhaul network in
|
||||
* the simulation program (i.e. the point-to-point links are created
|
||||
* in the simulation program instead of the pre-existing PointToPointEpcHelper)
|
||||
*
|
||||
* The pre-existing PointToPointEpcHelper is used with option --useHelper=1 and
|
||||
* the custom backhaul is built with option --useHelper=0
|
||||
*/
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("LenaSimpleEpcBackhaul");
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
uint16_t numNodePairs = 2;
|
||||
Time simTime = MilliSeconds (1900);
|
||||
double distance = 60.0;
|
||||
Time interPacketInterval = MilliSeconds (100);
|
||||
bool disableDl = false;
|
||||
bool disableUl = false;
|
||||
bool useHelper = false;
|
||||
|
||||
// Command line arguments
|
||||
CommandLine cmd;
|
||||
cmd.AddValue ("numNodePairs", "Number of eNodeBs + UE pairs", numNodePairs);
|
||||
cmd.AddValue ("simTime", "Total duration of the simulation", simTime);
|
||||
cmd.AddValue ("distance", "Distance between eNBs [m]", distance);
|
||||
cmd.AddValue ("interPacketInterval", "Inter packet interval", interPacketInterval);
|
||||
cmd.AddValue ("disableDl", "Disable downlink data flows", disableDl);
|
||||
cmd.AddValue ("disableUl", "Disable uplink data flows", disableUl);
|
||||
cmd.AddValue ("useHelper", "Build the backhaul network using the helper or "
|
||||
"it is built in the example", useHelper);
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
ConfigStore inputConfig;
|
||||
inputConfig.ConfigureDefaults ();
|
||||
|
||||
// parse again so you can override default values from the command line
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
Ptr<LteHelper> lteHelper = CreateObject<LteHelper> ();
|
||||
Ptr<EpcHelper> epcHelper;
|
||||
if (!useHelper)
|
||||
{
|
||||
epcHelper = CreateObject<NoBackhaulEpcHelper> ();
|
||||
}
|
||||
else
|
||||
{
|
||||
epcHelper = CreateObject<PointToPointEpcHelper> ();
|
||||
}
|
||||
lteHelper->SetEpcHelper (epcHelper);
|
||||
|
||||
Ptr<Node> pgw = epcHelper->GetPgwNode ();
|
||||
|
||||
// Create a single RemoteHost
|
||||
NodeContainer remoteHostContainer;
|
||||
remoteHostContainer.Create (1);
|
||||
Ptr<Node> 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 (MilliSeconds (10)));
|
||||
NetDeviceContainer internetDevices = p2ph.Install (pgw, remoteHost);
|
||||
Ipv4AddressHelper ipv4h;
|
||||
ipv4h.SetBase ("1.0.0.0", "255.0.0.0");
|
||||
Ipv4InterfaceContainer internetIpIfaces = ipv4h.Assign (internetDevices);
|
||||
// interface 0 is localhost, 1 is the p2p device
|
||||
Ipv4Address remoteHostAddr = internetIpIfaces.GetAddress (1);
|
||||
|
||||
Ipv4StaticRoutingHelper ipv4RoutingHelper;
|
||||
Ptr<Ipv4StaticRouting> remoteHostStaticRouting = ipv4RoutingHelper.GetStaticRouting (remoteHost->GetObject<Ipv4> ());
|
||||
remoteHostStaticRouting->AddNetworkRouteTo (Ipv4Address ("7.0.0.0"), Ipv4Mask ("255.0.0.0"), 1);
|
||||
|
||||
NodeContainer ueNodes;
|
||||
NodeContainer enbNodes;
|
||||
enbNodes.Create (numNodePairs);
|
||||
ueNodes.Create (numNodePairs);
|
||||
|
||||
// Install Mobility Model for eNBs and UEs
|
||||
Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
|
||||
for (uint16_t i = 0; i < numNodePairs; i++)
|
||||
{
|
||||
positionAlloc->Add (Vector (distance * i, 0, 0));
|
||||
}
|
||||
MobilityHelper mobility;
|
||||
mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
|
||||
mobility.SetPositionAllocator (positionAlloc);
|
||||
mobility.Install (enbNodes);
|
||||
mobility.Install (ueNodes);
|
||||
|
||||
// SGW node
|
||||
Ptr<Node> sgw = epcHelper->GetSgwNode ();
|
||||
|
||||
// Install Mobility Model for SGW
|
||||
Ptr<ListPositionAllocator> positionAlloc2 = CreateObject<ListPositionAllocator> ();
|
||||
positionAlloc2->Add (Vector (0.0, 50.0, 0.0));
|
||||
MobilityHelper mobility2;
|
||||
mobility2.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
|
||||
mobility2.SetPositionAllocator (positionAlloc2);
|
||||
mobility2.Install (sgw);
|
||||
|
||||
// Install LTE Devices to the nodes
|
||||
NetDeviceContainer enbLteDevs = lteHelper->InstallEnbDevice (enbNodes);
|
||||
NetDeviceContainer ueLteDevs = lteHelper->InstallUeDevice (ueNodes);
|
||||
|
||||
if (!useHelper)
|
||||
{
|
||||
Ipv4AddressHelper s1uIpv4AddressHelper;
|
||||
|
||||
// Create networks of the S1 interfaces
|
||||
s1uIpv4AddressHelper.SetBase ("10.0.0.0", "255.255.255.252");
|
||||
|
||||
for (uint16_t i = 0; i < numNodePairs; ++i)
|
||||
{
|
||||
Ptr<Node> enb = enbNodes.Get (i);
|
||||
|
||||
// Create a point to point link between the eNB and the SGW with
|
||||
// the corresponding new NetDevices on each side
|
||||
PointToPointHelper p2ph;
|
||||
DataRate s1uLinkDataRate = DataRate ("10Gb/s");
|
||||
uint16_t s1uLinkMtu = 2000;
|
||||
Time s1uLinkDelay = Time (0);
|
||||
p2ph.SetDeviceAttribute ("DataRate", DataRateValue (s1uLinkDataRate));
|
||||
p2ph.SetDeviceAttribute ("Mtu", UintegerValue (s1uLinkMtu));
|
||||
p2ph.SetChannelAttribute ("Delay", TimeValue (s1uLinkDelay));
|
||||
NetDeviceContainer sgwEnbDevices = p2ph.Install (sgw, enb);
|
||||
|
||||
Ipv4InterfaceContainer sgwEnbIpIfaces = s1uIpv4AddressHelper.Assign (sgwEnbDevices);
|
||||
s1uIpv4AddressHelper.NewNetwork ();
|
||||
|
||||
Ipv4Address sgwS1uAddress = sgwEnbIpIfaces.GetAddress (0);
|
||||
Ipv4Address enbS1uAddress = sgwEnbIpIfaces.GetAddress (1);
|
||||
|
||||
// Create S1 interface between the SGW and the eNB
|
||||
epcHelper->AddS1Interface (enb, enbS1uAddress, sgwS1uAddress);
|
||||
}
|
||||
}
|
||||
|
||||
// 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<Node> ueNode = ueNodes.Get (u);
|
||||
// Set the default gateway for the UE
|
||||
Ptr<Ipv4StaticRouting> ueStaticRouting = ipv4RoutingHelper.GetStaticRouting (ueNode->GetObject<Ipv4> ());
|
||||
ueStaticRouting->SetDefaultRoute (epcHelper->GetUeDefaultGatewayAddress (), 1);
|
||||
}
|
||||
|
||||
// Attach one UE per eNodeB
|
||||
for (uint16_t i = 0; i < numNodePairs; i++)
|
||||
{
|
||||
lteHelper->Attach (ueLteDevs.Get(i), enbLteDevs.Get(i));
|
||||
// side effect: the default EPS bearer will be activated
|
||||
}
|
||||
|
||||
|
||||
// Install and start applications on UEs and remote host
|
||||
uint16_t dlPort = 1100;
|
||||
uint16_t ulPort = 2000;
|
||||
ApplicationContainer clientApps;
|
||||
ApplicationContainer serverApps;
|
||||
for (uint32_t u = 0; u < ueNodes.GetN (); ++u)
|
||||
{
|
||||
if (!disableDl)
|
||||
{
|
||||
PacketSinkHelper dlPacketSinkHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), dlPort));
|
||||
serverApps.Add (dlPacketSinkHelper.Install (ueNodes.Get (u)));
|
||||
|
||||
UdpClientHelper dlClient (ueIpIface.GetAddress (u), dlPort);
|
||||
dlClient.SetAttribute ("Interval", TimeValue (interPacketInterval));
|
||||
dlClient.SetAttribute ("MaxPackets", UintegerValue (1000000));
|
||||
clientApps.Add (dlClient.Install (remoteHost));
|
||||
}
|
||||
|
||||
if (!disableUl)
|
||||
{
|
||||
++ulPort;
|
||||
PacketSinkHelper ulPacketSinkHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), ulPort));
|
||||
serverApps.Add (ulPacketSinkHelper.Install (remoteHost));
|
||||
|
||||
UdpClientHelper ulClient (remoteHostAddr, ulPort);
|
||||
ulClient.SetAttribute ("Interval", TimeValue (interPacketInterval));
|
||||
ulClient.SetAttribute ("MaxPackets", UintegerValue (1000000));
|
||||
clientApps.Add (ulClient.Install (ueNodes.Get(u)));
|
||||
}
|
||||
}
|
||||
|
||||
serverApps.Start (MilliSeconds (500));
|
||||
clientApps.Start (MilliSeconds (500));
|
||||
lteHelper->EnableTraces ();
|
||||
// Uncomment to enable PCAP tracing
|
||||
//p2ph.EnablePcapAll("lena-simple-epc-backhaul");
|
||||
|
||||
Simulator::Stop (simTime);
|
||||
Simulator::Run ();
|
||||
|
||||
/*GtkConfigStore config;
|
||||
config.ConfigureAttributes();*/
|
||||
|
||||
Simulator::Destroy ();
|
||||
return 0;
|
||||
}
|
||||
@@ -43,6 +43,9 @@ def build(bld):
|
||||
obj = bld.create_ns3_program('lena-simple-epc',
|
||||
['lte'])
|
||||
obj.source = 'lena-simple-epc.cc'
|
||||
obj = bld.create_ns3_program('lena-simple-epc-backhaul',
|
||||
['lte'])
|
||||
obj.source = 'lena-simple-epc-backhaul.cc'
|
||||
obj = bld.create_ns3_program('lena-deactivate-bearer',
|
||||
['lte'])
|
||||
obj.source = 'lena-deactivate-bearer.cc'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2011-2013 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
|
||||
* Copyright (c) 2011-2019 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
|
||||
@@ -20,35 +20,15 @@
|
||||
* Manuel Requena <manuel.requena@cttc.es>
|
||||
*/
|
||||
|
||||
#include <ns3/emu-epc-helper.h>
|
||||
#include <ns3/log.h>
|
||||
#include <ns3/inet-socket-address.h>
|
||||
#include <ns3/mac48-address.h>
|
||||
#include <ns3/eps-bearer.h>
|
||||
#include <ns3/ipv4-address.h>
|
||||
#include <ns3/ipv6-address.h>
|
||||
#include <ns3/internet-stack-helper.h>
|
||||
#include <ns3/packet-socket-helper.h>
|
||||
#include <ns3/packet-socket-address.h>
|
||||
#include <ns3/epc-enb-application.h>
|
||||
#include <ns3/epc-sgw-pgw-application.h>
|
||||
#include <ns3/emu-fd-net-device-helper.h>
|
||||
#include "ns3/ipv6-static-routing.h"
|
||||
#include "ns3/ipv6-static-routing-helper.h"
|
||||
#include <ns3/lte-enb-rrc.h>
|
||||
#include <ns3/epc-x2.h>
|
||||
#include <ns3/lte-enb-net-device.h>
|
||||
#include <ns3/lte-ue-net-device.h>
|
||||
#include <ns3/epc-mme.h>
|
||||
#include <ns3/epc-ue-nas.h>
|
||||
#include <ns3/string.h>
|
||||
#include <ns3/abort.h>
|
||||
#include <ns3/ipv4-address-generator.h>
|
||||
#include <ns3/ipv6-address-generator.h>
|
||||
#include <ns3/icmpv6-l4-protocol.h>
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/string.h"
|
||||
#include "ns3/lte-enb-net-device.h"
|
||||
#include "ns3/lte-enb-rrc.h"
|
||||
#include "ns3/epc-x2.h"
|
||||
#include "ns3/emu-fd-net-device-helper.h"
|
||||
#include "ns3/emu-epc-helper.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -57,12 +37,30 @@ NS_LOG_COMPONENT_DEFINE ("EmuEpcHelper");
|
||||
NS_OBJECT_ENSURE_REGISTERED (EmuEpcHelper);
|
||||
|
||||
|
||||
EmuEpcHelper::EmuEpcHelper ()
|
||||
: m_gtpuUdpPort (2152) // fixed by the standard
|
||||
EmuEpcHelper::EmuEpcHelper ()
|
||||
: NoBackhaulEpcHelper ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
// To access the attribute value within the constructor
|
||||
ObjectBase::ConstructSelf (AttributeConstructionList ());
|
||||
|
||||
// Create EmuFdNetDevice for SGW
|
||||
EmuFdNetDeviceHelper emu;
|
||||
NS_LOG_LOGIC ("SGW device: " << m_sgwDeviceName);
|
||||
emu.SetDeviceName (m_sgwDeviceName);
|
||||
|
||||
Ptr<Node> sgw = GetSgwNode ();
|
||||
NetDeviceContainer sgwDevices = emu.Install (sgw);
|
||||
Ptr<NetDevice> sgwDevice = sgwDevices.Get (0);
|
||||
NS_LOG_LOGIC ("SGW MAC address: " << m_sgwMacAddress);
|
||||
sgwDevice->SetAttribute ("Address", Mac48AddressValue (m_sgwMacAddress.c_str ()));
|
||||
|
||||
// Address of the SGW: 10.0.0.1
|
||||
m_epcIpv4AddressHelper.SetBase ("10.0.0.0", "255.255.255.0", "0.0.0.1");
|
||||
m_sgwIpIfaces = m_epcIpv4AddressHelper.Assign (sgwDevices);
|
||||
|
||||
// Address of the first eNB: 10.0.0.101
|
||||
m_epcIpv4AddressHelper.SetBase ("10.0.0.0", "255.255.255.0", "0.0.0.101");
|
||||
}
|
||||
|
||||
EmuEpcHelper::~EmuEpcHelper ()
|
||||
@@ -77,23 +75,23 @@ EmuEpcHelper::GetTypeId (void)
|
||||
.SetParent<EpcHelper> ()
|
||||
.SetGroupName("Lte")
|
||||
.AddConstructor<EmuEpcHelper> ()
|
||||
.AddAttribute ("sgwDeviceName",
|
||||
.AddAttribute ("SgwDeviceName",
|
||||
"The name of the device used for the S1-U interface of the SGW",
|
||||
StringValue ("veth0"),
|
||||
MakeStringAccessor (&EmuEpcHelper::m_sgwDeviceName),
|
||||
MakeStringChecker ())
|
||||
.AddAttribute ("enbDeviceName",
|
||||
.AddAttribute ("EnbDeviceName",
|
||||
"The name of the device used for the S1-U interface of the eNB",
|
||||
StringValue ("veth1"),
|
||||
MakeStringAccessor (&EmuEpcHelper::m_enbDeviceName),
|
||||
MakeStringChecker ())
|
||||
.AddAttribute ("SgwMacAddress",
|
||||
"MAC address used for the SGW ",
|
||||
.AddAttribute ("SgwMacAddress",
|
||||
"MAC address used for the SGW",
|
||||
StringValue ("00:00:00:59:00:aa"),
|
||||
MakeStringAccessor (&EmuEpcHelper::m_sgwMacAddress),
|
||||
MakeStringChecker ())
|
||||
.AddAttribute ("EnbMacAddressBase",
|
||||
"First 5 bytes of the Enb MAC address base",
|
||||
.AddAttribute ("EnbMacAddressBase",
|
||||
"First 5 bytes of the eNB MAC address base",
|
||||
StringValue ("00:00:00:eb:00"),
|
||||
MakeStringAccessor (&EmuEpcHelper::m_enbMacAddressBase),
|
||||
MakeStringChecker ())
|
||||
@@ -107,102 +105,11 @@ EmuEpcHelper::GetInstanceTypeId () const
|
||||
return GetTypeId ();
|
||||
}
|
||||
|
||||
void
|
||||
EmuEpcHelper::DoInitialize ()
|
||||
{
|
||||
NS_LOG_LOGIC (this);
|
||||
|
||||
// we use a /8 net for all UEs
|
||||
m_uePgwAddressHelper.SetBase ("7.0.0.0", "255.0.0.0");
|
||||
|
||||
// we use a /64 IPv6 net all UEs
|
||||
m_uePgwAddressHelper6.SetBase ("7777:f00d::", Ipv6Prefix (64));
|
||||
|
||||
|
||||
// create SgwPgwNode
|
||||
m_sgwPgw = CreateObject<Node> ();
|
||||
InternetStackHelper internet;
|
||||
internet.Install (m_sgwPgw);
|
||||
|
||||
// The Tun device resides in different 64 bit subnet.
|
||||
// We must create an unique route to tun device for all the packets destined
|
||||
// to all 64 bit IPv6 prefixes of UEs, based by the unique 48 bit network prefix of this EPC network
|
||||
Ipv6StaticRoutingHelper ipv6RoutingHelper;
|
||||
Ptr<Ipv6StaticRouting> pgwStaticRouting = ipv6RoutingHelper.GetStaticRouting (m_sgwPgw->GetObject<Ipv6> ());
|
||||
pgwStaticRouting->AddNetworkRouteTo ("7777:f00d::", Ipv6Prefix (64), Ipv6Address ("::"), 1, 0);
|
||||
|
||||
// create S1-U socket
|
||||
Ptr<Socket> sgwPgwS1uSocket = Socket::CreateSocket (m_sgwPgw, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
int retval = sgwPgwS1uSocket->Bind (InetSocketAddress (Ipv4Address::GetAny (), m_gtpuUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// create TUN device containing IPv4 address and implementing tunneling of user data over GTP-U/UDP/IP
|
||||
m_tunDevice = CreateObject<VirtualNetDevice> ();
|
||||
|
||||
// allow jumbo packets
|
||||
m_tunDevice->SetAttribute ("Mtu", UintegerValue (30000));
|
||||
|
||||
// yes we need this
|
||||
m_tunDevice->SetAddress (Mac48Address::Allocate ());
|
||||
|
||||
m_sgwPgw->AddDevice (m_tunDevice);
|
||||
NetDeviceContainer tunDeviceContainer;
|
||||
tunDeviceContainer.Add (m_tunDevice);
|
||||
|
||||
// the TUN device is on the same subnet as the UEs, so when a packet
|
||||
// addressed to an UE IPv4 address arrives at the intenet to the WAN interface of
|
||||
// the PGW it will be forwarded to the TUN device.
|
||||
Ipv4InterfaceContainer tunDeviceIpv4IfContainer = AssignUeIpv4Address (tunDeviceContainer);
|
||||
|
||||
// the TUN device for IPv6 address is on the different subnet as the
|
||||
// UEs, it will forward the UE packets as we have inserted the route
|
||||
// for all UEs at the time of assigning UE addresses
|
||||
Ipv6InterfaceContainer tunDeviceIpv6IfContainer = AssignUeIpv6Address (tunDeviceContainer);
|
||||
|
||||
//Set Forwarding
|
||||
tunDeviceIpv6IfContainer.SetForwarding (0,true);
|
||||
tunDeviceIpv6IfContainer.SetDefaultRouteInAllNodes (0);
|
||||
|
||||
|
||||
// create EpcSgwPgwApplication
|
||||
m_sgwPgwApp = CreateObject<EpcSgwPgwApplication> (m_tunDevice, sgwPgwS1uSocket);
|
||||
m_sgwPgw->AddApplication (m_sgwPgwApp);
|
||||
|
||||
// connect SgwPgwApplication and virtual net device for tunneling
|
||||
m_tunDevice->SetSendCallback (MakeCallback (&EpcSgwPgwApplication::RecvFromTunDevice, m_sgwPgwApp));
|
||||
|
||||
|
||||
// Create MME and connect with SGW via S11 interface
|
||||
m_mme = CreateObject<EpcMme> ();
|
||||
m_mme->SetS11SapSgw (m_sgwPgwApp->GetS11SapSgw ());
|
||||
m_sgwPgwApp->SetS11SapMme (m_mme->GetS11SapMme ());
|
||||
|
||||
// Create EmuFdNetDevice for SGW
|
||||
EmuFdNetDeviceHelper emu;
|
||||
NS_LOG_LOGIC ("SGW device: " << m_sgwDeviceName);
|
||||
emu.SetDeviceName (m_sgwDeviceName);
|
||||
NetDeviceContainer sgwDevices = emu.Install (m_sgwPgw);
|
||||
Ptr<NetDevice> sgwDevice = sgwDevices.Get (0);
|
||||
NS_LOG_LOGIC ("MAC address of SGW: " << m_sgwMacAddress);
|
||||
sgwDevice->SetAttribute ("Address", Mac48AddressValue (m_sgwMacAddress.c_str ()));
|
||||
|
||||
// we use a /8 subnet so the SGW and the eNBs can talk directly to each other
|
||||
m_epcIpv4AddressHelper.SetBase ("10.0.0.0", "255.255.255.0", "0.0.0.1");
|
||||
m_sgwIpIfaces = m_epcIpv4AddressHelper.Assign (sgwDevices);
|
||||
m_epcIpv4AddressHelper.SetBase ("10.0.0.0", "255.0.0.0", "0.0.0.101");
|
||||
|
||||
|
||||
EpcHelper::DoInitialize ();
|
||||
}
|
||||
|
||||
void
|
||||
EmuEpcHelper::DoDispose ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_tunDevice->SetSendCallback (MakeNullCallback<bool, Ptr<Packet>, const Address&, const Address&, uint16_t> ());
|
||||
m_tunDevice = 0;
|
||||
m_sgwPgwApp = 0;
|
||||
m_sgwPgw->Dispose ();
|
||||
NoBackhaulEpcHelper::DoDispose ();
|
||||
}
|
||||
|
||||
|
||||
@@ -211,88 +118,32 @@ EmuEpcHelper::AddEnb (Ptr<Node> enb, Ptr<NetDevice> lteEnbNetDevice, uint16_t ce
|
||||
{
|
||||
NS_LOG_FUNCTION (this << enb << lteEnbNetDevice << cellId);
|
||||
|
||||
Initialize ();
|
||||
|
||||
NS_ASSERT (enb == lteEnbNetDevice->GetNode ());
|
||||
|
||||
// add an Internet stack to the previously created eNB
|
||||
InternetStackHelper internet;
|
||||
internet.Install (enb);
|
||||
NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB after node creation: " << enb->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
|
||||
|
||||
NoBackhaulEpcHelper::AddEnb (enb, lteEnbNetDevice, cellId);
|
||||
|
||||
// Create an EmuFdNetDevice for the eNB to connect with the SGW and other eNBs
|
||||
EmuFdNetDeviceHelper emu;
|
||||
NS_LOG_LOGIC ("eNB cellId: " << cellId);
|
||||
NS_LOG_LOGIC ("eNB device: " << m_enbDeviceName);
|
||||
emu.SetDeviceName (m_enbDeviceName);
|
||||
emu.SetDeviceName (m_enbDeviceName);
|
||||
NetDeviceContainer enbDevices = emu.Install (enb);
|
||||
|
||||
NS_ABORT_IF ((cellId == 0) || (cellId > 255));
|
||||
std::ostringstream enbMacAddress;
|
||||
enbMacAddress << m_enbMacAddressBase << ":" << std::hex << std::setfill ('0') << std::setw (2) << cellId;
|
||||
NS_LOG_LOGIC ("MAC address of enB with cellId " << cellId << " : " << enbMacAddress.str ());
|
||||
NS_LOG_LOGIC ("eNB MAC address: " << enbMacAddress.str ());
|
||||
Ptr<NetDevice> enbDev = enbDevices.Get (0);
|
||||
enbDev->SetAttribute ("Address", Mac48AddressValue (enbMacAddress.str ().c_str ()));
|
||||
|
||||
//emu.EnablePcap ("enbDevice", enbDev);
|
||||
|
||||
NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB after installing emu dev: " << enb->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB after installing emu dev: " << enb->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
Ipv4InterfaceContainer enbIpIfaces = m_epcIpv4AddressHelper.Assign (enbDevices);
|
||||
NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB after assigning Ipv4 addr to S1 dev: " << enb->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
|
||||
|
||||
Ipv4Address enbAddress = enbIpIfaces.GetAddress (0);
|
||||
Ipv4Address sgwAddress = m_sgwIpIfaces.GetAddress (0);
|
||||
|
||||
// create S1-U socket for the ENB
|
||||
Ptr<Socket> enbS1uSocket = Socket::CreateSocket (enb, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
int retval = enbS1uSocket->Bind (InetSocketAddress (enbAddress, m_gtpuUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// create LTE socket for the ENB
|
||||
Ptr<Socket> enbLteSocket = Socket::CreateSocket (enb, TypeId::LookupByName ("ns3::PacketSocketFactory"));
|
||||
PacketSocketAddress enbLteSocketBindAddress;
|
||||
enbLteSocketBindAddress.SetSingleDevice (lteEnbNetDevice->GetIfIndex ());
|
||||
enbLteSocketBindAddress.SetProtocol (Ipv4L3Protocol::PROT_NUMBER);
|
||||
retval = enbLteSocket->Bind (enbLteSocketBindAddress);
|
||||
NS_ASSERT (retval == 0);
|
||||
PacketSocketAddress enbLteSocketConnectAddress;
|
||||
enbLteSocketConnectAddress.SetPhysicalAddress (Mac48Address::GetBroadcast ());
|
||||
enbLteSocketConnectAddress.SetSingleDevice (lteEnbNetDevice->GetIfIndex ());
|
||||
enbLteSocketConnectAddress.SetProtocol (Ipv4L3Protocol::PROT_NUMBER);
|
||||
retval = enbLteSocket->Connect (enbLteSocketConnectAddress);
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// create LTE socket for the ENB
|
||||
Ptr<Socket> enbLteSocket6 = Socket::CreateSocket (enb, TypeId::LookupByName ("ns3::PacketSocketFactory"));
|
||||
PacketSocketAddress enbLteSocketBindAddress6;
|
||||
enbLteSocketBindAddress6.SetSingleDevice (lteEnbNetDevice->GetIfIndex ());
|
||||
enbLteSocketBindAddress6.SetProtocol (Ipv6L3Protocol::PROT_NUMBER);
|
||||
retval = enbLteSocket6->Bind (enbLteSocketBindAddress6);
|
||||
NS_ASSERT (retval == 0);
|
||||
PacketSocketAddress enbLteSocketConnectAddress6;
|
||||
enbLteSocketConnectAddress6.SetPhysicalAddress (Mac48Address::GetBroadcast ());
|
||||
enbLteSocketConnectAddress6.SetSingleDevice (lteEnbNetDevice->GetIfIndex ());
|
||||
enbLteSocketConnectAddress6.SetProtocol (Ipv6L3Protocol::PROT_NUMBER);
|
||||
retval = enbLteSocket6->Connect (enbLteSocketConnectAddress6);
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
NS_LOG_INFO ("create EpcEnbApplication");
|
||||
Ptr<EpcEnbApplication> enbApp = CreateObject<EpcEnbApplication> (enbLteSocket, enbLteSocket6, enbS1uSocket, enbAddress, sgwAddress, cellId);
|
||||
enb->AddApplication (enbApp);
|
||||
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> ();
|
||||
enb->AggregateObject (x2);
|
||||
|
||||
NS_LOG_INFO ("connect S1-AP interface");
|
||||
m_mme->AddEnb (cellId, enbAddress, enbApp->GetS1apSapEnb ());
|
||||
m_sgwPgwApp->AddEnb (cellId, enbAddress, sgwAddress);
|
||||
enbApp->SetS1apSapMme (m_mme->GetS1apSapMme ());
|
||||
NoBackhaulEpcHelper::AddS1Interface (enb, enbAddress, sgwAddress, cellId);
|
||||
}
|
||||
|
||||
|
||||
@@ -345,100 +196,4 @@ EmuEpcHelper::AddX2Interface (Ptr<Node> enb1, Ptr<Node> enb2)
|
||||
enb2LteDev->GetRrc ()->AddX2Neighbour (enb1LteDev->GetCellId ());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EmuEpcHelper::AddUe (Ptr<NetDevice> ueDevice, uint64_t imsi)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << imsi << ueDevice );
|
||||
|
||||
m_mme->AddUe (imsi);
|
||||
m_sgwPgwApp->AddUe (imsi);
|
||||
|
||||
}
|
||||
|
||||
|
||||
uint8_t
|
||||
EmuEpcHelper::ActivateEpsBearer (Ptr<NetDevice> ueDevice, uint64_t imsi, Ptr<EpcTft> tft, EpsBearer bearer)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << ueDevice << imsi);
|
||||
|
||||
// we now retrieve the IPv4/IPv6 address of the UE and notify it to the SGW;
|
||||
// we couldn't do it before since address assignment is triggered by
|
||||
// the user simulation program, rather than done by the EPC
|
||||
Ptr<Node> ueNode = ueDevice->GetNode ();
|
||||
Ptr<Ipv4> ueIpv4 = ueNode->GetObject<Ipv4> ();
|
||||
Ptr<Ipv6> ueIpv6 = ueNode->GetObject<Ipv6> ();
|
||||
NS_ASSERT_MSG (ueIpv4 != 0 || ueIpv6 != 0, "UEs need to have IPv4/IPv6 installed before EPS bearers can be activated");
|
||||
|
||||
if (ueIpv4)
|
||||
{
|
||||
int32_t interface = ueIpv4->GetInterfaceForDevice (ueDevice);
|
||||
if (interface >= 0 && ueIpv4->GetNAddresses (interface) == 1)
|
||||
{
|
||||
Ipv4Address ueAddr = ueIpv4->GetAddress (interface, 0).GetLocal ();
|
||||
NS_LOG_LOGIC (" UE IPv4 address: " << ueAddr);
|
||||
m_sgwPgwApp->SetUeAddress (imsi, ueAddr);
|
||||
}
|
||||
}
|
||||
if (ueIpv6)
|
||||
{
|
||||
int32_t interface6 = ueIpv6->GetInterfaceForDevice (ueDevice);
|
||||
if (interface6 >= 0 && ueIpv6->GetNAddresses (interface6) == 2)
|
||||
{
|
||||
Ipv6Address ueAddr6 = ueIpv6->GetAddress (interface6, 1).GetAddress ();
|
||||
NS_LOG_LOGIC (" UE IPv6 address: " << ueAddr6);
|
||||
m_sgwPgwApp->SetUeAddress6 (imsi, ueAddr6);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t bearerId = m_mme->AddBearer (imsi, tft, bearer);
|
||||
Ptr<LteUeNetDevice> ueLteDevice = ueDevice->GetObject<LteUeNetDevice> ();
|
||||
if (ueLteDevice)
|
||||
{
|
||||
Simulator::ScheduleNow (&EpcUeNas::ActivateEpsBearer, ueLteDevice->GetNas (), bearer, tft);
|
||||
}
|
||||
return bearerId;
|
||||
}
|
||||
|
||||
|
||||
Ptr<Node>
|
||||
EmuEpcHelper::GetPgwNode () const
|
||||
{
|
||||
return m_sgwPgw;
|
||||
}
|
||||
|
||||
|
||||
Ipv4InterfaceContainer
|
||||
EmuEpcHelper::AssignUeIpv4Address (NetDeviceContainer ueDevices)
|
||||
{
|
||||
return m_uePgwAddressHelper.Assign (ueDevices);
|
||||
}
|
||||
|
||||
Ipv6InterfaceContainer
|
||||
EmuEpcHelper::AssignUeIpv6Address (NetDeviceContainer ueDevices)
|
||||
{
|
||||
for (NetDeviceContainer::Iterator iter = ueDevices.Begin ();
|
||||
iter != ueDevices.End ();
|
||||
iter ++)
|
||||
{
|
||||
Ptr<Icmpv6L4Protocol> icmpv6 = (*iter)->GetNode ()->GetObject<Icmpv6L4Protocol> ();
|
||||
icmpv6->SetAttribute ("DAD", BooleanValue (false));
|
||||
}
|
||||
return m_uePgwAddressHelper6.Assign (ueDevices);
|
||||
}
|
||||
|
||||
Ipv4Address
|
||||
EmuEpcHelper::GetUeDefaultGatewayAddress ()
|
||||
{
|
||||
// return the address of the tun device
|
||||
return m_sgwPgw->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ();
|
||||
}
|
||||
|
||||
Ipv6Address
|
||||
EmuEpcHelper::GetUeDefaultGatewayAddress6 ()
|
||||
{
|
||||
// return the address of the tun device 6
|
||||
return m_sgwPgw->GetObject<Ipv6> ()->GetAddress (1, 1).GetAddress ();
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2011-2013 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
|
||||
* Copyright (c) 2011-2019 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
|
||||
@@ -23,23 +23,10 @@
|
||||
#ifndef EMU_EPC_HELPER_H
|
||||
#define EMU_EPC_HELPER_H
|
||||
|
||||
#include <ns3/object.h>
|
||||
#include <ns3/ipv4-address-helper.h>
|
||||
#include <ns3/ipv6-address-helper.h>
|
||||
#include <ns3/data-rate.h>
|
||||
#include <ns3/epc-tft.h>
|
||||
#include <ns3/eps-bearer.h>
|
||||
#include <ns3/epc-helper.h>
|
||||
#include "ns3/no-backhaul-epc-helper.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Node;
|
||||
class NetDevice;
|
||||
class VirtualNetDevice;
|
||||
class EpcSgwPgwApplication;
|
||||
class EpcX2;
|
||||
class EpcMme;
|
||||
|
||||
/**
|
||||
* \ingroup lte
|
||||
*
|
||||
@@ -51,20 +38,19 @@ class EpcMme;
|
||||
* EmuFdNetDevice; in particular, one device is used to send all the
|
||||
* traffic related to these interfaces.
|
||||
*/
|
||||
class EmuEpcHelper : public EpcHelper
|
||||
class EmuEpcHelper : public NoBackhaulEpcHelper
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
EmuEpcHelper ();
|
||||
|
||||
/**
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
*/
|
||||
virtual ~EmuEpcHelper ();
|
||||
|
||||
|
||||
// inherited from Object
|
||||
/**
|
||||
* Register this type.
|
||||
@@ -72,71 +58,21 @@ public:
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
TypeId GetInstanceTypeId () const;
|
||||
virtual void DoInitialize ();
|
||||
virtual void DoDispose ();
|
||||
|
||||
// inherited from EpcHelper
|
||||
virtual void AddEnb (Ptr<Node> enbNode, Ptr<NetDevice> lteEnbNetDevice, uint16_t cellId);
|
||||
virtual void AddUe (Ptr<NetDevice> ueLteDevice, uint64_t imsi);
|
||||
virtual void AddX2Interface (Ptr<Node> enbNode1, Ptr<Node> enbNode2);
|
||||
virtual uint8_t ActivateEpsBearer (Ptr<NetDevice> ueLteDevice, uint64_t imsi, Ptr<EpcTft> tft, EpsBearer bearer);
|
||||
virtual Ptr<Node> GetPgwNode () const;
|
||||
virtual Ipv4InterfaceContainer AssignUeIpv4Address (NetDeviceContainer ueDevices);
|
||||
virtual Ipv6InterfaceContainer AssignUeIpv6Address (NetDeviceContainer ueDevices);
|
||||
virtual Ipv4Address GetUeDefaultGatewayAddress ();
|
||||
virtual Ipv6Address GetUeDefaultGatewayAddress6 ();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* helper to assign IPv4 addresses to UE devices as well as to the TUN device of the SGW/PGW
|
||||
/**
|
||||
* helper to assign addresses to S1-U NetDevices
|
||||
*/
|
||||
Ipv4AddressHelper m_uePgwAddressHelper;
|
||||
|
||||
/**
|
||||
* helper to assign IPv6 addresses to UE devices as well as to the TUN device of the SGW/PGW
|
||||
*/
|
||||
Ipv6AddressHelper m_uePgwAddressHelper6;
|
||||
Ipv4AddressHelper m_epcIpv4AddressHelper;
|
||||
|
||||
/**
|
||||
* SGW-PGW network element
|
||||
*/
|
||||
Ptr<Node> m_sgwPgw;
|
||||
|
||||
/**
|
||||
* SGW-PGW application
|
||||
*/
|
||||
Ptr<EpcSgwPgwApplication> m_sgwPgwApp;
|
||||
|
||||
/**
|
||||
* TUN device containing IPv4 address and implementing tunneling of user data over GTP-U/UDP/IP
|
||||
*/
|
||||
Ptr<VirtualNetDevice> m_tunDevice;
|
||||
|
||||
/**
|
||||
* MME network element
|
||||
*/
|
||||
Ptr<EpcMme> m_mme;
|
||||
|
||||
/**
|
||||
* helper to assign addresses to S1-U NetDevices
|
||||
*/
|
||||
Ipv4AddressHelper m_epcIpv4AddressHelper;
|
||||
|
||||
/**
|
||||
* UDP port where the GTP-U Socket is bound, fixed by the standard as 2152
|
||||
*/
|
||||
uint16_t m_gtpuUdpPort;
|
||||
|
||||
/**
|
||||
* Map storing for each IMSI the corresponding eNB NetDevice
|
||||
*
|
||||
*/
|
||||
std::map<uint64_t, Ptr<NetDevice> > m_imsiEnbDeviceMap;
|
||||
|
||||
/**
|
||||
* Container for Ipv4Interfaces of the SGW/PGW
|
||||
* Container for Ipv4Interfaces of the SGW
|
||||
*/
|
||||
Ipv4InterfaceContainer m_sgwIpIfaces;
|
||||
|
||||
@@ -159,12 +95,8 @@ private:
|
||||
* First 5 bytes of the Enb MAC address base
|
||||
*/
|
||||
std::string m_enbMacAddressBase;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif // EMU_EPC_HELPER_H
|
||||
|
||||
@@ -97,6 +97,17 @@ public:
|
||||
*/
|
||||
virtual void AddX2Interface (Ptr<Node> enbNode1, Ptr<Node> enbNode2) = 0;
|
||||
|
||||
/**
|
||||
* Add an S1 interface between an eNB and a SGW
|
||||
*
|
||||
* \param enb eNB peer of the S1 interface
|
||||
* \param enbAddress eNB IPv4 address of the S1 interface
|
||||
* \param sgwAddress SGW IPv4 address of the S1 interface
|
||||
* \param cellId cellId of the eNB
|
||||
*/
|
||||
virtual void AddS1Interface (Ptr<Node> enb, Ipv4Address enbAddress, Ipv4Address sgwAddress, uint16_t cellId = 0) = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Activate an EPS bearer, setting up the corresponding S1-U tunnel.
|
||||
*
|
||||
@@ -113,11 +124,18 @@ public:
|
||||
|
||||
|
||||
/**
|
||||
* Get the SGW node
|
||||
*
|
||||
* \return a pointer to the SGW
|
||||
*/
|
||||
virtual Ptr<Node> GetSgwNode () const = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Get the PGW node
|
||||
*
|
||||
* \return a pointer to the node implementing PGW
|
||||
* functionality. Note that in this particular implementation this
|
||||
* node will also hold the SGW functionality. The primary use
|
||||
* intended for this method is to allow the user to configure the Gi
|
||||
* \return a pointer to the PGW node
|
||||
* The primary use intended for this method is to allow the user to configure the SGi
|
||||
* interface of the PGW, i.e., to connect the PGW to the internet.
|
||||
*/
|
||||
virtual Ptr<Node> GetPgwNode () const = 0;
|
||||
|
||||
570
src/lte/helper/no-backhaul-epc-helper.cc
Normal file
570
src/lte/helper/no-backhaul-epc-helper.cc
Normal file
@@ -0,0 +1,570 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2019 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 <manuel.requena@cttc.es>
|
||||
* (based on the original point-to-point-epc-helper.cc)
|
||||
*/
|
||||
|
||||
#include "ns3/boolean.h"
|
||||
#include "ns3/string.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/packet-socket-address.h"
|
||||
#include "ns3/point-to-point-helper.h"
|
||||
#include "ns3/internet-stack-helper.h"
|
||||
#include "ns3/ipv6-static-routing-helper.h"
|
||||
#include "ns3/icmpv6-l4-protocol.h"
|
||||
#include "ns3/epc-enb-application.h"
|
||||
#include "ns3/epc-pgw-application.h"
|
||||
#include "ns3/epc-sgw-application.h"
|
||||
#include "ns3/epc-mme-application.h"
|
||||
#include "ns3/epc-x2.h"
|
||||
#include "ns3/lte-enb-rrc.h"
|
||||
#include "ns3/epc-ue-nas.h"
|
||||
#include "ns3/lte-enb-net-device.h"
|
||||
#include "ns3/lte-ue-net-device.h"
|
||||
|
||||
#include "ns3/no-backhaul-epc-helper.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("NoBackhaulEpcHelper");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (NoBackhaulEpcHelper);
|
||||
|
||||
|
||||
NoBackhaulEpcHelper::NoBackhaulEpcHelper ()
|
||||
: m_gtpuUdpPort (2152), // fixed by the standard
|
||||
m_s11LinkDataRate (DataRate ("10Gb/s")),
|
||||
m_s11LinkDelay (Seconds (0)),
|
||||
m_s11LinkMtu (3000),
|
||||
m_gtpcUdpPort (2123), // fixed by the standard
|
||||
m_s5LinkDataRate (DataRate ("10Gb/s")),
|
||||
m_s5LinkDelay (Seconds (0)),
|
||||
m_s5LinkMtu (3000)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
// To access the attribute value within the constructor
|
||||
ObjectBase::ConstructSelf (AttributeConstructionList ());
|
||||
|
||||
int retval;
|
||||
|
||||
// since we use point-to-point links for links between the core network nodes,
|
||||
// we use a /30 subnet which can hold exactly two addresses
|
||||
// (remember that net broadcast and null address are not valid)
|
||||
m_x2Ipv4AddressHelper.SetBase ("12.0.0.0", "255.255.255.252");
|
||||
m_s11Ipv4AddressHelper.SetBase ("13.0.0.0", "255.255.255.252");
|
||||
m_s5Ipv4AddressHelper.SetBase ("14.0.0.0", "255.255.255.252");
|
||||
|
||||
// we use a /8 net for all UEs
|
||||
m_uePgwAddressHelper.SetBase ("7.0.0.0", "255.0.0.0");
|
||||
|
||||
// we use a /64 IPv6 net all UEs
|
||||
m_uePgwAddressHelper6.SetBase ("7777:f00d::", Ipv6Prefix (64));
|
||||
|
||||
// Create PGW, SGW and MME nodes
|
||||
m_pgw = CreateObject<Node> ();
|
||||
m_sgw = CreateObject<Node> ();
|
||||
m_mme = CreateObject<Node> ();
|
||||
InternetStackHelper internet;
|
||||
internet.Install (m_pgw);
|
||||
internet.Install (m_sgw);
|
||||
internet.Install (m_mme);
|
||||
|
||||
// The Tun device resides in different 64 bit subnet.
|
||||
// We must create an unique route to tun device for all the packets destined
|
||||
// to all 64 bit IPv6 prefixes of UEs, based by the unique 48 bit network prefix of this EPC network
|
||||
Ipv6StaticRoutingHelper ipv6RoutingHelper;
|
||||
Ptr<Ipv6StaticRouting> pgwStaticRouting = ipv6RoutingHelper.GetStaticRouting (m_pgw->GetObject<Ipv6> ());
|
||||
pgwStaticRouting->AddNetworkRouteTo ("7777:f00d::", Ipv6Prefix (64), Ipv6Address ("::"), 1, 0);
|
||||
|
||||
// create TUN device implementing tunneling of user data over GTP-U/UDP/IP in the PGW
|
||||
m_tunDevice = CreateObject<VirtualNetDevice> ();
|
||||
|
||||
// allow jumbo packets
|
||||
m_tunDevice->SetAttribute ("Mtu", UintegerValue (30000));
|
||||
|
||||
// yes we need this
|
||||
m_tunDevice->SetAddress (Mac48Address::Allocate ());
|
||||
|
||||
m_pgw->AddDevice (m_tunDevice);
|
||||
NetDeviceContainer tunDeviceContainer;
|
||||
tunDeviceContainer.Add (m_tunDevice);
|
||||
// the TUN device is on the same subnet as the UEs, so when a packet
|
||||
// addressed to an UE arrives at the intenet to the WAN interface of
|
||||
// the PGW it will be forwarded to the TUN device.
|
||||
Ipv4InterfaceContainer tunDeviceIpv4IfContainer = AssignUeIpv4Address (tunDeviceContainer);
|
||||
|
||||
|
||||
// the TUN device for IPv6 address is on the different subnet as the
|
||||
// UEs, it will forward the UE packets as we have inserted the route
|
||||
// for all UEs at the time of assigning UE addresses
|
||||
Ipv6InterfaceContainer tunDeviceIpv6IfContainer = AssignUeIpv6Address (tunDeviceContainer);
|
||||
|
||||
|
||||
//Set Forwarding of the IPv6 interface
|
||||
tunDeviceIpv6IfContainer.SetForwarding (0,true);
|
||||
tunDeviceIpv6IfContainer.SetDefaultRouteInAllNodes (0);
|
||||
|
||||
// Create S5 link between PGW and SGW
|
||||
PointToPointHelper p2ph;
|
||||
p2ph.SetDeviceAttribute ("DataRate", DataRateValue (m_s5LinkDataRate));
|
||||
p2ph.SetDeviceAttribute ("Mtu", UintegerValue (m_s5LinkMtu));
|
||||
p2ph.SetChannelAttribute ("Delay", TimeValue (m_s5LinkDelay));
|
||||
NetDeviceContainer pgwSgwDevices = p2ph.Install (m_pgw, m_sgw);
|
||||
NS_LOG_LOGIC ("IPv4 ifaces of the PGW after installing p2p dev: " << m_pgw->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
NS_LOG_LOGIC ("IPv4 ifaces of the SGW after installing p2p dev: " << m_sgw->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
Ptr<NetDevice> pgwDev = pgwSgwDevices.Get (0);
|
||||
Ptr<NetDevice> sgwDev = pgwSgwDevices.Get (1);
|
||||
m_s5Ipv4AddressHelper.NewNetwork ();
|
||||
Ipv4InterfaceContainer pgwSgwIpIfaces = m_s5Ipv4AddressHelper.Assign (pgwSgwDevices);
|
||||
NS_LOG_LOGIC ("IPv4 ifaces of the PGW after assigning Ipv4 addr to S5 dev: " << m_pgw->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
NS_LOG_LOGIC ("IPv4 ifaces of the SGW after assigning Ipv4 addr to S5 dev: " << m_sgw->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
|
||||
Ipv4Address pgwS5Address = pgwSgwIpIfaces.GetAddress (0);
|
||||
Ipv4Address sgwS5Address = pgwSgwIpIfaces.GetAddress (1);
|
||||
|
||||
// Create S5-U socket in the PGW
|
||||
Ptr<Socket> pgwS5uSocket = Socket::CreateSocket (m_pgw, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
retval = pgwS5uSocket->Bind (InetSocketAddress (pgwS5Address, m_gtpuUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// Create S5-C socket in the PGW
|
||||
Ptr<Socket> pgwS5cSocket = Socket::CreateSocket (m_pgw, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
retval = pgwS5cSocket->Bind (InetSocketAddress (pgwS5Address, m_gtpcUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// Create EpcPgwApplication
|
||||
m_pgwApp = CreateObject<EpcPgwApplication> (m_tunDevice, pgwS5Address, pgwS5uSocket, pgwS5cSocket);
|
||||
m_pgw->AddApplication (m_pgwApp);
|
||||
|
||||
// Connect EpcPgwApplication and virtual net device for tunneling
|
||||
m_tunDevice->SetSendCallback (MakeCallback (&EpcPgwApplication::RecvFromTunDevice, m_pgwApp));
|
||||
|
||||
|
||||
// Create S5-U socket in the SGW
|
||||
Ptr<Socket> sgwS5uSocket = Socket::CreateSocket (m_sgw, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
retval = sgwS5uSocket->Bind (InetSocketAddress (sgwS5Address, m_gtpuUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// Create S5-C socket in the SGW
|
||||
Ptr<Socket> sgwS5cSocket = Socket::CreateSocket (m_sgw, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
retval = sgwS5cSocket->Bind (InetSocketAddress (sgwS5Address, m_gtpcUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// Create S1-U socket in the SGW
|
||||
Ptr<Socket> sgwS1uSocket = Socket::CreateSocket (m_sgw, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
retval = sgwS1uSocket->Bind (InetSocketAddress (Ipv4Address::GetAny (), m_gtpuUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// Create EpcSgwApplication
|
||||
m_sgwApp = CreateObject<EpcSgwApplication> (sgwS1uSocket, sgwS5Address, sgwS5uSocket, sgwS5cSocket);
|
||||
m_sgw->AddApplication (m_sgwApp);
|
||||
m_sgwApp->AddPgw (pgwS5Address);
|
||||
m_pgwApp->AddSgw (sgwS5Address);
|
||||
|
||||
|
||||
// Create S11 link between MME and SGW
|
||||
PointToPointHelper s11P2ph;
|
||||
s11P2ph.SetDeviceAttribute ("DataRate", DataRateValue (m_s11LinkDataRate));
|
||||
s11P2ph.SetDeviceAttribute ("Mtu", UintegerValue (m_s11LinkMtu));
|
||||
s11P2ph.SetChannelAttribute ("Delay", TimeValue (m_s11LinkDelay));
|
||||
NetDeviceContainer mmeSgwDevices = s11P2ph.Install (m_mme, m_sgw);
|
||||
NS_LOG_LOGIC ("MME's IPv4 ifaces after installing p2p dev: " << m_mme->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
NS_LOG_LOGIC ("SGW's IPv4 ifaces after installing p2p dev: " << m_sgw->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
Ptr<NetDevice> mmeDev = mmeSgwDevices.Get (0);
|
||||
Ptr<NetDevice> sgwS11Dev = mmeSgwDevices.Get (1);
|
||||
m_s11Ipv4AddressHelper.NewNetwork ();
|
||||
Ipv4InterfaceContainer mmeSgwIpIfaces = m_s11Ipv4AddressHelper.Assign (mmeSgwDevices);
|
||||
NS_LOG_LOGIC ("MME's IPv4 ifaces after assigning Ipv4 addr to S11 dev: " << m_mme->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
NS_LOG_LOGIC ("SGW's IPv4 ifaces after assigning Ipv4 addr to S11 dev: " << m_sgw->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
|
||||
Ipv4Address mmeS11Address = mmeSgwIpIfaces.GetAddress (0);
|
||||
Ipv4Address sgwS11Address = mmeSgwIpIfaces.GetAddress (1);
|
||||
|
||||
// Create S11 socket in the MME
|
||||
Ptr<Socket> mmeS11Socket = Socket::CreateSocket (m_mme, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
retval = mmeS11Socket->Bind (InetSocketAddress (mmeS11Address, m_gtpcUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// Create S11 socket in the SGW
|
||||
Ptr<Socket> sgwS11Socket = Socket::CreateSocket (m_sgw, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
retval = sgwS11Socket->Bind (InetSocketAddress (sgwS11Address, m_gtpcUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
|
||||
// Create MME Application and connect with SGW via S11 interface
|
||||
m_mmeApp = CreateObject<EpcMmeApplication> ();
|
||||
m_mme->AddApplication (m_mmeApp);
|
||||
m_mmeApp->AddSgw (sgwS11Address, mmeS11Address, mmeS11Socket);
|
||||
m_sgwApp->AddMme (mmeS11Address, sgwS11Socket);
|
||||
}
|
||||
|
||||
NoBackhaulEpcHelper::~NoBackhaulEpcHelper ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
TypeId
|
||||
NoBackhaulEpcHelper::GetTypeId (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
static TypeId tid = TypeId ("ns3::NoBackhaulEpcHelper")
|
||||
.SetParent<EpcHelper> ()
|
||||
.SetGroupName("Lte")
|
||||
.AddConstructor<NoBackhaulEpcHelper> ()
|
||||
.AddAttribute ("S5LinkDataRate",
|
||||
"The data rate to be used for the next S5 link to be created",
|
||||
DataRateValue (DataRate ("10Gb/s")),
|
||||
MakeDataRateAccessor (&NoBackhaulEpcHelper::m_s5LinkDataRate),
|
||||
MakeDataRateChecker ())
|
||||
.AddAttribute ("S5LinkDelay",
|
||||
"The delay to be used for the next S5 link to be created",
|
||||
TimeValue (Seconds (0)),
|
||||
MakeTimeAccessor (&NoBackhaulEpcHelper::m_s5LinkDelay),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("S5LinkMtu",
|
||||
"The MTU of the next S5 link to be created",
|
||||
UintegerValue (2000),
|
||||
MakeUintegerAccessor (&NoBackhaulEpcHelper::m_s5LinkMtu),
|
||||
MakeUintegerChecker<uint16_t> ())
|
||||
.AddAttribute ("S11LinkDataRate",
|
||||
"The data rate to be used for the next S11 link to be created",
|
||||
DataRateValue (DataRate ("10Gb/s")),
|
||||
MakeDataRateAccessor (&NoBackhaulEpcHelper::m_s11LinkDataRate),
|
||||
MakeDataRateChecker ())
|
||||
.AddAttribute ("S11LinkDelay",
|
||||
"The delay to be used for the next S11 link to be created",
|
||||
TimeValue (Seconds (0)),
|
||||
MakeTimeAccessor (&NoBackhaulEpcHelper::m_s11LinkDelay),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("S11LinkMtu",
|
||||
"The MTU of the next S11 link to be created.",
|
||||
UintegerValue (2000),
|
||||
MakeUintegerAccessor (&NoBackhaulEpcHelper::m_s11LinkMtu),
|
||||
MakeUintegerChecker<uint16_t> ())
|
||||
.AddAttribute ("X2LinkDataRate",
|
||||
"The data rate to be used for the next X2 link to be created",
|
||||
DataRateValue (DataRate ("10Gb/s")),
|
||||
MakeDataRateAccessor (&NoBackhaulEpcHelper::m_x2LinkDataRate),
|
||||
MakeDataRateChecker ())
|
||||
.AddAttribute ("X2LinkDelay",
|
||||
"The delay to be used for the next X2 link to be created",
|
||||
TimeValue (Seconds (0)),
|
||||
MakeTimeAccessor (&NoBackhaulEpcHelper::m_x2LinkDelay),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("X2LinkMtu",
|
||||
"The MTU of the next X2 link to be created. Note that, because of some big X2 messages, you need a big MTU.",
|
||||
UintegerValue (3000),
|
||||
MakeUintegerAccessor (&NoBackhaulEpcHelper::m_x2LinkMtu),
|
||||
MakeUintegerChecker<uint16_t> ())
|
||||
.AddAttribute ("X2LinkPcapPrefix",
|
||||
"Prefix for Pcap generated by X2 link",
|
||||
StringValue ("x2"),
|
||||
MakeStringAccessor (&NoBackhaulEpcHelper::m_x2LinkPcapPrefix),
|
||||
MakeStringChecker ())
|
||||
.AddAttribute ("X2LinkEnablePcap",
|
||||
"Enable Pcap for X2 link",
|
||||
BooleanValue (false),
|
||||
MakeBooleanAccessor (&NoBackhaulEpcHelper::m_x2LinkEnablePcap),
|
||||
MakeBooleanChecker ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
TypeId
|
||||
NoBackhaulEpcHelper::GetInstanceTypeId () const
|
||||
{
|
||||
return GetTypeId ();
|
||||
}
|
||||
|
||||
void
|
||||
NoBackhaulEpcHelper::DoDispose ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_tunDevice->SetSendCallback (MakeNullCallback<bool, Ptr<Packet>, const Address&, const Address&, uint16_t> ());
|
||||
m_tunDevice = 0;
|
||||
m_sgwApp = 0;
|
||||
m_sgw->Dispose ();
|
||||
m_pgwApp = 0;
|
||||
m_pgw->Dispose ();
|
||||
m_mmeApp = 0;
|
||||
m_mme->Dispose ();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NoBackhaulEpcHelper::AddEnb (Ptr<Node> enb, Ptr<NetDevice> lteEnbNetDevice, uint16_t cellId)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << enb << lteEnbNetDevice << cellId);
|
||||
NS_ASSERT (enb == lteEnbNetDevice->GetNode ());
|
||||
|
||||
int retval;
|
||||
|
||||
// add an IPv4 stack to the previously created eNB
|
||||
InternetStackHelper internet;
|
||||
internet.Install (enb);
|
||||
NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB after node creation: " << enb->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
|
||||
// create LTE socket for the ENB
|
||||
Ptr<Socket> enbLteSocket = Socket::CreateSocket (enb, TypeId::LookupByName ("ns3::PacketSocketFactory"));
|
||||
PacketSocketAddress enbLteSocketBindAddress;
|
||||
enbLteSocketBindAddress.SetSingleDevice (lteEnbNetDevice->GetIfIndex ());
|
||||
enbLteSocketBindAddress.SetProtocol (Ipv4L3Protocol::PROT_NUMBER);
|
||||
retval = enbLteSocket->Bind (enbLteSocketBindAddress);
|
||||
NS_ASSERT (retval == 0);
|
||||
PacketSocketAddress enbLteSocketConnectAddress;
|
||||
enbLteSocketConnectAddress.SetPhysicalAddress (Mac48Address::GetBroadcast ());
|
||||
enbLteSocketConnectAddress.SetSingleDevice (lteEnbNetDevice->GetIfIndex ());
|
||||
enbLteSocketConnectAddress.SetProtocol (Ipv4L3Protocol::PROT_NUMBER);
|
||||
retval = enbLteSocket->Connect (enbLteSocketConnectAddress);
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// create LTE socket for the ENB
|
||||
Ptr<Socket> enbLteSocket6 = Socket::CreateSocket (enb, TypeId::LookupByName ("ns3::PacketSocketFactory"));
|
||||
PacketSocketAddress enbLteSocketBindAddress6;
|
||||
enbLteSocketBindAddress6.SetSingleDevice (lteEnbNetDevice->GetIfIndex ());
|
||||
enbLteSocketBindAddress6.SetProtocol (Ipv6L3Protocol::PROT_NUMBER);
|
||||
retval = enbLteSocket6->Bind (enbLteSocketBindAddress6);
|
||||
NS_ASSERT (retval == 0);
|
||||
PacketSocketAddress enbLteSocketConnectAddress6;
|
||||
enbLteSocketConnectAddress6.SetPhysicalAddress (Mac48Address::GetBroadcast ());
|
||||
enbLteSocketConnectAddress6.SetSingleDevice (lteEnbNetDevice->GetIfIndex ());
|
||||
enbLteSocketConnectAddress6.SetProtocol (Ipv6L3Protocol::PROT_NUMBER);
|
||||
retval = enbLteSocket6->Connect (enbLteSocketConnectAddress6);
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
NS_LOG_INFO ("Create EpcEnbApplication");
|
||||
Ptr<EpcEnbApplication> enbApp = CreateObject<EpcEnbApplication> (enbLteSocket, enbLteSocket6, cellId);
|
||||
enb->AddApplication (enbApp);
|
||||
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> ();
|
||||
enb->AggregateObject (x2);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NoBackhaulEpcHelper::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
|
||||
PointToPointHelper p2ph;
|
||||
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 ());
|
||||
|
||||
if (m_x2LinkEnablePcap)
|
||||
{
|
||||
p2ph.EnablePcapAll (m_x2LinkPcapPrefix);
|
||||
}
|
||||
|
||||
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 enb1X2Address = enbIpIfaces.GetAddress (0);
|
||||
Ipv4Address enb2X2Address = enbIpIfaces.GetAddress (1);
|
||||
|
||||
// Add X2 interface to both eNBs' X2 entities
|
||||
Ptr<EpcX2> enb1X2 = enb1->GetObject<EpcX2> ();
|
||||
Ptr<EpcX2> enb2X2 = enb2->GetObject<EpcX2> ();
|
||||
|
||||
Ptr<NetDevice> enb1LteDev = enb1->GetDevice (0);
|
||||
Ptr<NetDevice> enb2LteDev = enb2->GetDevice (0);
|
||||
|
||||
DoAddX2Interface (enb1X2, enb1LteDev, enb1X2Address, enb2X2, enb2LteDev, enb2X2Address);
|
||||
}
|
||||
|
||||
void
|
||||
NoBackhaulEpcHelper::DoAddX2Interface (const Ptr<EpcX2> &enb1X2, const Ptr<NetDevice> &enb1LteDev,
|
||||
const Ipv4Address &enb1X2Address,
|
||||
const Ptr<EpcX2> &enb2X2, const Ptr<NetDevice> &enb2LteDev,
|
||||
const Ipv4Address &enb2X2Address) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
Ptr<LteEnbNetDevice> enb1LteDevice = enb1LteDev->GetObject<LteEnbNetDevice> ();
|
||||
Ptr<LteEnbNetDevice> enb2LteDevice = enb2LteDev->GetObject<LteEnbNetDevice> ();
|
||||
|
||||
NS_ABORT_MSG_IF (enb1LteDevice == nullptr , "Unable to find LteEnbNetDevice for the first eNB");
|
||||
NS_ABORT_MSG_IF (enb2LteDevice == nullptr , "Unable to find LteEnbNetDevice for the second eNB");
|
||||
|
||||
uint16_t enb1CellId = enb1LteDevice->GetCellId ();
|
||||
uint16_t enb2CellId = enb2LteDevice->GetCellId ();
|
||||
|
||||
NS_LOG_LOGIC ("LteEnbNetDevice #1 = " << enb1LteDev << " - CellId = " << enb1CellId);
|
||||
NS_LOG_LOGIC ("LteEnbNetDevice #2 = " << enb2LteDev << " - CellId = " << enb2CellId);
|
||||
|
||||
enb1X2->AddX2Interface (enb1CellId, enb1X2Address, enb2CellId, enb2X2Address);
|
||||
enb2X2->AddX2Interface (enb2CellId, enb2X2Address, enb1CellId, enb1X2Address);
|
||||
|
||||
enb1LteDevice->GetRrc ()->AddX2Neighbour (enb2CellId);
|
||||
enb2LteDevice->GetRrc ()->AddX2Neighbour (enb1CellId);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NoBackhaulEpcHelper::AddUe (Ptr<NetDevice> ueDevice, uint64_t imsi)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << imsi << ueDevice);
|
||||
|
||||
m_mmeApp->AddUe (imsi);
|
||||
m_pgwApp->AddUe (imsi);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
NoBackhaulEpcHelper::ActivateEpsBearer (Ptr<NetDevice> ueDevice, uint64_t imsi,
|
||||
Ptr<EpcTft> tft, EpsBearer bearer)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << ueDevice << imsi);
|
||||
|
||||
// we now retrieve the IPv4/IPv6 address of the UE and notify it to the SGW;
|
||||
// we couldn't do it before since address assignment is triggered by
|
||||
// the user simulation program, rather than done by the EPC
|
||||
Ptr<Node> ueNode = ueDevice->GetNode ();
|
||||
Ptr<Ipv4> ueIpv4 = ueNode->GetObject<Ipv4> ();
|
||||
Ptr<Ipv6> ueIpv6 = ueNode->GetObject<Ipv6> ();
|
||||
NS_ASSERT_MSG (ueIpv4 != 0 || ueIpv6 != 0, "UEs need to have IPv4/IPv6 installed before EPS bearers can be activated");
|
||||
|
||||
if (ueIpv4)
|
||||
{
|
||||
int32_t interface = ueIpv4->GetInterfaceForDevice (ueDevice);
|
||||
if (interface >= 0 && ueIpv4->GetNAddresses (interface) == 1)
|
||||
{
|
||||
Ipv4Address ueAddr = ueIpv4->GetAddress (interface, 0).GetLocal ();
|
||||
NS_LOG_LOGIC (" UE IPv4 address: " << ueAddr);
|
||||
m_pgwApp->SetUeAddress (imsi, ueAddr);
|
||||
}
|
||||
}
|
||||
if (ueIpv6)
|
||||
{
|
||||
int32_t interface6 = ueIpv6->GetInterfaceForDevice (ueDevice);
|
||||
if (interface6 >= 0 && ueIpv6->GetNAddresses (interface6) == 2)
|
||||
{
|
||||
Ipv6Address ueAddr6 = ueIpv6->GetAddress (interface6, 1).GetAddress ();
|
||||
NS_LOG_LOGIC (" UE IPv6 address: " << ueAddr6);
|
||||
m_pgwApp->SetUeAddress6 (imsi, ueAddr6);
|
||||
}
|
||||
}
|
||||
uint8_t bearerId = m_mmeApp->AddBearer (imsi, tft, bearer);
|
||||
DoActivateEpsBearerForUe (ueDevice, tft, bearer);
|
||||
|
||||
return bearerId;
|
||||
}
|
||||
|
||||
void
|
||||
NoBackhaulEpcHelper::DoActivateEpsBearerForUe (const Ptr<NetDevice> &ueDevice,
|
||||
const Ptr<EpcTft> &tft,
|
||||
const EpsBearer &bearer) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
Ptr<LteUeNetDevice> ueLteDevice = DynamicCast<LteUeNetDevice> (ueDevice);
|
||||
if (ueLteDevice == nullptr)
|
||||
{
|
||||
// You may wonder why this is not an assert. Well, take a look in epc-test-s1u-downlink
|
||||
// and -uplink: we are using CSMA to simulate UEs.
|
||||
NS_LOG_WARN ("Unable to find LteUeNetDevice while activating the EPS bearer");
|
||||
}
|
||||
else
|
||||
{
|
||||
Simulator::ScheduleNow (&EpcUeNas::ActivateEpsBearer, ueLteDevice->GetNas (), bearer, tft);
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<Node>
|
||||
NoBackhaulEpcHelper::GetPgwNode () const
|
||||
{
|
||||
return m_pgw;
|
||||
}
|
||||
|
||||
Ipv4InterfaceContainer
|
||||
NoBackhaulEpcHelper::AssignUeIpv4Address (NetDeviceContainer ueDevices)
|
||||
{
|
||||
return m_uePgwAddressHelper.Assign (ueDevices);
|
||||
}
|
||||
|
||||
Ipv6InterfaceContainer
|
||||
NoBackhaulEpcHelper::AssignUeIpv6Address (NetDeviceContainer ueDevices)
|
||||
{
|
||||
for (NetDeviceContainer::Iterator iter = ueDevices.Begin ();
|
||||
iter != ueDevices.End ();
|
||||
iter ++)
|
||||
{
|
||||
Ptr<Icmpv6L4Protocol> icmpv6 = (*iter)->GetNode ()->GetObject<Icmpv6L4Protocol> ();
|
||||
icmpv6->SetAttribute ("DAD", BooleanValue (false));
|
||||
}
|
||||
return m_uePgwAddressHelper6.Assign (ueDevices);
|
||||
}
|
||||
|
||||
Ipv4Address
|
||||
NoBackhaulEpcHelper::GetUeDefaultGatewayAddress ()
|
||||
{
|
||||
// return the address of the tun device
|
||||
return m_pgw->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ();
|
||||
}
|
||||
|
||||
Ipv6Address
|
||||
NoBackhaulEpcHelper::GetUeDefaultGatewayAddress6 ()
|
||||
{
|
||||
// return the address of the tun device
|
||||
return m_pgw->GetObject<Ipv6> ()->GetAddress (1, 1).GetAddress ();
|
||||
}
|
||||
|
||||
|
||||
Ptr<Node>
|
||||
NoBackhaulEpcHelper::GetSgwNode () const
|
||||
{
|
||||
return m_sgw;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NoBackhaulEpcHelper::AddS1Interface (Ptr<Node> enb, Ipv4Address enbAddress, Ipv4Address sgwAddress, uint16_t cellId)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << enb << enbAddress << sgwAddress << cellId);
|
||||
|
||||
// create S1-U socket for the ENB
|
||||
Ptr<Socket> enbS1uSocket = Socket::CreateSocket (enb, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
int retval = enbS1uSocket->Bind (InetSocketAddress (enbAddress, m_gtpuUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
Ptr<EpcEnbApplication> enbApp = enb->GetApplication (0)->GetObject<EpcEnbApplication> ();
|
||||
NS_ASSERT_MSG (enbApp != 0, "EpcEnbApplication not available");
|
||||
enbApp->AddS1Interface (enbS1uSocket, enbAddress, sgwAddress);
|
||||
|
||||
NS_LOG_INFO ("Connect S1-AP interface");
|
||||
if (cellId == 0)
|
||||
{
|
||||
Ptr<LteEnbNetDevice> enbLteDev = enb->GetDevice (0)->GetObject<LteEnbNetDevice> ();
|
||||
NS_ASSERT_MSG (enbLteDev, "LteEnbNetDevice is missing");
|
||||
cellId = enbLteDev->GetCellId ();
|
||||
}
|
||||
m_mmeApp->AddEnb (cellId, enbAddress, enbApp->GetS1apSapEnb ());
|
||||
m_sgwApp->AddEnb (cellId, enbAddress, sgwAddress);
|
||||
enbApp->SetS1apSapMme (m_mmeApp->GetS1apSapMme ());
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
247
src/lte/helper/no-backhaul-epc-helper.h
Normal file
247
src/lte/helper/no-backhaul-epc-helper.h
Normal file
@@ -0,0 +1,247 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2019 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 <manuel.requena@cttc.es>
|
||||
* (based on the original point-to-point-epc-helper.h)
|
||||
*/
|
||||
|
||||
#ifndef NO_BACKHAUL_EPC_HELPER_H
|
||||
#define NO_BACKHAUL_EPC_HELPER_H
|
||||
|
||||
#include "ns3/epc-helper.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class EpcSgwApplication;
|
||||
class EpcPgwApplication;
|
||||
class EpcMmeApplication;
|
||||
|
||||
/**
|
||||
* \ingroup lte
|
||||
* \brief Create an EPC network with PointToPoint links between the core network nodes.
|
||||
*
|
||||
* This Helper will create an EPC network topology comprising of
|
||||
* three nodes: SGW, PGW and MME.
|
||||
* The X2-U, X2-C, S5 and S11 interfaces are realized over PointToPoint links.
|
||||
*
|
||||
* The S1 interface is not created. So, no backhaul network is built.
|
||||
* You have to build your own backhaul network in the simulation program.
|
||||
* Or you can use PointToPointEpcHelper or CsmaEpcHelper
|
||||
* (instead of this NoBackhaulEpcHelper) to use reference backhaul networks.
|
||||
*/
|
||||
class NoBackhaulEpcHelper : public EpcHelper
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
NoBackhaulEpcHelper ();
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~NoBackhaulEpcHelper ();
|
||||
|
||||
// inherited from Object
|
||||
/**
|
||||
* Register this type.
|
||||
* \return The object TypeId.
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
TypeId GetInstanceTypeId () const;
|
||||
virtual void DoDispose ();
|
||||
|
||||
// inherited from EpcHelper
|
||||
virtual void AddEnb (Ptr<Node> enbNode, Ptr<NetDevice> lteEnbNetDevice, uint16_t cellId);
|
||||
virtual void AddUe (Ptr<NetDevice> ueLteDevice, uint64_t imsi);
|
||||
virtual void AddX2Interface (Ptr<Node> enbNode1, Ptr<Node> enbNode2);
|
||||
virtual void AddS1Interface (Ptr<Node> enb, Ipv4Address enbAddress, Ipv4Address sgwAddress, uint16_t cellId = 0);
|
||||
virtual uint8_t ActivateEpsBearer (Ptr<NetDevice> ueLteDevice, uint64_t imsi, Ptr<EpcTft> tft, EpsBearer bearer);
|
||||
virtual Ptr<Node> GetSgwNode () const;
|
||||
virtual Ptr<Node> GetPgwNode () const;
|
||||
virtual Ipv4InterfaceContainer AssignUeIpv4Address (NetDeviceContainer ueDevices);
|
||||
virtual Ipv6InterfaceContainer AssignUeIpv6Address (NetDeviceContainer ueDevices);
|
||||
virtual Ipv4Address GetUeDefaultGatewayAddress ();
|
||||
virtual Ipv6Address GetUeDefaultGatewayAddress6 ();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \brief DoAddX2Interface: Call AddX2Interface on top of the Enb device pointers
|
||||
*
|
||||
* \param enb1X2 EPCX2 of ENB1
|
||||
* \param enb1LteDev LTE device of ENB1
|
||||
* \param enb1X2Address Address for ENB1
|
||||
* \param enb2X2 EPCX2 of ENB2
|
||||
* \param enb2LteDev LTE device of ENB2
|
||||
* \param enb2X2Address Address for ENB2
|
||||
*/
|
||||
virtual void DoAddX2Interface(const Ptr<EpcX2> &enb1X2, const Ptr<NetDevice> &enb1LteDev,
|
||||
const Ipv4Address &enb1X2Address,
|
||||
const Ptr<EpcX2> &enb2X2, const Ptr<NetDevice> &enb2LteDev,
|
||||
const Ipv4Address &enb2X2Address) const;
|
||||
|
||||
/**
|
||||
* \brief DoActivateEpsBearerForUe: Schedule ActivateEpsBearer on the UE
|
||||
* \param ueDevice LTE device for the UE
|
||||
* \param tft TFT
|
||||
* \param bearer Bearer
|
||||
*/
|
||||
virtual void DoActivateEpsBearerForUe (const Ptr<NetDevice> &ueDevice,
|
||||
const Ptr<EpcTft> &tft,
|
||||
const EpsBearer &bearer) const;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* helper to assign IPv4 addresses to UE devices as well as to the TUN device of the SGW/PGW
|
||||
*/
|
||||
Ipv4AddressHelper m_uePgwAddressHelper;
|
||||
/**
|
||||
* helper to assign IPv6 addresses to UE devices as well as to the TUN device of the SGW/PGW
|
||||
*/
|
||||
Ipv6AddressHelper m_uePgwAddressHelper6;
|
||||
|
||||
/**
|
||||
* PGW network element
|
||||
*/
|
||||
Ptr<Node> m_pgw;
|
||||
|
||||
/**
|
||||
* SGW network element
|
||||
*/
|
||||
Ptr<Node> m_sgw;
|
||||
|
||||
/**
|
||||
* MME network element
|
||||
*/
|
||||
Ptr<Node> m_mme;
|
||||
|
||||
/**
|
||||
* SGW application
|
||||
*/
|
||||
Ptr<EpcSgwApplication> m_sgwApp;
|
||||
|
||||
/**
|
||||
* PGW application
|
||||
*/
|
||||
Ptr<EpcPgwApplication> m_pgwApp;
|
||||
|
||||
/**
|
||||
* MME application
|
||||
*/
|
||||
Ptr<EpcMmeApplication> m_mmeApp;
|
||||
|
||||
/**
|
||||
* TUN device implementing tunneling of user data over GTP-U/UDP/IP
|
||||
*/
|
||||
Ptr<VirtualNetDevice> m_tunDevice;
|
||||
|
||||
/**
|
||||
* UDP port where the GTP-U Socket is bound, fixed by the standard as 2152
|
||||
*/
|
||||
uint16_t m_gtpuUdpPort;
|
||||
|
||||
/**
|
||||
* Helper to assign addresses to S11 NetDevices
|
||||
*/
|
||||
Ipv4AddressHelper m_s11Ipv4AddressHelper;
|
||||
|
||||
/**
|
||||
* The data rate to be used for the next S11 link to be created
|
||||
*/
|
||||
DataRate m_s11LinkDataRate;
|
||||
|
||||
/**
|
||||
* The delay to be used for the next S11 link to be created
|
||||
*/
|
||||
Time m_s11LinkDelay;
|
||||
|
||||
/**
|
||||
* The MTU of the next S11 link to be created
|
||||
*/
|
||||
uint16_t m_s11LinkMtu;
|
||||
|
||||
/**
|
||||
* UDP port where the GTPv2-C Socket is bound, fixed by the standard as 2123
|
||||
*/
|
||||
uint16_t m_gtpcUdpPort;
|
||||
|
||||
/**
|
||||
* S5 interfaces
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helper to assign addresses to S5 NetDevices
|
||||
*/
|
||||
Ipv4AddressHelper m_s5Ipv4AddressHelper;
|
||||
|
||||
/**
|
||||
* The data rate to be used for the next S5 link to be created
|
||||
*/
|
||||
DataRate m_s5LinkDataRate;
|
||||
|
||||
/**
|
||||
* The delay to be used for the next S5 link to be created
|
||||
*/
|
||||
Time m_s5LinkDelay;
|
||||
|
||||
/**
|
||||
* The MTU of the next S5 link to be created
|
||||
*/
|
||||
uint16_t m_s5LinkMtu;
|
||||
|
||||
/**
|
||||
* Map storing for each IMSI the corresponding eNB NetDevice
|
||||
*/
|
||||
std::map<uint64_t, Ptr<NetDevice> > m_imsiEnbDeviceMap;
|
||||
|
||||
/**
|
||||
* helper to assign addresses to X2 NetDevices
|
||||
*/
|
||||
Ipv4AddressHelper m_x2Ipv4AddressHelper;
|
||||
|
||||
/**
|
||||
* The data rate to be used for the next X2 link to be created
|
||||
*/
|
||||
DataRate m_x2LinkDataRate;
|
||||
|
||||
/**
|
||||
* The delay to be used for the next X2 link to be created
|
||||
*/
|
||||
Time m_x2LinkDelay;
|
||||
|
||||
/**
|
||||
* The MTU of the next X2 link to be created. Note that,
|
||||
* because of some big X2 messages, you need a big MTU.
|
||||
*/
|
||||
uint16_t m_x2LinkMtu;
|
||||
|
||||
/**
|
||||
* Enable PCAP generation for X2 link
|
||||
*/
|
||||
bool m_x2LinkEnablePcap;
|
||||
|
||||
/**
|
||||
* Prefix for the PCAP file for the X2 link
|
||||
*/
|
||||
std::string m_x2LinkPcapPrefix;
|
||||
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif // NO_BACKHAUL_EPC_HELPER_H
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2011-2018 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
|
||||
* Copyright (c) 2011-2019 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
|
||||
@@ -18,35 +18,15 @@
|
||||
* Author: Jaume Nin <jnin@cttc.es>
|
||||
* Nicola Baldo <nbaldo@cttc.es>
|
||||
* Manuel Requena <manuel.requena@cttc.es>
|
||||
* (most of the code refactored to no-backhaul-epc-helper.cc)
|
||||
*/
|
||||
|
||||
#include <ns3/point-to-point-epc-helper.h>
|
||||
#include <ns3/log.h>
|
||||
#include <ns3/inet-socket-address.h>
|
||||
#include <ns3/mac48-address.h>
|
||||
#include <ns3/string.h>
|
||||
#include <ns3/boolean.h>
|
||||
#include <ns3/eps-bearer.h>
|
||||
#include <ns3/ipv4-address.h>
|
||||
#include <ns3/internet-stack-helper.h>
|
||||
#include <ns3/point-to-point-helper.h>
|
||||
#include <ns3/packet-socket-helper.h>
|
||||
#include <ns3/packet-socket-address.h>
|
||||
#include <ns3/epc-enb-application.h>
|
||||
#include "ns3/ipv6-static-routing.h"
|
||||
#include "ns3/ipv6-static-routing-helper.h"
|
||||
#include <ns3/epc-pgw-application.h>
|
||||
#include <ns3/epc-sgw-application.h>
|
||||
#include <ns3/epc-mme-application.h>
|
||||
#include "ns3/boolean.h"
|
||||
#include "ns3/string.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/point-to-point-helper.h"
|
||||
|
||||
#include <ns3/lte-enb-rrc.h>
|
||||
#include <ns3/epc-x2.h>
|
||||
#include <ns3/lte-enb-net-device.h>
|
||||
#include <ns3/lte-ue-net-device.h>
|
||||
#include <ns3/epc-ue-nas.h>
|
||||
#include <ns3/ipv4-address-generator.h>
|
||||
#include <ns3/ipv6-address-generator.h>
|
||||
#include <ns3/icmpv6-l4-protocol.h>
|
||||
#include "ns3/point-to-point-epc-helper.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -55,181 +35,18 @@ NS_LOG_COMPONENT_DEFINE ("PointToPointEpcHelper");
|
||||
NS_OBJECT_ENSURE_REGISTERED (PointToPointEpcHelper);
|
||||
|
||||
|
||||
PointToPointEpcHelper::PointToPointEpcHelper ()
|
||||
: m_gtpuUdpPort (2152), // fixed by the standard
|
||||
m_s11LinkDataRate (DataRate ("10Gb/s")),
|
||||
m_s11LinkDelay (Seconds (0)),
|
||||
m_s11LinkMtu (3000),
|
||||
m_gtpcUdpPort (2123), // fixed by the standard
|
||||
m_s5LinkDataRate (DataRate ("10Gb/s")),
|
||||
m_s5LinkDelay (Seconds (0)),
|
||||
m_s5LinkMtu (3000)
|
||||
PointToPointEpcHelper::PointToPointEpcHelper ()
|
||||
: NoBackhaulEpcHelper ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
// To access the attribute value within the constructor
|
||||
ObjectBase::ConstructSelf (AttributeConstructionList ());
|
||||
|
||||
int retval;
|
||||
// since we use point-to-point links for all links,
|
||||
// we use a /30 subnet which can hold exactly two addresses
|
||||
// since we use point-to-point links for the backhaul links,
|
||||
// we use a /30 subnet which can hold exactly two addresses
|
||||
// (remember that net broadcast and null address are not valid)
|
||||
m_s1uIpv4AddressHelper.SetBase ("10.0.0.0", "255.255.255.252");
|
||||
|
||||
m_s1apIpv4AddressHelper.SetBase ("11.0.0.0", "255.255.255.252");
|
||||
m_x2Ipv4AddressHelper.SetBase ("12.0.0.0", "255.255.255.252");
|
||||
m_s11Ipv4AddressHelper.SetBase ("13.0.0.0", "255.255.255.252");
|
||||
m_s5Ipv4AddressHelper.SetBase ("14.0.0.0", "255.255.255.252");
|
||||
|
||||
// we use a /8 net for all UEs
|
||||
m_uePgwAddressHelper.SetBase ("7.0.0.0", "255.0.0.0");
|
||||
|
||||
// we use a /64 IPv6 net all UEs
|
||||
m_uePgwAddressHelper6.SetBase ("7777:f00d::", Ipv6Prefix (64));
|
||||
|
||||
// Create PGW, SGW and MME nodes
|
||||
m_pgw = CreateObject<Node> ();
|
||||
m_sgw = CreateObject<Node> ();
|
||||
m_mme = CreateObject<Node> ();
|
||||
InternetStackHelper internet;
|
||||
internet.Install (m_pgw);
|
||||
internet.Install (m_sgw);
|
||||
internet.Install (m_mme);
|
||||
|
||||
// The Tun device resides in different 64 bit subnet.
|
||||
// We must create an unique route to tun device for all the packets destined
|
||||
// to all 64 bit IPv6 prefixes of UEs, based by the unique 48 bit network prefix of this EPC network
|
||||
Ipv6StaticRoutingHelper ipv6RoutingHelper;
|
||||
Ptr<Ipv6StaticRouting> pgwStaticRouting = ipv6RoutingHelper.GetStaticRouting (m_pgw->GetObject<Ipv6> ());
|
||||
pgwStaticRouting->AddNetworkRouteTo ("7777:f00d::", Ipv6Prefix (64), Ipv6Address ("::"), 1, 0);
|
||||
|
||||
// create TUN device implementing tunneling of user data over GTP-U/UDP/IP in the PGW
|
||||
m_tunDevice = CreateObject<VirtualNetDevice> ();
|
||||
|
||||
// allow jumbo packets
|
||||
m_tunDevice->SetAttribute ("Mtu", UintegerValue (30000));
|
||||
|
||||
// yes we need this
|
||||
m_tunDevice->SetAddress (Mac48Address::Allocate ());
|
||||
|
||||
m_pgw->AddDevice (m_tunDevice);
|
||||
NetDeviceContainer tunDeviceContainer;
|
||||
tunDeviceContainer.Add (m_tunDevice);
|
||||
// the TUN device is on the same subnet as the UEs, so when a packet
|
||||
// addressed to an UE arrives at the intenet to the WAN interface of
|
||||
// the PGW it will be forwarded to the TUN device.
|
||||
Ipv4InterfaceContainer tunDeviceIpv4IfContainer = AssignUeIpv4Address (tunDeviceContainer);
|
||||
|
||||
|
||||
// the TUN device for IPv6 address is on the different subnet as the
|
||||
// UEs, it will forward the UE packets as we have inserted the route
|
||||
// for all UEs at the time of assigning UE addresses
|
||||
Ipv6InterfaceContainer tunDeviceIpv6IfContainer = AssignUeIpv6Address (tunDeviceContainer);
|
||||
|
||||
|
||||
//Set Forwarding of the IPv6 interface
|
||||
tunDeviceIpv6IfContainer.SetForwarding (0,true);
|
||||
tunDeviceIpv6IfContainer.SetDefaultRouteInAllNodes (0);
|
||||
|
||||
// Create S5 link between PGW and SGW
|
||||
NodeContainer pgwSgwNodes;
|
||||
pgwSgwNodes.Add (m_pgw);
|
||||
pgwSgwNodes.Add (m_sgw);
|
||||
PointToPointHelper p2ph;
|
||||
p2ph.SetDeviceAttribute ("DataRate", DataRateValue (m_s5LinkDataRate));
|
||||
p2ph.SetDeviceAttribute ("Mtu", UintegerValue (m_s5LinkMtu));
|
||||
p2ph.SetChannelAttribute ("Delay", TimeValue (m_s5LinkDelay));
|
||||
NetDeviceContainer pgwSgwDevices = p2ph.Install (m_pgw, m_sgw);
|
||||
NS_LOG_LOGIC ("IPv4 ifaces of the PGW after installing p2p dev: " << m_pgw->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
NS_LOG_LOGIC ("IPv4 ifaces of the SGW after installing p2p dev: " << m_sgw->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
Ptr<NetDevice> pgwDev = pgwSgwDevices.Get (0);
|
||||
Ptr<NetDevice> sgwDev = pgwSgwDevices.Get (1);
|
||||
m_s5Ipv4AddressHelper.NewNetwork ();
|
||||
Ipv4InterfaceContainer pgwSgwIpIfaces = m_s5Ipv4AddressHelper.Assign (pgwSgwDevices);
|
||||
NS_LOG_LOGIC ("IPv4 ifaces of the PGW after assigning Ipv4 addr to S5 dev: " << m_pgw->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
NS_LOG_LOGIC ("IPv4 ifaces of the SGW after assigning Ipv4 addr to S5 dev: " << m_sgw->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
|
||||
Ipv4Address pgwS5Address = pgwSgwIpIfaces.GetAddress (0);
|
||||
Ipv4Address sgwS5Address = pgwSgwIpIfaces.GetAddress (1);
|
||||
|
||||
// Create S5-U socket in the PGW
|
||||
Ptr<Socket> pgwS5uSocket = Socket::CreateSocket (m_pgw, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
retval = pgwS5uSocket->Bind (InetSocketAddress (pgwS5Address, m_gtpuUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// Create S5-C socket in the PGW
|
||||
Ptr<Socket> pgwS5cSocket = Socket::CreateSocket (m_pgw, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
retval = pgwS5cSocket->Bind (InetSocketAddress (pgwS5Address, m_gtpcUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// Create EpcPgwApplication
|
||||
m_pgwApp = CreateObject<EpcPgwApplication> (m_tunDevice, pgwS5Address, pgwS5uSocket, pgwS5cSocket);
|
||||
m_pgw->AddApplication (m_pgwApp);
|
||||
|
||||
// Connect EpcPgwApplication and virtual net device for tunneling
|
||||
m_tunDevice->SetSendCallback (MakeCallback (&EpcPgwApplication::RecvFromTunDevice, m_pgwApp));
|
||||
|
||||
|
||||
// Create S5-U socket in the SGW
|
||||
Ptr<Socket> sgwS5uSocket = Socket::CreateSocket (m_sgw, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
retval = sgwS5uSocket->Bind (InetSocketAddress (sgwS5Address, m_gtpuUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// Create S5-C socket in the SGW
|
||||
Ptr<Socket> sgwS5cSocket = Socket::CreateSocket (m_sgw, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
retval = sgwS5cSocket->Bind (InetSocketAddress (sgwS5Address, m_gtpcUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// Create S1-U socket in the SGW
|
||||
Ptr<Socket> sgwS1uSocket = Socket::CreateSocket (m_sgw, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
retval = sgwS1uSocket->Bind (InetSocketAddress (Ipv4Address::GetAny (), m_gtpuUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// Create EpcSgwApplication
|
||||
m_sgwApp = CreateObject<EpcSgwApplication> (sgwS1uSocket, sgwS5Address, sgwS5uSocket, sgwS5cSocket);
|
||||
m_sgw->AddApplication (m_sgwApp);
|
||||
m_sgwApp->AddPgw (pgwS5Address);
|
||||
m_pgwApp->AddSgw (sgwS5Address);
|
||||
|
||||
|
||||
// Create S11 link between MME and SGW
|
||||
NodeContainer mmeSgwNodes;
|
||||
mmeSgwNodes.Add (m_mme);
|
||||
mmeSgwNodes.Add (m_sgw);
|
||||
PointToPointHelper s11P2ph;
|
||||
s11P2ph.SetDeviceAttribute ("DataRate", DataRateValue (m_s11LinkDataRate));
|
||||
s11P2ph.SetDeviceAttribute ("Mtu", UintegerValue (m_s11LinkMtu));
|
||||
s11P2ph.SetChannelAttribute ("Delay", TimeValue (m_s11LinkDelay));
|
||||
NetDeviceContainer mmeSgwDevices = s11P2ph.Install (m_mme, m_sgw);
|
||||
NS_LOG_LOGIC ("MME's IPv4 ifaces after installing p2p dev: " << m_mme->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
NS_LOG_LOGIC ("SGW's IPv4 ifaces after installing p2p dev: " << m_sgw->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
Ptr<NetDevice> mmeDev = mmeSgwDevices.Get (0);
|
||||
Ptr<NetDevice> sgwS11Dev = mmeSgwDevices.Get (1);
|
||||
m_s11Ipv4AddressHelper.NewNetwork ();
|
||||
Ipv4InterfaceContainer mmeSgwIpIfaces = m_s11Ipv4AddressHelper.Assign (mmeSgwDevices);
|
||||
NS_LOG_LOGIC ("MME's IPv4 ifaces after assigning Ipv4 addr to S11 dev: " << m_mme->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
NS_LOG_LOGIC ("SGW's IPv4 ifaces after assigning Ipv4 addr to S11 dev: " << m_sgw->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
|
||||
Ipv4Address mmeS11Address = mmeSgwIpIfaces.GetAddress (0);
|
||||
Ipv4Address sgwS11Address = mmeSgwIpIfaces.GetAddress (1);
|
||||
|
||||
// Create S11 socket in the MME
|
||||
Ptr<Socket> mmeS11Socket = Socket::CreateSocket (m_mme, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
retval = mmeS11Socket->Bind (InetSocketAddress (mmeS11Address, m_gtpcUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// Create S11 socket in the SGW
|
||||
Ptr<Socket> sgwS11Socket = Socket::CreateSocket (m_sgw, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
retval = sgwS11Socket->Bind (InetSocketAddress (sgwS11Address, m_gtpcUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
|
||||
// Create MME Application and connect with SGW via S11 interface
|
||||
m_mmeApp = CreateObject<EpcMmeApplication> ();
|
||||
m_mme->AddApplication (m_mmeApp);
|
||||
// // m_mmeApp->SetS11SapSgw (m_sgwApp->GetS11SapSgw ());
|
||||
// // m_sgwApp->SetS11SapMme (m_mmeApp->GetS11SapMme ());
|
||||
m_mmeApp->AddSgw (sgwS11Address, mmeS11Address, mmeS11Socket);
|
||||
m_sgwApp->AddMme (mmeS11Address, sgwS11Socket);
|
||||
}
|
||||
|
||||
PointToPointEpcHelper::~PointToPointEpcHelper ()
|
||||
@@ -242,88 +59,33 @@ PointToPointEpcHelper::GetTypeId (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
static TypeId tid = TypeId ("ns3::PointToPointEpcHelper")
|
||||
.SetParent<EpcHelper> ()
|
||||
.SetGroupName("Lte")
|
||||
.SetParent<NoBackhaulEpcHelper> ()
|
||||
.SetGroupName ("Lte")
|
||||
.AddConstructor<PointToPointEpcHelper> ()
|
||||
.AddAttribute ("S1uLinkDataRate",
|
||||
.AddAttribute ("S1uLinkDataRate",
|
||||
"The data rate to be used for the next S1-U link to be created",
|
||||
DataRateValue (DataRate ("10Gb/s")),
|
||||
MakeDataRateAccessor (&PointToPointEpcHelper::m_s1uLinkDataRate),
|
||||
MakeDataRateChecker ())
|
||||
.AddAttribute ("S1uLinkDelay",
|
||||
.AddAttribute ("S1uLinkDelay",
|
||||
"The delay to be used for the next S1-U link to be created",
|
||||
TimeValue (Seconds (0)),
|
||||
MakeTimeAccessor (&PointToPointEpcHelper::m_s1uLinkDelay),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("S1uLinkMtu",
|
||||
.AddAttribute ("S1uLinkMtu",
|
||||
"The MTU of the next S1-U link to be created. Note that, because of the additional GTP/UDP/IP tunneling overhead, you need a MTU larger than the end-to-end MTU that you want to support.",
|
||||
UintegerValue (2000),
|
||||
MakeUintegerAccessor (&PointToPointEpcHelper::m_s1uLinkMtu),
|
||||
MakeUintegerChecker<uint16_t> ())
|
||||
.AddAttribute ("S5LinkDataRate",
|
||||
"The data rate to be used for the next S5 link to be created",
|
||||
DataRateValue (DataRate ("10Gb/s")),
|
||||
MakeDataRateAccessor (&PointToPointEpcHelper::m_s5LinkDataRate),
|
||||
MakeDataRateChecker ())
|
||||
.AddAttribute ("S5LinkDelay",
|
||||
"The delay to be used for the next S5 link to be created",
|
||||
TimeValue (Seconds (0)),
|
||||
MakeTimeAccessor (&PointToPointEpcHelper::m_s5LinkDelay),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("S5LinkMtu",
|
||||
"The MTU of the next S5 link to be created",
|
||||
UintegerValue (2000),
|
||||
MakeUintegerAccessor (&PointToPointEpcHelper::m_s5LinkMtu),
|
||||
MakeUintegerChecker<uint16_t> ())
|
||||
.AddAttribute ("S11LinkDataRate",
|
||||
"The data rate to be used for the next S11 link to be created",
|
||||
DataRateValue (DataRate ("10Gb/s")),
|
||||
MakeDataRateAccessor (&PointToPointEpcHelper::m_s11LinkDataRate),
|
||||
MakeDataRateChecker ())
|
||||
.AddAttribute ("S11LinkDelay",
|
||||
"The delay to be used for the next S11 link to be created",
|
||||
TimeValue (Seconds (0)),
|
||||
MakeTimeAccessor (&PointToPointEpcHelper::m_s11LinkDelay),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("S11LinkMtu",
|
||||
"The MTU of the next S11 link to be created.",
|
||||
UintegerValue (2000),
|
||||
MakeUintegerAccessor (&PointToPointEpcHelper::m_s11LinkMtu),
|
||||
MakeUintegerChecker<uint16_t> ())
|
||||
.AddAttribute ("X2LinkDataRate",
|
||||
"The data rate to be used for the next X2 link to be created",
|
||||
DataRateValue (DataRate ("10Gb/s")),
|
||||
MakeDataRateAccessor (&PointToPointEpcHelper::m_x2LinkDataRate),
|
||||
MakeDataRateChecker ())
|
||||
.AddAttribute ("X2LinkDelay",
|
||||
"The delay to be used for the next X2 link to be created",
|
||||
TimeValue (Seconds (0)),
|
||||
MakeTimeAccessor (&PointToPointEpcHelper::m_x2LinkDelay),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("X2LinkMtu",
|
||||
"The MTU of the next X2 link to be created. Note that, because of some big X2 messages, you need a big MTU.",
|
||||
UintegerValue (3000),
|
||||
MakeUintegerAccessor (&PointToPointEpcHelper::m_x2LinkMtu),
|
||||
MakeUintegerChecker<uint16_t> ())
|
||||
.AddAttribute ("S1uLinkPcapPrefix",
|
||||
"Prefix for Pcap generated by S1-U link",
|
||||
StringValue ("s1-u"),
|
||||
StringValue ("s1u"),
|
||||
MakeStringAccessor (&PointToPointEpcHelper::m_s1uLinkPcapPrefix),
|
||||
MakeStringChecker ())
|
||||
.AddAttribute ("X2LinkPcapPrefix",
|
||||
"Prefix for Pcap generated by X2 link",
|
||||
StringValue ("x2"),
|
||||
MakeStringAccessor (&PointToPointEpcHelper::m_x2LinkPcapPrefix),
|
||||
MakeStringChecker ())
|
||||
.AddAttribute ("X2LinkEnablePcap",
|
||||
"Enable Pcap for X2 link",
|
||||
BooleanValue (false),
|
||||
MakeBooleanAccessor (&PointToPointEpcHelper::m_enablePcapOverX2),
|
||||
MakeBooleanChecker ())
|
||||
.AddAttribute ("S1uLinkEnablePcap",
|
||||
"Enable Pcap for X2 link",
|
||||
BooleanValue (false),
|
||||
MakeBooleanAccessor (&PointToPointEpcHelper::m_enablePcapOverS1U),
|
||||
MakeBooleanAccessor (&PointToPointEpcHelper::m_s1uLinkEnablePcap),
|
||||
MakeBooleanChecker ())
|
||||
;
|
||||
return tid;
|
||||
@@ -339,14 +101,7 @@ void
|
||||
PointToPointEpcHelper::DoDispose ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_tunDevice->SetSendCallback (MakeNullCallback<bool, Ptr<Packet>, const Address&, const Address&, uint16_t> ());
|
||||
m_tunDevice = 0;
|
||||
m_sgwApp = 0;
|
||||
m_sgw->Dispose ();
|
||||
m_pgwApp = 0;
|
||||
m_pgw->Dispose ();
|
||||
m_mmeApp = 0;
|
||||
m_mme->Dispose ();
|
||||
NoBackhaulEpcHelper::DoDispose ();
|
||||
}
|
||||
|
||||
|
||||
@@ -355,267 +110,32 @@ PointToPointEpcHelper::AddEnb (Ptr<Node> enb, Ptr<NetDevice> lteEnbNetDevice, ui
|
||||
{
|
||||
NS_LOG_FUNCTION (this << enb << lteEnbNetDevice << cellId);
|
||||
|
||||
NS_ASSERT (enb == lteEnbNetDevice->GetNode ());
|
||||
NoBackhaulEpcHelper::AddEnb (enb, lteEnbNetDevice, cellId);
|
||||
|
||||
// add an IPv4 stack to the previously created eNB
|
||||
InternetStackHelper internet;
|
||||
internet.Install (enb);
|
||||
NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB after node creation: " << enb->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
// create a point to point link between the eNB and the SGW with
|
||||
// the corresponding new NetDevices on each side
|
||||
Ptr<Node> sgw = GetSgwNode ();
|
||||
|
||||
// create a point to point link between the new eNB and the SGW with
|
||||
// the corresponding new NetDevices on each side
|
||||
NodeContainer enbSgwNodes;
|
||||
enbSgwNodes.Add (m_sgw);
|
||||
enbSgwNodes.Add (enb);
|
||||
PointToPointHelper p2ph;
|
||||
p2ph.SetDeviceAttribute ("DataRate", DataRateValue (m_s1uLinkDataRate));
|
||||
p2ph.SetDeviceAttribute ("Mtu", UintegerValue (m_s1uLinkMtu));
|
||||
p2ph.SetChannelAttribute ("Delay", TimeValue (m_s1uLinkDelay));
|
||||
NetDeviceContainer enbSgwDevices = p2ph.Install (enb, m_sgw);
|
||||
NetDeviceContainer enbSgwDevices = p2ph.Install (enb, sgw);
|
||||
NS_LOG_LOGIC ("Ipv4 ifaces of the eNB after installing p2p dev: " << enb->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
Ptr<NetDevice> enbDev = enbSgwDevices.Get (0);
|
||||
Ptr<NetDevice> sgwDev = enbSgwDevices.Get (1);
|
||||
|
||||
if (m_enablePcapOverS1U)
|
||||
if (m_s1uLinkEnablePcap)
|
||||
{
|
||||
p2ph.EnablePcapAll(m_s1uLinkPcapPrefix);
|
||||
p2ph.EnablePcapAll (m_s1uLinkPcapPrefix);
|
||||
}
|
||||
|
||||
m_s1uIpv4AddressHelper.NewNetwork ();
|
||||
Ipv4InterfaceContainer enbSgwIpIfaces = m_s1uIpv4AddressHelper.Assign (enbSgwDevices);
|
||||
NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB after assigning Ipv4 addr to S1 dev: " << enb->GetObject<Ipv4> ()->GetNInterfaces ());
|
||||
|
||||
|
||||
Ipv4Address enbS1uAddress = enbSgwIpIfaces.GetAddress (0);
|
||||
Ipv4Address sgwS1uAddress = enbSgwIpIfaces.GetAddress (1);
|
||||
|
||||
// create S1-U socket for the ENB
|
||||
Ptr<Socket> enbS1uSocket = Socket::CreateSocket (enb, TypeId::LookupByName ("ns3::UdpSocketFactory"));
|
||||
int retval = enbS1uSocket->Bind (InetSocketAddress (enbS1uAddress, m_gtpuUdpPort));
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// give PacketSocket powers to the eNB
|
||||
//PacketSocketHelper packetSocket;
|
||||
//packetSocket.Install (enb);
|
||||
// create LTE socket for the ENB
|
||||
Ptr<Socket> enbLteSocket = Socket::CreateSocket (enb, TypeId::LookupByName ("ns3::PacketSocketFactory"));
|
||||
PacketSocketAddress enbLteSocketBindAddress;
|
||||
enbLteSocketBindAddress.SetSingleDevice (lteEnbNetDevice->GetIfIndex ());
|
||||
enbLteSocketBindAddress.SetProtocol (Ipv4L3Protocol::PROT_NUMBER);
|
||||
retval = enbLteSocket->Bind (enbLteSocketBindAddress);
|
||||
NS_ASSERT (retval == 0);
|
||||
PacketSocketAddress enbLteSocketConnectAddress;
|
||||
enbLteSocketConnectAddress.SetPhysicalAddress (Mac48Address::GetBroadcast ());
|
||||
enbLteSocketConnectAddress.SetSingleDevice (lteEnbNetDevice->GetIfIndex ());
|
||||
enbLteSocketConnectAddress.SetProtocol (Ipv4L3Protocol::PROT_NUMBER);
|
||||
retval = enbLteSocket->Connect (enbLteSocketConnectAddress);
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
// create LTE socket for the ENB
|
||||
Ptr<Socket> enbLteSocket6 = Socket::CreateSocket (enb, TypeId::LookupByName ("ns3::PacketSocketFactory"));
|
||||
PacketSocketAddress enbLteSocketBindAddress6;
|
||||
enbLteSocketBindAddress6.SetSingleDevice (lteEnbNetDevice->GetIfIndex ());
|
||||
enbLteSocketBindAddress6.SetProtocol (Ipv6L3Protocol::PROT_NUMBER);
|
||||
retval = enbLteSocket6->Bind (enbLteSocketBindAddress6);
|
||||
NS_ASSERT (retval == 0);
|
||||
PacketSocketAddress enbLteSocketConnectAddress6;
|
||||
enbLteSocketConnectAddress6.SetPhysicalAddress (Mac48Address::GetBroadcast ());
|
||||
enbLteSocketConnectAddress6.SetSingleDevice (lteEnbNetDevice->GetIfIndex ());
|
||||
enbLteSocketConnectAddress6.SetProtocol (Ipv6L3Protocol::PROT_NUMBER);
|
||||
retval = enbLteSocket6->Connect (enbLteSocketConnectAddress6);
|
||||
NS_ASSERT (retval == 0);
|
||||
|
||||
NS_LOG_INFO ("Create EpcEnbApplication");
|
||||
Ptr<EpcEnbApplication> enbApp = CreateObject<EpcEnbApplication> (enbLteSocket, enbLteSocket6, enbS1uSocket, enbS1uAddress, sgwS1uAddress, cellId);
|
||||
enb->AddApplication (enbApp);
|
||||
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> ();
|
||||
enb->AggregateObject (x2);
|
||||
|
||||
NS_LOG_INFO ("Connect S1-AP interface");
|
||||
m_mmeApp->AddEnb (cellId, enbS1uAddress, enbApp->GetS1apSapEnb ());
|
||||
m_sgwApp->AddEnb (cellId, enbS1uAddress, sgwS1uAddress);
|
||||
enbApp->SetS1apSapMme (m_mmeApp->GetS1apSapMme ());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PointToPointEpcHelper::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
|
||||
PointToPointHelper p2ph;
|
||||
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);
|
||||
|
||||
if (m_enablePcapOverX2)
|
||||
{
|
||||
p2ph.EnablePcapAll(m_x2LinkPcapPrefix);
|
||||
}
|
||||
|
||||
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 enb1X2Address = enbIpIfaces.GetAddress (0);
|
||||
Ipv4Address enb2X2Address = enbIpIfaces.GetAddress (1);
|
||||
|
||||
// Add X2 interface to both eNBs' X2 entities
|
||||
Ptr<EpcX2> enb1X2 = enb1->GetObject<EpcX2> ();
|
||||
Ptr<EpcX2> enb2X2 = enb2->GetObject<EpcX2> ();
|
||||
|
||||
Ptr<NetDevice> enb1LteDev = enb1->GetDevice (0);
|
||||
Ptr<NetDevice> enb2LteDev = enb2->GetDevice (0);
|
||||
|
||||
DoAddX2Interface (enb1X2, enb1LteDev, enb1X2Address, enb2X2, enb2LteDev, enb2X2Address);
|
||||
}
|
||||
|
||||
void
|
||||
PointToPointEpcHelper::DoAddX2Interface (const Ptr<EpcX2> &enb1X2, const Ptr<NetDevice> &enb1LteDev,
|
||||
const Ipv4Address &enb1X2Address,
|
||||
const Ptr<EpcX2> &enb2X2, const Ptr<NetDevice> &enb2LteDev,
|
||||
const Ipv4Address &enb2X2Address) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
Ptr<LteEnbNetDevice> enb1LteDevice = enb1LteDev->GetObject<LteEnbNetDevice> ();
|
||||
Ptr<LteEnbNetDevice> enb2LteDevice = enb2LteDev->GetObject<LteEnbNetDevice> ();
|
||||
|
||||
NS_ABORT_MSG_IF (enb1LteDevice == nullptr , "Unable to find LteEnbNetDevice for the first eNB");
|
||||
NS_ABORT_MSG_IF (enb2LteDevice == nullptr , "Unable to find LteEnbNetDevice for the second eNB");
|
||||
|
||||
uint16_t enb1CellId = enb1LteDevice->GetCellId ();
|
||||
uint16_t enb2CellId = enb2LteDevice->GetCellId ();
|
||||
|
||||
NS_LOG_LOGIC ("LteEnbNetDevice #1 = " << enb1LteDev << " - CellId = " << enb1CellId);
|
||||
NS_LOG_LOGIC ("LteEnbNetDevice #2 = " << enb2LteDev << " - CellId = " << enb2CellId);
|
||||
|
||||
enb1X2->AddX2Interface (enb1CellId, enb1X2Address, enb2CellId, enb2X2Address);
|
||||
enb2X2->AddX2Interface (enb2CellId, enb2X2Address, enb1CellId, enb1X2Address);
|
||||
|
||||
enb1LteDevice->GetRrc ()->AddX2Neighbour (enb2CellId);
|
||||
enb2LteDevice->GetRrc ()->AddX2Neighbour (enb1CellId);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PointToPointEpcHelper::AddUe (Ptr<NetDevice> ueDevice, uint64_t imsi)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << imsi << ueDevice);
|
||||
|
||||
m_mmeApp->AddUe (imsi);
|
||||
m_pgwApp->AddUe (imsi);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
PointToPointEpcHelper::ActivateEpsBearer (Ptr<NetDevice> ueDevice, uint64_t imsi,
|
||||
Ptr<EpcTft> tft, EpsBearer bearer)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << ueDevice << imsi);
|
||||
|
||||
// we now retrieve the IPv4/IPv6 address of the UE and notify it to the SGW;
|
||||
// we couldn't do it before since address assignment is triggered by
|
||||
// the user simulation program, rather than done by the EPC
|
||||
Ptr<Node> ueNode = ueDevice->GetNode ();
|
||||
Ptr<Ipv4> ueIpv4 = ueNode->GetObject<Ipv4> ();
|
||||
Ptr<Ipv6> ueIpv6 = ueNode->GetObject<Ipv6> ();
|
||||
NS_ASSERT_MSG (ueIpv4 != 0 || ueIpv6 != 0, "UEs need to have IPv4/IPv6 installed before EPS bearers can be activated");
|
||||
|
||||
if (ueIpv4)
|
||||
{
|
||||
int32_t interface = ueIpv4->GetInterfaceForDevice (ueDevice);
|
||||
if (interface >= 0 && ueIpv4->GetNAddresses (interface) == 1)
|
||||
{
|
||||
Ipv4Address ueAddr = ueIpv4->GetAddress (interface, 0).GetLocal ();
|
||||
NS_LOG_LOGIC (" UE IPv4 address: " << ueAddr);
|
||||
m_pgwApp->SetUeAddress (imsi, ueAddr);
|
||||
}
|
||||
}
|
||||
if (ueIpv6)
|
||||
{
|
||||
int32_t interface6 = ueIpv6->GetInterfaceForDevice (ueDevice);
|
||||
if (interface6 >= 0 && ueIpv6->GetNAddresses (interface6) == 2)
|
||||
{
|
||||
Ipv6Address ueAddr6 = ueIpv6->GetAddress (interface6, 1).GetAddress ();
|
||||
NS_LOG_LOGIC (" UE IPv6 address: " << ueAddr6);
|
||||
m_pgwApp->SetUeAddress6 (imsi, ueAddr6);
|
||||
}
|
||||
}
|
||||
uint8_t bearerId = m_mmeApp->AddBearer (imsi, tft, bearer);
|
||||
|
||||
DoActivateEpsBearerForUe (ueDevice, tft, bearer);
|
||||
|
||||
return bearerId;
|
||||
}
|
||||
|
||||
void
|
||||
PointToPointEpcHelper::DoActivateEpsBearerForUe (const Ptr<NetDevice> &ueDevice,
|
||||
const Ptr<EpcTft> &tft,
|
||||
const EpsBearer &bearer) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
Ptr<LteUeNetDevice> ueLteDevice = DynamicCast<LteUeNetDevice> (ueDevice);
|
||||
if (ueLteDevice == nullptr)
|
||||
{
|
||||
// You may wonder why this is not an assert. Well, take a look in epc-test-s1u-downlink
|
||||
// and -uplink: we are using CSMA to simulate UEs.
|
||||
NS_LOG_WARN ("Unable to find LteUeNetDevice while activating the EPS bearer");
|
||||
}
|
||||
else
|
||||
{
|
||||
Simulator::ScheduleNow (&EpcUeNas::ActivateEpsBearer, ueLteDevice->GetNas (), bearer, tft);
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<Node>
|
||||
PointToPointEpcHelper::GetPgwNode () const
|
||||
{
|
||||
return m_pgw;
|
||||
}
|
||||
|
||||
Ipv4InterfaceContainer
|
||||
PointToPointEpcHelper::AssignUeIpv4Address (NetDeviceContainer ueDevices)
|
||||
{
|
||||
return m_uePgwAddressHelper.Assign (ueDevices);
|
||||
}
|
||||
|
||||
Ipv6InterfaceContainer
|
||||
PointToPointEpcHelper::AssignUeIpv6Address (NetDeviceContainer ueDevices)
|
||||
{
|
||||
for (NetDeviceContainer::Iterator iter = ueDevices.Begin ();
|
||||
iter != ueDevices.End ();
|
||||
iter ++)
|
||||
{
|
||||
Ptr<Icmpv6L4Protocol> icmpv6 = (*iter)->GetNode ()->GetObject<Icmpv6L4Protocol> ();
|
||||
icmpv6->SetAttribute ("DAD", BooleanValue (false));
|
||||
}
|
||||
return m_uePgwAddressHelper6.Assign (ueDevices);
|
||||
}
|
||||
|
||||
Ipv4Address
|
||||
PointToPointEpcHelper::GetUeDefaultGatewayAddress ()
|
||||
{
|
||||
// return the address of the tun device
|
||||
return m_pgw->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ();
|
||||
}
|
||||
|
||||
Ipv6Address
|
||||
PointToPointEpcHelper::GetUeDefaultGatewayAddress6 ()
|
||||
{
|
||||
// return the address of the tun device
|
||||
return m_pgw->GetObject<Ipv6> ()->GetAddress (1, 1).GetAddress ();
|
||||
NoBackhaulEpcHelper::AddS1Interface (enb, enbS1uAddress, sgwS1uAddress, cellId);
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2011-2018 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
|
||||
* Copyright (c) 2011-2019 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
|
||||
@@ -18,39 +18,24 @@
|
||||
* Author: Jaume Nin <jnin@cttc.es>
|
||||
* Nicola Baldo <nbaldo@cttc.es>
|
||||
* Manuel Requena <manuel.requena@cttc.es>
|
||||
* (most of the code refactored to no-backhaul-epc-helper.h)
|
||||
*/
|
||||
|
||||
#ifndef POINT_TO_POINT_EPC_HELPER_H
|
||||
#define POINT_TO_POINT_EPC_HELPER_H
|
||||
|
||||
#include <ns3/object.h>
|
||||
#include <ns3/ipv4-address-helper.h>
|
||||
#include <ns3/ipv6-address-helper.h>
|
||||
#include <ns3/data-rate.h>
|
||||
#include <ns3/epc-tft.h>
|
||||
#include <ns3/eps-bearer.h>
|
||||
#include <ns3/epc-helper.h>
|
||||
#include "ns3/no-backhaul-epc-helper.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Node;
|
||||
class NetDevice;
|
||||
class VirtualNetDevice;
|
||||
class EpcSgwApplication;
|
||||
class EpcPgwApplication;
|
||||
class EpcMmeApplication;
|
||||
class EpcX2;
|
||||
|
||||
/**
|
||||
* \ingroup lte
|
||||
* \brief Create an EPC network with PointToPoint links
|
||||
* \brief Create an EPC network with PointToPoint links in the backhaul network.
|
||||
*
|
||||
* This Helper will create an EPC network topology comprising of
|
||||
* three nodes: SGW, PGW and MME.
|
||||
* The S1-U, X2-U, X2-C, S5 and S11 interfaces are realized over
|
||||
* PointToPoint links.
|
||||
* This Helper extends NoBackhaulEpcHelper creating PointToPoint links in the
|
||||
* backhaul network (i.e. in the S1-U and S1-MME interfaces)
|
||||
*/
|
||||
class PointToPointEpcHelper : public EpcHelper
|
||||
class PointToPointEpcHelper : public NoBackhaulEpcHelper
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -62,7 +47,7 @@ public:
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~PointToPointEpcHelper ();
|
||||
|
||||
|
||||
// inherited from Object
|
||||
/**
|
||||
* Register this type.
|
||||
@@ -74,87 +59,10 @@ public:
|
||||
|
||||
// inherited from EpcHelper
|
||||
virtual void AddEnb (Ptr<Node> enbNode, Ptr<NetDevice> lteEnbNetDevice, uint16_t cellId);
|
||||
virtual void AddUe (Ptr<NetDevice> ueLteDevice, uint64_t imsi);
|
||||
virtual void AddX2Interface (Ptr<Node> enbNode1, Ptr<Node> enbNode2);
|
||||
virtual uint8_t ActivateEpsBearer (Ptr<NetDevice> ueLteDevice, uint64_t imsi, Ptr<EpcTft> tft, EpsBearer bearer);
|
||||
virtual Ptr<Node> GetPgwNode () const;
|
||||
virtual Ipv4InterfaceContainer AssignUeIpv4Address (NetDeviceContainer ueDevices);
|
||||
virtual Ipv6InterfaceContainer AssignUeIpv6Address (NetDeviceContainer ueDevices);
|
||||
virtual Ipv4Address GetUeDefaultGatewayAddress ();
|
||||
virtual Ipv6Address GetUeDefaultGatewayAddress6 ();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \brief DoAddX2Interface: Call AddX2Interface on top of the Enb device pointers
|
||||
*
|
||||
* \param enb1X2 EPCX2 of ENB1
|
||||
* \param enb1LteDev LTE device of ENB1
|
||||
* \param enb1X2Address Address for ENB1
|
||||
* \param enb2X2 EPCX2 of ENB2
|
||||
* \param enb2LteDev LTE device of ENB2
|
||||
* \param enb2X2Address Address for ENB2
|
||||
*/
|
||||
virtual void DoAddX2Interface(const Ptr<EpcX2> &enb1X2, const Ptr<NetDevice> &enb1LteDev,
|
||||
const Ipv4Address &enb1X2Address,
|
||||
const Ptr<EpcX2> &enb2X2, const Ptr<NetDevice> &enb2LteDev,
|
||||
const Ipv4Address &enb2X2Address) const;
|
||||
|
||||
/**
|
||||
* \brief DoActivateEpsBearerForUe: Schedule ActivateEpsBearer on the UE
|
||||
* \param ueDevice LTE device for the UE
|
||||
* \param tft TFT
|
||||
* \param bearer Bearer
|
||||
*/
|
||||
virtual void DoActivateEpsBearerForUe (const Ptr<NetDevice> &ueDevice,
|
||||
const Ptr<EpcTft> &tft,
|
||||
const EpsBearer &bearer) const;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* helper to assign IPv4 addresses to UE devices as well as to the TUN device of the SGW/PGW
|
||||
*/
|
||||
Ipv4AddressHelper m_uePgwAddressHelper;
|
||||
/**
|
||||
* helper to assign IPv6 addresses to UE devices as well as to the TUN device of the SGW/PGW
|
||||
*/
|
||||
Ipv6AddressHelper m_uePgwAddressHelper6;
|
||||
|
||||
/**
|
||||
* SGW network element
|
||||
*/
|
||||
Ptr<Node> m_sgw;
|
||||
|
||||
/**
|
||||
* PGW network element
|
||||
*/
|
||||
Ptr<Node> m_pgw;
|
||||
|
||||
/**
|
||||
* MME network element
|
||||
*/
|
||||
Ptr<Node> m_mme;
|
||||
|
||||
/**
|
||||
* SGW application
|
||||
*/
|
||||
Ptr<EpcSgwApplication> m_sgwApp;
|
||||
|
||||
/**
|
||||
* PGW application
|
||||
*/
|
||||
Ptr<EpcPgwApplication> m_pgwApp;
|
||||
|
||||
/**
|
||||
* MME application
|
||||
*/
|
||||
Ptr<EpcMmeApplication> m_mmeApp;
|
||||
|
||||
/**
|
||||
* TUN device implementing tunneling of user data over GTP-U/UDP/IP
|
||||
*/
|
||||
Ptr<VirtualNetDevice> m_tunDevice;
|
||||
|
||||
/**
|
||||
* S1-U interfaces
|
||||
*/
|
||||
@@ -182,103 +90,15 @@ private:
|
||||
*/
|
||||
uint16_t m_s1uLinkMtu;
|
||||
|
||||
/**
|
||||
* UDP port where the GTP-U Socket is bound, fixed by the standard as 2152
|
||||
*/
|
||||
uint16_t m_gtpuUdpPort;
|
||||
/**
|
||||
* Helper to assign addresses to S1-MME NetDevices
|
||||
*/
|
||||
Ipv4AddressHelper m_s1apIpv4AddressHelper;
|
||||
|
||||
/**
|
||||
* Helper to assign addresses to S11 NetDevices
|
||||
* Enable PCAP generation for S1 link
|
||||
*/
|
||||
Ipv4AddressHelper m_s11Ipv4AddressHelper;
|
||||
|
||||
/**
|
||||
* The data rate to be used for the next S11 link to be created
|
||||
*/
|
||||
DataRate m_s11LinkDataRate;
|
||||
|
||||
/**
|
||||
* The delay to be used for the next S11 link to be created
|
||||
*/
|
||||
Time m_s11LinkDelay;
|
||||
|
||||
/**
|
||||
* The MTU of the next S11 link to be created
|
||||
*/
|
||||
uint16_t m_s11LinkMtu;
|
||||
|
||||
/**
|
||||
* UDP port where the GTPv2-C Socket is bound, fixed by the standard as 2123
|
||||
*/
|
||||
uint16_t m_gtpcUdpPort;
|
||||
|
||||
/**
|
||||
* S5 interfaces
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helper to assign addresses to S5 NetDevices
|
||||
*/
|
||||
Ipv4AddressHelper m_s5Ipv4AddressHelper;
|
||||
|
||||
/**
|
||||
* The data rate to be used for the next S5 link to be created
|
||||
*/
|
||||
DataRate m_s5LinkDataRate;
|
||||
|
||||
/**
|
||||
* The delay to be used for the next S5 link to be created
|
||||
*/
|
||||
Time m_s5LinkDelay;
|
||||
|
||||
/**
|
||||
* The MTU of the next S5 link to be created
|
||||
*/
|
||||
uint16_t m_s5LinkMtu;
|
||||
|
||||
/**
|
||||
* Map storing for each IMSI the corresponding eNB NetDevice
|
||||
*/
|
||||
std::map<uint64_t, Ptr<NetDevice> > m_imsiEnbDeviceMap;
|
||||
|
||||
/**
|
||||
* helper to assign addresses to X2 NetDevices
|
||||
*/
|
||||
Ipv4AddressHelper m_x2Ipv4AddressHelper;
|
||||
|
||||
/**
|
||||
* The data rate to be used for the next X2 link to be created
|
||||
*/
|
||||
DataRate m_x2LinkDataRate;
|
||||
|
||||
/**
|
||||
* The delay to be used for the next X2 link to be created
|
||||
*/
|
||||
Time m_x2LinkDelay;
|
||||
|
||||
/**
|
||||
* The MTU of the next X2 link to be created. Note that,
|
||||
* because of some big X2 messages, you need a big MTU.
|
||||
*/
|
||||
uint16_t m_x2LinkMtu;
|
||||
|
||||
/**
|
||||
* Enable PCAP generation for X2 link
|
||||
*/
|
||||
bool m_enablePcapOverX2;
|
||||
/**
|
||||
* Prefix for the PCAP file for the X2 link
|
||||
*/
|
||||
std::string m_x2LinkPcapPrefix;
|
||||
|
||||
/**
|
||||
* Enable PCAP generation for S1U link
|
||||
*/
|
||||
bool m_enablePcapOverS1U;
|
||||
bool m_s1uLinkEnablePcap;
|
||||
|
||||
/**
|
||||
* Prefix for the PCAP file for the S1 link
|
||||
@@ -286,9 +106,6 @@ private:
|
||||
std::string m_s1uLinkPcapPrefix;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif // POINT_TO_POINT_EPC_HELPER_H
|
||||
|
||||
@@ -87,19 +87,16 @@ EpcEnbApplication::DoDispose (void)
|
||||
delete m_s1apSapEnb;
|
||||
}
|
||||
|
||||
EpcEnbApplication::EpcEnbApplication (Ptr<Socket> lteSocket, Ptr<Socket> lteSocket6, Ptr<Socket> s1uSocket, Ipv4Address enbS1uAddress, Ipv4Address sgwS1uAddress, uint16_t cellId)
|
||||
EpcEnbApplication::EpcEnbApplication (Ptr<Socket> lteSocket, Ptr<Socket> lteSocket6, uint16_t cellId)
|
||||
: m_lteSocket (lteSocket),
|
||||
m_lteSocket6 (lteSocket6),
|
||||
m_s1uSocket (s1uSocket),
|
||||
m_enbS1uAddress (enbS1uAddress),
|
||||
m_sgwS1uAddress (sgwS1uAddress),
|
||||
m_gtpuUdpPort (2152), // fixed by the standard
|
||||
m_s1SapUser (0),
|
||||
m_s1apSapMme (0),
|
||||
m_cellId (cellId)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << lteSocket << s1uSocket << sgwS1uAddress);
|
||||
m_s1uSocket->SetRecvCallback (MakeCallback (&EpcEnbApplication::RecvFromS1uSocket, this));
|
||||
NS_LOG_FUNCTION (this << lteSocket << lteSocket6 << cellId);
|
||||
|
||||
m_lteSocket->SetRecvCallback (MakeCallback (&EpcEnbApplication::RecvFromLteSocket, this));
|
||||
m_lteSocket6->SetRecvCallback (MakeCallback (&EpcEnbApplication::RecvFromLteSocket, this));
|
||||
m_s1SapProvider = new MemberEpcEnbS1SapProvider<EpcEnbApplication> (this);
|
||||
@@ -107,6 +104,18 @@ EpcEnbApplication::EpcEnbApplication (Ptr<Socket> lteSocket, Ptr<Socket> lteSock
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EpcEnbApplication::AddS1Interface (Ptr<Socket> s1uSocket, Ipv4Address enbAddress, Ipv4Address sgwAddress)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << s1uSocket << enbAddress << sgwAddress);
|
||||
|
||||
m_s1uSocket = s1uSocket;
|
||||
m_s1uSocket->SetRecvCallback (MakeCallback (&EpcEnbApplication::RecvFromS1uSocket, this));
|
||||
m_enbS1uAddress = enbAddress;
|
||||
m_sgwS1uAddress = sgwAddress;
|
||||
}
|
||||
|
||||
|
||||
EpcEnbApplication::~EpcEnbApplication (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
@@ -73,12 +73,19 @@ public:
|
||||
*
|
||||
* \param lteSocket the socket to be used to send/receive IPv4 packets to/from the LTE radio interface
|
||||
* \param lteSocket6 the socket to be used to send/receive IPv6 packets to/from the LTE radio interface
|
||||
* \param cellId the identifier of the eNB
|
||||
*/
|
||||
EpcEnbApplication (Ptr<Socket> lteSocket, Ptr<Socket> lteSocket6, uint16_t cellId);
|
||||
|
||||
/**
|
||||
* Add a S1-U interface to the eNB
|
||||
*
|
||||
* \param s1uSocket the socket to be used to send/receive packets to/from the S1-U interface connected with the SGW
|
||||
* \param enbS1uAddress the IPv4 address of the S1-U interface of this eNB
|
||||
* \param sgwS1uAddress the IPv4 address at which this eNB will be able to reach its SGW for S1-U communications
|
||||
* \param cellId the identifier of the eNB
|
||||
*/
|
||||
EpcEnbApplication (Ptr<Socket> lteSocket, Ptr<Socket> lteSocket6, Ptr<Socket> s1uSocket, Ipv4Address enbS1uAddress, Ipv4Address sgwS1uAddress, uint16_t cellId);
|
||||
void AddS1Interface (Ptr<Socket> s1uSocket, Ipv4Address enbAddress, Ipv4Address sgwAddress);
|
||||
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
|
||||
@@ -1,286 +0,0 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Nicola Baldo <nbaldo@cttc.es>
|
||||
*/
|
||||
|
||||
#include <ns3/fatal-error.h>
|
||||
#include <ns3/log.h>
|
||||
|
||||
#include "epc-s1ap-sap.h"
|
||||
#include "epc-s11-sap.h"
|
||||
|
||||
#include "epc-mme.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("EpcMme");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (EpcMme);
|
||||
|
||||
EpcMme::EpcMme ()
|
||||
: m_s11SapSgw (0)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_s1apSapMme = new MemberEpcS1apSapMme<EpcMme> (this);
|
||||
m_s11SapMme = new MemberEpcS11SapMme<EpcMme> (this);
|
||||
}
|
||||
|
||||
|
||||
EpcMme::~EpcMme ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
void
|
||||
EpcMme::DoDispose ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
delete m_s1apSapMme;
|
||||
delete m_s11SapMme;
|
||||
}
|
||||
|
||||
TypeId
|
||||
EpcMme::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::EpcMme")
|
||||
.SetParent<Object> ()
|
||||
.SetGroupName("Lte")
|
||||
.AddConstructor<EpcMme> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
EpcS1apSapMme*
|
||||
EpcMme::GetS1apSapMme ()
|
||||
{
|
||||
return m_s1apSapMme;
|
||||
}
|
||||
|
||||
void
|
||||
EpcMme::SetS11SapSgw (EpcS11SapSgw * s)
|
||||
{
|
||||
m_s11SapSgw = s;
|
||||
}
|
||||
|
||||
EpcS11SapMme*
|
||||
EpcMme::GetS11SapMme ()
|
||||
{
|
||||
return m_s11SapMme;
|
||||
}
|
||||
|
||||
void
|
||||
EpcMme::AddEnb (uint16_t gci, Ipv4Address enbS1uAddr, EpcS1apSapEnb* enbS1apSap)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << gci << enbS1uAddr);
|
||||
Ptr<EnbInfo> enbInfo = Create<EnbInfo> ();
|
||||
enbInfo->gci = gci;
|
||||
enbInfo->s1uAddr = enbS1uAddr;
|
||||
enbInfo->s1apSapEnb = enbS1apSap;
|
||||
m_enbInfoMap[gci] = enbInfo;
|
||||
}
|
||||
|
||||
void
|
||||
EpcMme::AddUe (uint64_t imsi)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << imsi);
|
||||
Ptr<UeInfo> ueInfo = Create<UeInfo> ();
|
||||
ueInfo->imsi = imsi;
|
||||
ueInfo->mmeUeS1Id = imsi;
|
||||
m_ueInfoMap[imsi] = ueInfo;
|
||||
ueInfo->bearerCounter = 0;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
EpcMme::AddBearer (uint64_t imsi, Ptr<EpcTft> tft, EpsBearer bearer)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << imsi);
|
||||
std::map<uint64_t, Ptr<UeInfo> >::iterator it = m_ueInfoMap.find (imsi);
|
||||
NS_ASSERT_MSG (it != m_ueInfoMap.end (), "could not find any UE with IMSI " << imsi);
|
||||
NS_ASSERT_MSG (it->second->bearerCounter < 11, "too many bearers already! " << it->second->bearerCounter);
|
||||
BearerInfo bearerInfo;
|
||||
bearerInfo.bearerId = ++(it->second->bearerCounter);
|
||||
bearerInfo.tft = tft;
|
||||
bearerInfo.bearer = bearer;
|
||||
it->second->bearersToBeActivated.push_back (bearerInfo);
|
||||
return bearerInfo.bearerId;
|
||||
}
|
||||
|
||||
|
||||
// S1-AP SAP MME forwarded methods
|
||||
|
||||
void
|
||||
EpcMme::DoInitialUeMessage (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, uint64_t imsi, uint16_t gci)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << mmeUeS1Id << enbUeS1Id << imsi << gci);
|
||||
std::map<uint64_t, Ptr<UeInfo> >::iterator it = m_ueInfoMap.find (imsi);
|
||||
NS_ASSERT_MSG (it != m_ueInfoMap.end (), "could not find any UE with IMSI " << imsi);
|
||||
it->second->cellId = gci;
|
||||
EpcS11SapSgw::CreateSessionRequestMessage msg;
|
||||
msg.imsi = imsi;
|
||||
msg.uli.gci = gci;
|
||||
msg.teid = 0;
|
||||
for (std::list<BearerInfo>::iterator bit = it->second->bearersToBeActivated.begin ();
|
||||
bit != it->second->bearersToBeActivated.end ();
|
||||
++bit)
|
||||
{
|
||||
EpcS11SapSgw::BearerContextToBeCreated bearerContext;
|
||||
bearerContext.epsBearerId = bit->bearerId;
|
||||
bearerContext.bearerLevelQos = bit->bearer;
|
||||
bearerContext.tft = bit->tft;
|
||||
msg.bearerContextsToBeCreated.push_back (bearerContext);
|
||||
}
|
||||
m_s11SapSgw->CreateSessionRequest (msg);
|
||||
}
|
||||
|
||||
void
|
||||
EpcMme::DoInitialContextSetupResponse (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<EpcS1apSapMme::ErabSetupItem> erabSetupList)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << mmeUeS1Id << enbUeS1Id);
|
||||
NS_FATAL_ERROR ("unimplemented");
|
||||
}
|
||||
|
||||
void
|
||||
EpcMme::DoPathSwitchRequest (uint64_t enbUeS1Id, uint64_t mmeUeS1Id, uint16_t gci, std::list<EpcS1apSapMme::ErabSwitchedInDownlinkItem> erabToBeSwitchedInDownlinkList)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << mmeUeS1Id << enbUeS1Id << gci);
|
||||
|
||||
uint64_t imsi = mmeUeS1Id;
|
||||
std::map<uint64_t, Ptr<UeInfo> >::iterator it = m_ueInfoMap.find (imsi);
|
||||
NS_ASSERT_MSG (it != m_ueInfoMap.end (), "could not find any UE with IMSI " << imsi);
|
||||
NS_LOG_INFO ("IMSI " << imsi << " old eNB: " << it->second->cellId << ", new eNB: " << gci);
|
||||
it->second->cellId = gci;
|
||||
it->second->enbUeS1Id = enbUeS1Id;
|
||||
|
||||
EpcS11SapSgw::ModifyBearerRequestMessage msg;
|
||||
msg.teid = imsi; // trick to avoid the need for allocating TEIDs on the S11 interface
|
||||
msg.uli.gci = gci;
|
||||
// bearer modification is not supported for now
|
||||
m_s11SapSgw->ModifyBearerRequest (msg);
|
||||
}
|
||||
|
||||
|
||||
// S11 SAP MME forwarded methods
|
||||
|
||||
void
|
||||
EpcMme::DoCreateSessionResponse (EpcS11SapMme::CreateSessionResponseMessage msg)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << msg.teid);
|
||||
uint64_t imsi = msg.teid;
|
||||
std::list<EpcS1apSapEnb::ErabToBeSetupItem> erabToBeSetupList;
|
||||
for (std::list<EpcS11SapMme::BearerContextCreated>::iterator bit = msg.bearerContextsCreated.begin ();
|
||||
bit != msg.bearerContextsCreated.end ();
|
||||
++bit)
|
||||
{
|
||||
EpcS1apSapEnb::ErabToBeSetupItem erab;
|
||||
erab.erabId = bit->epsBearerId;
|
||||
erab.erabLevelQosParameters = bit->bearerLevelQos;
|
||||
erab.transportLayerAddress = bit->sgwFteid.address;
|
||||
erab.sgwTeid = bit->sgwFteid.teid;
|
||||
erabToBeSetupList.push_back (erab);
|
||||
}
|
||||
std::map<uint64_t, Ptr<UeInfo> >::iterator it = m_ueInfoMap.find (imsi);
|
||||
NS_ASSERT_MSG (it != m_ueInfoMap.end (), "could not find any UE with IMSI " << imsi);
|
||||
uint16_t cellId = it->second->cellId;
|
||||
uint16_t enbUeS1Id = it->second->enbUeS1Id;
|
||||
uint64_t mmeUeS1Id = it->second->mmeUeS1Id;
|
||||
std::map<uint16_t, Ptr<EnbInfo> >::iterator jt = m_enbInfoMap.find (cellId);
|
||||
NS_ASSERT_MSG (jt != m_enbInfoMap.end (), "could not find any eNB with CellId " << cellId);
|
||||
jt->second->s1apSapEnb->InitialContextSetupRequest (mmeUeS1Id, enbUeS1Id, erabToBeSetupList);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EpcMme::DoModifyBearerResponse (EpcS11SapMme::ModifyBearerResponseMessage msg)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << msg.teid);
|
||||
NS_ASSERT (msg.cause == EpcS11SapMme::ModifyBearerResponseMessage::REQUEST_ACCEPTED);
|
||||
uint64_t imsi = msg.teid;
|
||||
std::map<uint64_t, Ptr<UeInfo> >::iterator it = m_ueInfoMap.find (imsi);
|
||||
NS_ASSERT_MSG (it != m_ueInfoMap.end (), "could not find any UE with IMSI " << imsi);
|
||||
uint64_t enbUeS1Id = it->second->enbUeS1Id;
|
||||
uint64_t mmeUeS1Id = it->second->mmeUeS1Id;
|
||||
uint16_t cgi = it->second->cellId;
|
||||
std::list<EpcS1apSapEnb::ErabSwitchedInUplinkItem> erabToBeSwitchedInUplinkList; // unused for now
|
||||
std::map<uint16_t, Ptr<EnbInfo> >::iterator jt = m_enbInfoMap.find (it->second->cellId);
|
||||
NS_ASSERT_MSG (jt != m_enbInfoMap.end (), "could not find any eNB with CellId " << it->second->cellId);
|
||||
jt->second->s1apSapEnb->PathSwitchRequestAcknowledge (enbUeS1Id, mmeUeS1Id, cgi, erabToBeSwitchedInUplinkList);
|
||||
}
|
||||
|
||||
void
|
||||
EpcMme::DoErabReleaseIndication (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<EpcS1apSapMme::ErabToBeReleasedIndication> erabToBeReleaseIndication)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << mmeUeS1Id << enbUeS1Id);
|
||||
uint64_t imsi = mmeUeS1Id;
|
||||
std::map<uint64_t, Ptr<UeInfo> >::iterator it = m_ueInfoMap.find (imsi);
|
||||
NS_ASSERT_MSG (it != m_ueInfoMap.end (), "could not find any UE with IMSI " << imsi);
|
||||
|
||||
EpcS11SapSgw::DeleteBearerCommandMessage msg;
|
||||
// trick to avoid the need for allocating TEIDs on the S11 interface
|
||||
msg.teid = imsi;
|
||||
|
||||
for (std::list<EpcS1apSapMme::ErabToBeReleasedIndication>::iterator bit = erabToBeReleaseIndication.begin (); bit != erabToBeReleaseIndication.end (); ++bit)
|
||||
{
|
||||
EpcS11SapSgw::BearerContextToBeRemoved bearerContext;
|
||||
bearerContext.epsBearerId = bit->erabId;
|
||||
msg.bearerContextsToBeRemoved.push_back (bearerContext);
|
||||
}
|
||||
//Delete Bearer command towards epc-sgw-pgw-application
|
||||
m_s11SapSgw->DeleteBearerCommand (msg);
|
||||
}
|
||||
|
||||
void
|
||||
EpcMme::DoDeleteBearerRequest (EpcS11SapMme::DeleteBearerRequestMessage msg)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
uint64_t imsi = msg.teid;
|
||||
std::map<uint64_t, Ptr<UeInfo> >::iterator it = m_ueInfoMap.find (imsi);
|
||||
NS_ASSERT_MSG (it != m_ueInfoMap.end (), "could not find any UE with IMSI " << imsi);
|
||||
EpcS11SapSgw::DeleteBearerResponseMessage res;
|
||||
|
||||
res.teid = imsi;
|
||||
|
||||
for (std::list<EpcS11SapMme::BearerContextRemoved>::iterator bit = msg.bearerContextsRemoved.begin ();
|
||||
bit != msg.bearerContextsRemoved.end ();
|
||||
++bit)
|
||||
{
|
||||
EpcS11SapSgw::BearerContextRemovedSgwPgw bearerContext;
|
||||
bearerContext.epsBearerId = bit->epsBearerId;
|
||||
res.bearerContextsRemoved.push_back (bearerContext);
|
||||
|
||||
RemoveBearer (it->second, bearerContext.epsBearerId); //schedules function to erase, context of de-activated bearer
|
||||
}
|
||||
//schedules Delete Bearer Response towards epc-sgw-pgw-application
|
||||
m_s11SapSgw->DeleteBearerResponse (res);
|
||||
}
|
||||
|
||||
void EpcMme::RemoveBearer (Ptr<UeInfo> ueInfo, uint8_t epsBearerId)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << epsBearerId);
|
||||
for (std::list<BearerInfo>::iterator bit = ueInfo->bearersToBeActivated.begin ();
|
||||
bit != ueInfo->bearersToBeActivated.end ();
|
||||
++bit)
|
||||
{
|
||||
if (bit->bearerId == epsBearerId)
|
||||
{
|
||||
ueInfo->bearersToBeActivated.erase (bit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
@@ -1,241 +0,0 @@
|
||||
/* -*- 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: Nicola Baldo <nbaldo@cttc.es>
|
||||
*/
|
||||
|
||||
#ifndef EPC_MME_H
|
||||
#define EPC_MME_H
|
||||
|
||||
#include <ns3/object.h>
|
||||
#include <ns3/epc-s1ap-sap.h>
|
||||
#include <ns3/epc-s11-sap.h>
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Node;
|
||||
class NetDevice;
|
||||
|
||||
/**
|
||||
* \brief This object implements the MME functionality.
|
||||
*
|
||||
*/
|
||||
class EpcMme : public Object
|
||||
{
|
||||
|
||||
/// allow MemberEpcS1apSapMme<EpcMme> class friend access
|
||||
friend class MemberEpcS1apSapMme<EpcMme>;
|
||||
/// allow MemberEpcS11SapMme<EpcMme> class friend access
|
||||
friend class MemberEpcS11SapMme<EpcMme>;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
EpcMme ();
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~EpcMme ();
|
||||
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
protected:
|
||||
virtual void DoDispose ();
|
||||
|
||||
public:
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* \return the MME side of the S1-AP SAP
|
||||
*/
|
||||
EpcS1apSapMme* GetS1apSapMme ();
|
||||
|
||||
/**
|
||||
* Set the SGW side of the S11 SAP
|
||||
*
|
||||
* \param s the SGW side of the S11 SAP
|
||||
*/
|
||||
void SetS11SapSgw (EpcS11SapSgw * s);
|
||||
|
||||
/**
|
||||
*
|
||||
* \return the MME side of the S11 SAP
|
||||
*/
|
||||
EpcS11SapMme* GetS11SapMme ();
|
||||
|
||||
/**
|
||||
* Add a new ENB to the MME.
|
||||
* \param ecgi E-UTRAN Cell Global ID, the unique identifier of the eNodeB
|
||||
* \param enbS1UAddr address of the eNB for S1-U communications
|
||||
* \param enbS1apSap the ENB side of the S1-AP SAP
|
||||
*/
|
||||
void AddEnb (uint16_t ecgi, Ipv4Address enbS1UAddr, EpcS1apSapEnb* enbS1apSap);
|
||||
|
||||
/**
|
||||
* Add a new UE to the MME. This is the equivalent of storing the UE
|
||||
* credentials before the UE is ever turned on.
|
||||
*
|
||||
* \param imsi the unique identifier of the UE
|
||||
*/
|
||||
void AddUe (uint64_t imsi);
|
||||
|
||||
/**
|
||||
* Add an EPS bearer to the list of bearers to be activated for this
|
||||
* UE. The bearer will be activated when the UE enters the ECM
|
||||
* connected state.
|
||||
*
|
||||
* \param imsi UE identifier
|
||||
* \param tft traffic flow template of the bearer
|
||||
* \param bearer QoS characteristics of the bearer
|
||||
* \returns bearer ID
|
||||
*/
|
||||
uint8_t AddBearer (uint64_t imsi, Ptr<EpcTft> tft, EpsBearer bearer);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// S1-AP SAP MME forwarded methods
|
||||
/**
|
||||
* Initial UE Message function
|
||||
* \param mmeUeS1Id the MME UE S1 ID
|
||||
* \param enbUeS1Id the ENB UE S1 ID
|
||||
* \param imsi the IMSI
|
||||
* \param ecgi the ECGI
|
||||
*/
|
||||
void DoInitialUeMessage (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, uint64_t imsi, uint16_t ecgi);
|
||||
/**
|
||||
* Initial Context Setup Response function
|
||||
* \param mmeUeS1Id the MME UE S1 ID
|
||||
* \param enbUeS1Id the ENB UE S1 ID
|
||||
* \param erabSetupList the ERAB setup list
|
||||
*/
|
||||
void DoInitialContextSetupResponse (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<EpcS1apSapMme::ErabSetupItem> erabSetupList);
|
||||
/**
|
||||
* Path Switch Request function
|
||||
* \param mmeUeS1Id the MME UE S1 ID
|
||||
* \param enbUeS1Id the ENB UE S1 ID
|
||||
* \param cgi the CGI
|
||||
* \param erabToBeSwitchedInDownlinkList the ERAB to be switched in downlink list
|
||||
*/
|
||||
void DoPathSwitchRequest (uint64_t enbUeS1Id, uint64_t mmeUeS1Id, uint16_t cgi, std::list<EpcS1apSapMme::ErabSwitchedInDownlinkItem> erabToBeSwitchedInDownlinkList);
|
||||
/**
|
||||
* ERAB Release Indication function
|
||||
* \param mmeUeS1Id the MME UE S1 ID
|
||||
* \param enbUeS1Id the ENB UE S1 ID
|
||||
* \param erabToBeReleaseIndication the ERAB to be release indication list
|
||||
*/
|
||||
void DoErabReleaseIndication (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<EpcS1apSapMme::ErabToBeReleasedIndication> erabToBeReleaseIndication);
|
||||
|
||||
// S11 SAP MME forwarded methods
|
||||
/**
|
||||
* Create Session Response function
|
||||
* \param msg EpcS11SapMme::CreateSessionResponseMessage
|
||||
*/
|
||||
void DoCreateSessionResponse (EpcS11SapMme::CreateSessionResponseMessage msg);
|
||||
/**
|
||||
* Modify Bearer Response function
|
||||
* \param msg EpcS11SapMme::ModifyBearerResponseMessage
|
||||
*/
|
||||
void DoModifyBearerResponse (EpcS11SapMme::ModifyBearerResponseMessage msg);
|
||||
/**
|
||||
* Delete Bearer Request function
|
||||
* \param msg EpcS11SapMme::DeleteBearerRequestMessage
|
||||
*/
|
||||
void DoDeleteBearerRequest (EpcS11SapMme::DeleteBearerRequestMessage msg);
|
||||
|
||||
|
||||
/**
|
||||
* Hold info on an EPS bearer to be activated
|
||||
*
|
||||
*/
|
||||
struct BearerInfo
|
||||
{
|
||||
Ptr<EpcTft> tft; ///< traffic flow template
|
||||
EpsBearer bearer; ///< bearer QOS characteristics
|
||||
uint8_t bearerId; ///< bearer ID
|
||||
};
|
||||
|
||||
/**
|
||||
* Hold info on a UE
|
||||
*
|
||||
*/
|
||||
struct UeInfo : public SimpleRefCount<UeInfo>
|
||||
{
|
||||
uint64_t mmeUeS1Id; ///< mmeUeS1Id
|
||||
uint16_t enbUeS1Id; ///< enbUeS1Id
|
||||
uint64_t imsi; ///< UE identifier
|
||||
uint16_t cellId; ///< cell ID
|
||||
std::list<BearerInfo> bearersToBeActivated; ///< list of bearers to be activated
|
||||
uint16_t bearerCounter; ///< bearer counter
|
||||
};
|
||||
|
||||
/**
|
||||
* UeInfo stored by IMSI
|
||||
*
|
||||
*/
|
||||
std::map<uint64_t, Ptr<UeInfo> > m_ueInfoMap;
|
||||
|
||||
/**
|
||||
* \brief This Function erases all contexts of bearer from MME side
|
||||
* \param ueInfo UE information pointer
|
||||
* \param epsBearerId Bearer Id which need to be removed corresponding to UE
|
||||
*/
|
||||
void RemoveBearer (Ptr<UeInfo> ueInfo, uint8_t epsBearerId);
|
||||
|
||||
/**
|
||||
* Hold info on a ENB
|
||||
*
|
||||
*/
|
||||
struct EnbInfo : public SimpleRefCount<EnbInfo>
|
||||
{
|
||||
uint16_t gci; ///< GCI
|
||||
Ipv4Address s1uAddr; ///< IP address
|
||||
EpcS1apSapEnb* s1apSapEnb; ///< EpcS1apSapEnb
|
||||
};
|
||||
|
||||
/**
|
||||
* EnbInfo stored by EGCI
|
||||
*
|
||||
*/
|
||||
std::map<uint16_t, Ptr<EnbInfo> > m_enbInfoMap;
|
||||
|
||||
|
||||
|
||||
|
||||
EpcS1apSapMme* m_s1apSapMme; ///< EpcS1apSapMme
|
||||
|
||||
EpcS11SapMme* m_s11SapMme; ///< EpcS11SapMme
|
||||
EpcS11SapSgw* m_s11SapSgw; ///< EpcS11SapSgw
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif // EPC_MME_H
|
||||
@@ -1,436 +0,0 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Jaume Nin <jnin@cttc.cat>
|
||||
* Nicola Baldo <nbaldo@cttc.cat>
|
||||
*/
|
||||
|
||||
|
||||
#include "epc-sgw-pgw-application.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/ipv4-l3-protocol.h"
|
||||
#include "ns3/ipv6.h"
|
||||
#include "ns3/ipv6-header.h"
|
||||
#include "ns3/ipv6-l3-protocol.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/epc-gtpu-header.h"
|
||||
#include "ns3/abort.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("EpcSgwPgwApplication");
|
||||
|
||||
/////////////////////////
|
||||
// UeInfo
|
||||
/////////////////////////
|
||||
|
||||
|
||||
EpcSgwPgwApplication::UeInfo::UeInfo ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::UeInfo::AddBearer (Ptr<EpcTft> tft, uint8_t bearerId, uint32_t teid)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << tft << teid);
|
||||
m_teidByBearerIdMap[bearerId] = teid;
|
||||
return m_tftClassifier.Add (tft, teid);
|
||||
}
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::UeInfo::RemoveBearer (uint8_t bearerId)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << bearerId);
|
||||
m_teidByBearerIdMap.erase (bearerId);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
EpcSgwPgwApplication::UeInfo::Classify (Ptr<Packet> p, uint16_t protocolNumber)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << p);
|
||||
// we hardcode DOWNLINK direction since the PGW is expected to
|
||||
// classify only downlink packets (uplink packets will go to the
|
||||
// internet without any classification).
|
||||
return m_tftClassifier.Classify (p, EpcTft::DOWNLINK, protocolNumber);
|
||||
}
|
||||
|
||||
Ipv4Address
|
||||
EpcSgwPgwApplication::UeInfo::GetEnbAddr ()
|
||||
{
|
||||
return m_enbAddr;
|
||||
}
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::UeInfo::SetEnbAddr (Ipv4Address enbAddr)
|
||||
{
|
||||
m_enbAddr = enbAddr;
|
||||
}
|
||||
|
||||
Ipv4Address
|
||||
EpcSgwPgwApplication::UeInfo::GetUeAddr ()
|
||||
{
|
||||
return m_ueAddr;
|
||||
}
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::UeInfo::SetUeAddr (Ipv4Address ueAddr)
|
||||
{
|
||||
m_ueAddr = ueAddr;
|
||||
}
|
||||
|
||||
Ipv6Address
|
||||
EpcSgwPgwApplication::UeInfo::GetUeAddr6 ()
|
||||
{
|
||||
return m_ueAddr6;
|
||||
}
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::UeInfo::SetUeAddr6 (Ipv6Address ueAddr)
|
||||
{
|
||||
m_ueAddr6 = ueAddr;
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// EpcSgwPgwApplication
|
||||
/////////////////////////
|
||||
|
||||
|
||||
TypeId
|
||||
EpcSgwPgwApplication::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::EpcSgwPgwApplication")
|
||||
.SetParent<Object> ()
|
||||
.SetGroupName("Lte")
|
||||
.AddTraceSource ("RxFromTun",
|
||||
"Receive data packets from internet in Tunnel net device",
|
||||
MakeTraceSourceAccessor (&EpcSgwPgwApplication::m_rxTunPktTrace),
|
||||
"ns3::EpcSgwPgwApplication::RxTracedCallback")
|
||||
.AddTraceSource ("RxFromS1u",
|
||||
"Receive data packets from S1 U Socket",
|
||||
MakeTraceSourceAccessor (&EpcSgwPgwApplication::m_rxS1uPktTrace),
|
||||
"ns3::EpcSgwPgwApplication::RxTracedCallback")
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::DoDispose ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_s1uSocket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket> > ());
|
||||
m_s1uSocket = 0;
|
||||
delete (m_s11SapSgw);
|
||||
}
|
||||
|
||||
|
||||
EpcSgwPgwApplication::EpcSgwPgwApplication (const Ptr<VirtualNetDevice> tunDevice, const Ptr<Socket> s1uSocket)
|
||||
: m_s1uSocket (s1uSocket),
|
||||
m_tunDevice (tunDevice),
|
||||
m_gtpuUdpPort (2152), // fixed by the standard
|
||||
m_teidCount (0),
|
||||
m_s11SapMme (0)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << tunDevice << s1uSocket);
|
||||
m_s1uSocket->SetRecvCallback (MakeCallback (&EpcSgwPgwApplication::RecvFromS1uSocket, this));
|
||||
m_s11SapSgw = new MemberEpcS11SapSgw<EpcSgwPgwApplication> (this);
|
||||
}
|
||||
|
||||
|
||||
EpcSgwPgwApplication::~EpcSgwPgwApplication ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
EpcSgwPgwApplication::RecvFromTunDevice (Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << source << dest << protocolNumber << packet << packet->GetSize ());
|
||||
m_rxTunPktTrace (packet->Copy ());
|
||||
Ptr<Packet> pCopy = packet->Copy ();
|
||||
|
||||
// get IP address of UE
|
||||
if (protocolNumber == Ipv4L3Protocol::PROT_NUMBER)
|
||||
{
|
||||
Ipv4Header ipv4Header;
|
||||
pCopy->RemoveHeader (ipv4Header);
|
||||
Ipv4Address ueAddr = ipv4Header.GetDestination ();
|
||||
NS_LOG_LOGIC ("packet addressed to UE " << ueAddr);
|
||||
// find corresponding UeInfo address
|
||||
std::map<Ipv4Address, Ptr<UeInfo> >::iterator it = m_ueInfoByAddrMap.find (ueAddr);
|
||||
if (it == m_ueInfoByAddrMap.end ())
|
||||
{
|
||||
NS_LOG_WARN ("unknown UE address " << ueAddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Ipv4Address enbAddr = it->second->GetEnbAddr ();
|
||||
uint32_t teid = it->second->Classify (packet, protocolNumber);
|
||||
if (teid == 0)
|
||||
{
|
||||
NS_LOG_WARN ("no matching bearer for this packet");
|
||||
}
|
||||
else
|
||||
{
|
||||
SendToS1uSocket (packet, enbAddr, teid);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (protocolNumber == Ipv6L3Protocol::PROT_NUMBER)
|
||||
{
|
||||
Ipv6Header ipv6Header;
|
||||
pCopy->RemoveHeader (ipv6Header);
|
||||
Ipv6Address ueAddr = ipv6Header.GetDestinationAddress ();
|
||||
NS_LOG_LOGIC ("packet addressed to UE " << ueAddr);
|
||||
// find corresponding UeInfo address
|
||||
std::map<Ipv6Address, Ptr<UeInfo> >::iterator it = m_ueInfoByAddrMap6.find (ueAddr);
|
||||
if (it == m_ueInfoByAddrMap6.end ())
|
||||
{
|
||||
NS_LOG_WARN ("unknown UE address " << ueAddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Ipv4Address enbAddr = it->second->GetEnbAddr ();
|
||||
uint32_t teid = it->second->Classify (packet, protocolNumber);
|
||||
if (teid == 0)
|
||||
{
|
||||
NS_LOG_WARN ("no matching bearer for this packet");
|
||||
}
|
||||
else
|
||||
{
|
||||
SendToS1uSocket (packet, enbAddr, teid);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ABORT_MSG ("EpcSgwPgwApplication::RecvFromTunDevice - Unknown IP type...");
|
||||
}
|
||||
|
||||
// there is no reason why we should notify the TUN
|
||||
// VirtualNetDevice that he failed to send the packet: if we receive
|
||||
// any bogus packet, it will just be silently discarded.
|
||||
const bool succeeded = true;
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::RecvFromS1uSocket (Ptr<Socket> socket)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << socket);
|
||||
NS_ASSERT (socket == m_s1uSocket);
|
||||
Ptr<Packet> packet = socket->Recv ();
|
||||
GtpuHeader gtpu;
|
||||
packet->RemoveHeader (gtpu);
|
||||
uint32_t teid = gtpu.GetTeid ();
|
||||
|
||||
SendToTunDevice (packet, teid);
|
||||
|
||||
m_rxS1uPktTrace (packet->Copy ());
|
||||
}
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::SendToTunDevice (Ptr<Packet> packet, uint32_t teid)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << packet << teid);
|
||||
NS_LOG_LOGIC (" packet size: " << packet->GetSize () << " bytes");
|
||||
|
||||
uint8_t ipType;
|
||||
packet->CopyData (&ipType, 1);
|
||||
ipType = (ipType>>4) & 0x0f;
|
||||
|
||||
if (ipType == 0x04)
|
||||
{
|
||||
m_tunDevice->Receive (packet, 0x0800, m_tunDevice->GetAddress (), m_tunDevice->GetAddress (), NetDevice::PACKET_HOST);
|
||||
}
|
||||
else if (ipType == 0x06)
|
||||
{
|
||||
m_tunDevice->Receive (packet, 0x86DD, m_tunDevice->GetAddress (), m_tunDevice->GetAddress (), NetDevice::PACKET_HOST);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ABORT_MSG ("EpcSgwPgwApplication::SendToTunDevice - Unknown IP type...");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::SendToS1uSocket (Ptr<Packet> packet, Ipv4Address enbAddr, uint32_t teid)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << packet << enbAddr << teid);
|
||||
|
||||
GtpuHeader gtpu;
|
||||
gtpu.SetTeid (teid);
|
||||
// From 3GPP TS 29.281 v10.0.0 Section 5.1
|
||||
// Length of the payload + the non obligatory GTP-U header
|
||||
gtpu.SetLength (packet->GetSize () + gtpu.GetSerializedSize () - 8);
|
||||
packet->AddHeader (gtpu);
|
||||
uint32_t flags = 0;
|
||||
m_s1uSocket->SendTo (packet, flags, InetSocketAddress (enbAddr, m_gtpuUdpPort));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::SetS11SapMme (EpcS11SapMme * s)
|
||||
{
|
||||
m_s11SapMme = s;
|
||||
}
|
||||
|
||||
EpcS11SapSgw*
|
||||
EpcSgwPgwApplication::GetS11SapSgw ()
|
||||
{
|
||||
return m_s11SapSgw;
|
||||
}
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::AddEnb (uint16_t cellId, Ipv4Address enbAddr, Ipv4Address sgwAddr)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << cellId << enbAddr << sgwAddr);
|
||||
EnbInfo enbInfo;
|
||||
enbInfo.enbAddr = enbAddr;
|
||||
enbInfo.sgwAddr = sgwAddr;
|
||||
m_enbInfoByCellId[cellId] = enbInfo;
|
||||
}
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::AddUe (uint64_t imsi)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << imsi);
|
||||
Ptr<UeInfo> ueInfo = Create<UeInfo> ();
|
||||
m_ueInfoByImsiMap[imsi] = ueInfo;
|
||||
}
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::SetUeAddress (uint64_t imsi, Ipv4Address ueAddr)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << imsi << ueAddr);
|
||||
std::map<uint64_t, Ptr<UeInfo> >::iterator ueit = m_ueInfoByImsiMap.find (imsi);
|
||||
NS_ASSERT_MSG (ueit != m_ueInfoByImsiMap.end (), "unknown IMSI " << imsi);
|
||||
m_ueInfoByAddrMap[ueAddr] = ueit->second;
|
||||
ueit->second->SetUeAddr (ueAddr);
|
||||
}
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::SetUeAddress6 (uint64_t imsi, Ipv6Address ueAddr)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << imsi << ueAddr);
|
||||
std::map<uint64_t, Ptr<UeInfo> >::iterator ueit = m_ueInfoByImsiMap.find (imsi);
|
||||
NS_ASSERT_MSG (ueit != m_ueInfoByImsiMap.end (), "unknown IMSI " << imsi);
|
||||
m_ueInfoByAddrMap6[ueAddr] = ueit->second;
|
||||
ueit->second->SetUeAddr6 (ueAddr);
|
||||
}
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::DoCreateSessionRequest (EpcS11SapSgw::CreateSessionRequestMessage req)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << req.imsi);
|
||||
std::map<uint64_t, Ptr<UeInfo> >::iterator ueit = m_ueInfoByImsiMap.find (req.imsi);
|
||||
NS_ASSERT_MSG (ueit != m_ueInfoByImsiMap.end (), "unknown IMSI " << req.imsi);
|
||||
uint16_t cellId = req.uli.gci;
|
||||
std::map<uint16_t, EnbInfo>::iterator enbit = m_enbInfoByCellId.find (cellId);
|
||||
NS_ASSERT_MSG (enbit != m_enbInfoByCellId.end (), "unknown CellId " << cellId);
|
||||
Ipv4Address enbAddr = enbit->second.enbAddr;
|
||||
ueit->second->SetEnbAddr (enbAddr);
|
||||
|
||||
EpcS11SapMme::CreateSessionResponseMessage res;
|
||||
res.teid = req.imsi; // trick to avoid the need for allocating TEIDs on the S11 interface
|
||||
|
||||
for (std::list<EpcS11SapSgw::BearerContextToBeCreated>::iterator bit = req.bearerContextsToBeCreated.begin ();
|
||||
bit != req.bearerContextsToBeCreated.end ();
|
||||
++bit)
|
||||
{
|
||||
// simple sanity check. If you ever need more than 4M teids
|
||||
// throughout your simulation, you'll need to implement a smarter teid
|
||||
// management algorithm.
|
||||
NS_ABORT_IF (m_teidCount == 0xFFFFFFFF);
|
||||
uint32_t teid = ++m_teidCount;
|
||||
ueit->second->AddBearer (bit->tft, bit->epsBearerId, teid);
|
||||
|
||||
EpcS11SapMme::BearerContextCreated bearerContext;
|
||||
bearerContext.sgwFteid.teid = teid;
|
||||
bearerContext.sgwFteid.address = enbit->second.sgwAddr;
|
||||
bearerContext.epsBearerId = bit->epsBearerId;
|
||||
bearerContext.bearerLevelQos = bit->bearerLevelQos;
|
||||
bearerContext.tft = bit->tft;
|
||||
res.bearerContextsCreated.push_back (bearerContext);
|
||||
}
|
||||
m_s11SapMme->CreateSessionResponse (res);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::DoModifyBearerRequest (EpcS11SapSgw::ModifyBearerRequestMessage req)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << req.teid);
|
||||
uint64_t imsi = req.teid; // trick to avoid the need for allocating TEIDs on the S11 interface
|
||||
std::map<uint64_t, Ptr<UeInfo> >::iterator ueit = m_ueInfoByImsiMap.find (imsi);
|
||||
NS_ASSERT_MSG (ueit != m_ueInfoByImsiMap.end (), "unknown IMSI " << imsi);
|
||||
uint16_t cellId = req.uli.gci;
|
||||
std::map<uint16_t, EnbInfo>::iterator enbit = m_enbInfoByCellId.find (cellId);
|
||||
NS_ASSERT_MSG (enbit != m_enbInfoByCellId.end (), "unknown CellId " << cellId);
|
||||
Ipv4Address enbAddr = enbit->second.enbAddr;
|
||||
ueit->second->SetEnbAddr (enbAddr);
|
||||
// no actual bearer modification: for now we just support the minimum needed for path switch request (handover)
|
||||
EpcS11SapMme::ModifyBearerResponseMessage res;
|
||||
res.teid = imsi; // trick to avoid the need for allocating TEIDs on the S11 interface
|
||||
res.cause = EpcS11SapMme::ModifyBearerResponseMessage::REQUEST_ACCEPTED;
|
||||
m_s11SapMme->ModifyBearerResponse (res);
|
||||
}
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::DoDeleteBearerCommand (EpcS11SapSgw::DeleteBearerCommandMessage req)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << req.teid);
|
||||
uint64_t imsi = req.teid; // trick to avoid the need for allocating TEIDs on the S11 interface
|
||||
std::map<uint64_t, Ptr<UeInfo> >::iterator ueit = m_ueInfoByImsiMap.find (imsi);
|
||||
NS_ASSERT_MSG (ueit != m_ueInfoByImsiMap.end (), "unknown IMSI " << imsi);
|
||||
|
||||
EpcS11SapMme::DeleteBearerRequestMessage res;
|
||||
res.teid = imsi;
|
||||
|
||||
for (std::list<EpcS11SapSgw::BearerContextToBeRemoved>::iterator bit = req.bearerContextsToBeRemoved.begin ();
|
||||
bit != req.bearerContextsToBeRemoved.end ();
|
||||
++bit)
|
||||
{
|
||||
EpcS11SapMme::BearerContextRemoved bearerContext;
|
||||
bearerContext.epsBearerId = bit->epsBearerId;
|
||||
res.bearerContextsRemoved.push_back (bearerContext);
|
||||
}
|
||||
//schedules Delete Bearer Request towards MME
|
||||
m_s11SapMme->DeleteBearerRequest (res);
|
||||
}
|
||||
|
||||
void
|
||||
EpcSgwPgwApplication::DoDeleteBearerResponse (EpcS11SapSgw::DeleteBearerResponseMessage req)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << req.teid);
|
||||
uint64_t imsi = req.teid; // trick to avoid the need for allocating TEIDs on the S11 interface
|
||||
std::map<uint64_t, Ptr<UeInfo> >::iterator ueit = m_ueInfoByImsiMap.find (imsi);
|
||||
NS_ASSERT_MSG (ueit != m_ueInfoByImsiMap.end (), "unknown IMSI " << imsi);
|
||||
|
||||
for (std::list<EpcS11SapSgw::BearerContextRemovedSgwPgw>::iterator bit = req.bearerContextsRemoved.begin ();
|
||||
bit != req.bearerContextsRemoved.end ();
|
||||
++bit)
|
||||
{
|
||||
//Function to remove de-activated bearer contexts from S-Gw and P-Gw side
|
||||
ueit->second->RemoveBearer (bit->epsBearerId);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
@@ -1,351 +0,0 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Jaume Nin <jnin@cttc.cat>
|
||||
* Nicola Baldo <nbaldo@cttc.cat>
|
||||
*/
|
||||
|
||||
#ifndef EPC_SGW_PGW_APPLICATION_H
|
||||
#define EPC_SGW_PGW_APPLICATION_H
|
||||
|
||||
#include <ns3/address.h>
|
||||
#include <ns3/socket.h>
|
||||
#include <ns3/virtual-net-device.h>
|
||||
#include <ns3/traced-callback.h>
|
||||
#include <ns3/callback.h>
|
||||
#include <ns3/ptr.h>
|
||||
#include <ns3/object.h>
|
||||
#include <ns3/eps-bearer.h>
|
||||
#include <ns3/epc-tft.h>
|
||||
#include <ns3/epc-tft-classifier.h>
|
||||
#include <ns3/lte-common.h>
|
||||
#include <ns3/application.h>
|
||||
#include <ns3/epc-s1ap-sap.h>
|
||||
#include <ns3/epc-s11-sap.h>
|
||||
#include <map>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \ingroup lte
|
||||
*
|
||||
* This application implements the SGW/PGW functionality.
|
||||
*/
|
||||
class EpcSgwPgwApplication : public Application
|
||||
{
|
||||
/// allow MemberEpcS11SapSgw<EpcSgwPgwApplication> class friend access
|
||||
friend class MemberEpcS11SapSgw<EpcSgwPgwApplication>;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
virtual void DoDispose ();
|
||||
|
||||
/**
|
||||
* Constructor that binds the tap device to the callback methods.
|
||||
*
|
||||
* \param tunDevice TUN VirtualNetDevice used to tunnel IP packets from
|
||||
* the Gi interface of the PGW/SGW over the
|
||||
* internet over GTP-U/UDP/IP on the S1-U interface
|
||||
* \param s1uSocket socket used to send GTP-U packets to the eNBs
|
||||
*/
|
||||
|
||||
EpcSgwPgwApplication (const Ptr<VirtualNetDevice> tunDevice, const Ptr<Socket> s1uSocket);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~EpcSgwPgwApplication (void);
|
||||
|
||||
/**
|
||||
* Method to be assigned to the callback of the Gi TUN VirtualNetDevice. It
|
||||
* is called when the SGW/PGW receives a data packet from the
|
||||
* internet (including IP headers) that is to be sent to the UE via
|
||||
* its associated eNB, tunneling IP over GTP-U/UDP/IP.
|
||||
*
|
||||
* \param packet
|
||||
* \param source
|
||||
* \param dest
|
||||
* \param protocolNumber
|
||||
* \return true always
|
||||
*/
|
||||
bool RecvFromTunDevice (Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber);
|
||||
|
||||
|
||||
/**
|
||||
* Method to be assigned to the recv callback of the S1-U socket. It
|
||||
* is called when the SGW/PGW receives a data packet from the eNB
|
||||
* that is to be forwarded to the internet.
|
||||
*
|
||||
* \param socket pointer to the S1-U socket
|
||||
*/
|
||||
void RecvFromS1uSocket (Ptr<Socket> socket);
|
||||
|
||||
/**
|
||||
* Send a packet to the internet via the Gi interface of the SGW/PGW
|
||||
*
|
||||
* \param packet
|
||||
* \param teid the Tunnel Enpoint Identifier
|
||||
*/
|
||||
void SendToTunDevice (Ptr<Packet> packet, uint32_t teid);
|
||||
|
||||
|
||||
/**
|
||||
* Send a packet to the SGW via the S1-U interface
|
||||
*
|
||||
* \param packet packet to be sent
|
||||
* \param enbS1uAddress the address of the eNB
|
||||
* \param teid the Tunnel Enpoint IDentifier
|
||||
*/
|
||||
void SendToS1uSocket (Ptr<Packet> packet, Ipv4Address enbS1uAddress, uint32_t teid);
|
||||
|
||||
|
||||
/**
|
||||
* Set the MME side of the S11 SAP
|
||||
*
|
||||
* \param s the MME side of the S11 SAP
|
||||
*/
|
||||
void SetS11SapMme (EpcS11SapMme * s);
|
||||
|
||||
/**
|
||||
*
|
||||
* \return the SGW side of the S11 SAP
|
||||
*/
|
||||
EpcS11SapSgw* GetS11SapSgw ();
|
||||
|
||||
|
||||
/**
|
||||
* Let the SGW be aware of a new eNB
|
||||
*
|
||||
* \param cellId the cell identifier
|
||||
* \param enbAddr the address of the eNB
|
||||
* \param sgwAddr the address of the SGW
|
||||
*/
|
||||
void AddEnb (uint16_t cellId, Ipv4Address enbAddr, Ipv4Address sgwAddr);
|
||||
|
||||
/**
|
||||
* Let the SGW be aware of a new UE
|
||||
*
|
||||
* \param imsi the unique identifier of the UE
|
||||
*/
|
||||
void AddUe (uint64_t imsi);
|
||||
|
||||
/**
|
||||
* set the address of a previously added UE
|
||||
*
|
||||
* \param imsi the unique identifier of the UE
|
||||
* \param ueAddr the IPv4 address of the UE
|
||||
*/
|
||||
void SetUeAddress (uint64_t imsi, Ipv4Address ueAddr);
|
||||
|
||||
/**
|
||||
* set the address of a previously added UE
|
||||
*
|
||||
* \param imsi the unique identifier of the UE
|
||||
* \param ueAddr the IPv6 address of the UE
|
||||
*/
|
||||
void SetUeAddress6 (uint64_t imsi, Ipv6Address ueAddr);
|
||||
|
||||
/**
|
||||
* TracedCallback signature for data Packet reception event.
|
||||
*
|
||||
* \param [in] packet The data packet sent from the internet.
|
||||
*/
|
||||
typedef void (* RxTracedCallback)
|
||||
(Ptr<Packet> packet);
|
||||
|
||||
private:
|
||||
|
||||
// S11 SAP SGW methods
|
||||
/**
|
||||
* Create session request function
|
||||
* \param msg EpcS11SapSgw::CreateSessionRequestMessage
|
||||
*/
|
||||
void DoCreateSessionRequest (EpcS11SapSgw::CreateSessionRequestMessage msg);
|
||||
/**
|
||||
* Modify bearer request function
|
||||
* \param msg EpcS11SapSgw::ModifyBearerRequestMessage
|
||||
*/
|
||||
void DoModifyBearerRequest (EpcS11SapSgw::ModifyBearerRequestMessage msg);
|
||||
|
||||
/**
|
||||
* Delete bearer command function
|
||||
* \param req EpcS11SapSgw::DeleteBearerCommandMessage
|
||||
*/
|
||||
void DoDeleteBearerCommand (EpcS11SapSgw::DeleteBearerCommandMessage req);
|
||||
/**
|
||||
* Delete bearer response function
|
||||
* \param req EpcS11SapSgw::DeleteBearerResponseMessage
|
||||
*/
|
||||
void DoDeleteBearerResponse (EpcS11SapSgw::DeleteBearerResponseMessage req);
|
||||
|
||||
|
||||
/**
|
||||
* store info for each UE connected to this SGW
|
||||
*/
|
||||
class UeInfo : public SimpleRefCount<UeInfo>
|
||||
{
|
||||
public:
|
||||
UeInfo ();
|
||||
|
||||
/**
|
||||
*
|
||||
* \param tft the Traffic Flow Template of the new bearer to be added
|
||||
* \param epsBearerId the ID of the EPS Bearer to be activated
|
||||
* \param teid the TEID of the new bearer
|
||||
*/
|
||||
void AddBearer (Ptr<EpcTft> tft, uint8_t epsBearerId, uint32_t teid);
|
||||
|
||||
/**
|
||||
* \brief Function, deletes contexts of bearer on SGW and PGW side
|
||||
* \param bearerId the Bearer Id whose contexts to be removed
|
||||
*/
|
||||
void RemoveBearer (uint8_t bearerId);
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* \param p the IP packet from the internet to be classified
|
||||
* \param protocolNumber the protocol number of the IP packet
|
||||
*
|
||||
* \return the corresponding bearer ID > 0 identifying the bearer
|
||||
* among all the bearers of this UE; returns 0 if no bearers
|
||||
* matches with the previously declared TFTs
|
||||
*/
|
||||
uint32_t Classify (Ptr<Packet> p, uint16_t protocolNumber);
|
||||
|
||||
/**
|
||||
* \return the address of the eNB to which the UE is connected
|
||||
*/
|
||||
Ipv4Address GetEnbAddr ();
|
||||
|
||||
/**
|
||||
* set the address of the eNB to which the UE is connected
|
||||
*
|
||||
* \param addr the address of the eNB
|
||||
*/
|
||||
void SetEnbAddr (Ipv4Address addr);
|
||||
|
||||
/**
|
||||
* \return the IPv4 address of the UE
|
||||
*/
|
||||
Ipv4Address GetUeAddr ();
|
||||
|
||||
/**
|
||||
* set the IPv4 address of the UE
|
||||
*
|
||||
* \param addr the IPv4 address of the UE
|
||||
*/
|
||||
void SetUeAddr (Ipv4Address addr);
|
||||
|
||||
/**
|
||||
* \return the IPv6 address of the UE
|
||||
*/
|
||||
Ipv6Address GetUeAddr6 ();
|
||||
|
||||
/**
|
||||
* set the IPv6 address of the UE
|
||||
*
|
||||
* \param addr the IPv6 address of the UE
|
||||
*/
|
||||
void SetUeAddr6 (Ipv6Address addr);
|
||||
|
||||
private:
|
||||
EpcTftClassifier m_tftClassifier; ///< TFT classifier
|
||||
Ipv4Address m_enbAddr; ///< ENB IPv4 address
|
||||
Ipv4Address m_ueAddr; ///< UE IPv4 address
|
||||
Ipv6Address m_ueAddr6; ///< UE IPv6 address
|
||||
std::map<uint8_t, uint32_t> m_teidByBearerIdMap; ///< TEID By bearer ID Map
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* UDP socket to send and receive GTP-U packets to and from the S1-U interface
|
||||
*/
|
||||
Ptr<Socket> m_s1uSocket;
|
||||
|
||||
/**
|
||||
* TUN VirtualNetDevice used for tunneling/detunneling IP packets
|
||||
* from/to the internet over GTP-U/UDP/IP on the S1 interface
|
||||
*/
|
||||
Ptr<VirtualNetDevice> m_tunDevice;
|
||||
|
||||
/**
|
||||
* Map telling for each UE IPv4 address the corresponding UE info
|
||||
*/
|
||||
std::map<Ipv4Address, Ptr<UeInfo> > m_ueInfoByAddrMap;
|
||||
|
||||
/**
|
||||
* Map telling for each UE IPv6 address the corresponding UE info
|
||||
*/
|
||||
std::map<Ipv6Address, Ptr<UeInfo> > m_ueInfoByAddrMap6;
|
||||
|
||||
/**
|
||||
* Map telling for each IMSI the corresponding UE info
|
||||
*/
|
||||
std::map<uint64_t, Ptr<UeInfo> > m_ueInfoByImsiMap;
|
||||
|
||||
/**
|
||||
* UDP port to be used for GTP
|
||||
*/
|
||||
uint16_t m_gtpuUdpPort;
|
||||
|
||||
/**
|
||||
* TEID count
|
||||
*/
|
||||
uint32_t m_teidCount;
|
||||
|
||||
/**
|
||||
* MME side of the S11 SAP
|
||||
*
|
||||
*/
|
||||
EpcS11SapMme* m_s11SapMme;
|
||||
|
||||
/**
|
||||
* SGW side of the S11 SAP
|
||||
*
|
||||
*/
|
||||
EpcS11SapSgw* m_s11SapSgw;
|
||||
|
||||
/// EnbInfo structure
|
||||
struct EnbInfo
|
||||
{
|
||||
Ipv4Address enbAddr; ///< eNB IPv4 address
|
||||
Ipv4Address sgwAddr; ///< SGW IPV4 address
|
||||
};
|
||||
|
||||
std::map<uint16_t, EnbInfo> m_enbInfoByCellId; ///< eNB info by cell ID
|
||||
|
||||
/**
|
||||
* \brief Callback to trace RX (reception) data packets at Tun Net Device from internet.
|
||||
*/
|
||||
TracedCallback<Ptr<Packet> > m_rxTunPktTrace;
|
||||
|
||||
/**
|
||||
* \brief Callback to trace RX (reception) data packets from S1-U socket.
|
||||
*/
|
||||
TracedCallback<Ptr<Packet> > m_rxS1uPktTrace;
|
||||
};
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
#endif /* EPC_SGW_PGW_APPLICATION_H */
|
||||
|
||||
@@ -43,6 +43,7 @@ def build(bld):
|
||||
'helper/lte-helper.cc',
|
||||
'helper/lte-stats-calculator.cc',
|
||||
'helper/epc-helper.cc',
|
||||
'helper/no-backhaul-epc-helper.cc',
|
||||
'helper/point-to-point-epc-helper.cc',
|
||||
'helper/radio-bearer-stats-calculator.cc',
|
||||
'helper/radio-bearer-stats-connector.cc',
|
||||
@@ -86,7 +87,6 @@ def build(bld):
|
||||
'model/epc-gtpu-header.cc',
|
||||
'model/epc-gtpc-header.cc',
|
||||
'model/epc-enb-application.cc',
|
||||
'model/epc-sgw-pgw-application.cc',
|
||||
'model/epc-sgw-application.cc',
|
||||
'model/epc-pgw-application.cc',
|
||||
'model/epc-mme-application.cc',
|
||||
@@ -103,7 +103,6 @@ def build(bld):
|
||||
'model/lte-as-sap.cc',
|
||||
'model/epc-ue-nas.cc',
|
||||
'model/lte-harq-phy.cc',
|
||||
'model/epc-mme.cc',
|
||||
'model/lte-asn1-header.cc',
|
||||
'model/lte-rrc-header.cc',
|
||||
'model/lte-handover-management-sap.cc',
|
||||
@@ -238,6 +237,7 @@ def build(bld):
|
||||
'helper/lte-helper.h',
|
||||
'helper/lte-stats-calculator.h',
|
||||
'helper/epc-helper.h',
|
||||
'helper/no-backhaul-epc-helper.h',
|
||||
'helper/point-to-point-epc-helper.h',
|
||||
'helper/phy-stats-calculator.h',
|
||||
'helper/mac-stats-calculator.h',
|
||||
@@ -281,7 +281,6 @@ def build(bld):
|
||||
'model/epc-gtpu-header.h',
|
||||
'model/epc-gtpc-header.h',
|
||||
'model/epc-enb-application.h',
|
||||
'model/epc-sgw-pgw-application.h',
|
||||
'model/epc-sgw-application.h',
|
||||
'model/epc-pgw-application.h',
|
||||
'model/epc-mme-application.h',
|
||||
@@ -298,7 +297,6 @@ def build(bld):
|
||||
'model/lte-as-sap.h',
|
||||
'model/epc-ue-nas.h',
|
||||
'model/lte-harq-phy.h',
|
||||
'model/epc-mme.h',
|
||||
'model/lte-asn1-header.h',
|
||||
'model/lte-rrc-header.h',
|
||||
'model/lte-handover-management-sap.h',
|
||||
|
||||
Reference in New Issue
Block a user