lte: EPC upgrade

The LTE/EPC model has been enhanced with new features:
    * SGW, PGW and MME are full nodes.
    * There are P2P links between core network nodes.
    * New S5 interface between SGW and PGW nodes based on GTPv2-C protocol.
    * Allow simulations with multiple SGWs and PGWs.

LTE eNB RRC is extended to support:
    * S1 signalling with the core network is initiated after the
      RRC connection establishment procedure is finished.
    * New ATTACH_REQUEST state to wait for finalization of the S1
      signalling with the core network.
    * New InitialContextSetupRequest primitive of the S1 SAP that is
      received by the eNB RRC when the S1 signalling from the core network
      is finished.

Squashed commit of the following from mrequena:epc-upgrade:

    lte: Clarify that e2e is IPv4/IPv6 and core network is IPv4-only
    lte: Remove duplicated example from wscript
    lte: Add new features of the EPC upgrade to CHANGES.html
    lte: Remove duplicated example
    lte: (fixes #3027) S1 signalling is done before RRC connection establishment is finished
    lte: Add new ATTACH_REQUEST state in eNB RRC
    lte: cast a uint8_t when logging
    lte: Fix doxygen comments and doc typos
    lte: Add documentation for EPC split
    lte: Use protocolNumber in new EpcPgwApplication
    lte: Add doxygen doc for EpcSgwApplication class
    lte: Add doxygen doc for EpcPgwApplication class
    lte: Add doxygen doc for EpcMmeApplication class
    lte: PreSerialize/PreDesearialize are only used in the derived messages
    lte: Command line parameters take precedence over parameters in config file
    lte: Rename number of node pairs variable
    lte: Add IPv6 support to new PgwApplication
    lte: Change to new pgw node
    lte: Number of nodes has changed after EPC split
    lte: InitialUeMessage cannot be called if simulation is not started
    lte: Change some names of addresses and clean debug code
    lte: New GetPacketFilters method
    lte: Add new files to build system
    lte: Don't need to build the GtpcHeader by hand, just the message
    lte: GTPC messages derived from GtpcHeader
    lte: Add new PGW Application
    lte: Add new SGW Application
    lte: Add new MME Application
    lte: Add new GTP-C protocol header
    lte: Split SGW/PGW/MME in different nodes
    lte: Add new example
This commit is contained in:
Manuel Requena
2019-01-12 17:51:17 -08:00
committed by Tom Henderson
parent bba146ea39
commit 4dd0821ed6
33 changed files with 4652 additions and 271 deletions

View File

@@ -83,6 +83,21 @@ us a note on ns-developers mailing list.</p>
<h2>Changed behavior:</h2>
<ul>
<li>The wifi ADDBA handshake process is now protected with the use of two timeouts who makes sure we do not end up in a blocked situation. If the handshake process is not established, packets that are in the queue are sent as normal MPDUs. Once handshake is successfully established, A-MPDUs can be transmitted.</li>
<li>LTE/EPC model has been enhanced with the new features. These new features allow the simulation user to test more realistic simulations related to the core network. These features are:<li>
<ul>
<li>SGW, PGW and MME are full nodes.</li>
<li>There are P2P links between core network nodes.</li>
<li>New S5 interface between SGW and PGW nodes based on GTPv2-C protocol.</li>
<li>Allow simulations with multiple SGWs and PGWs.</li>
</ul>
</li>
<li>LTE eNB RRC is extended to support:</li>
<ul>
<li>S1 signalling with the core network is initiated after the RRC connection establishment procedure is finished.</li>
<li>New ATTACH_REQUEST state to wait for finalization of the S1 signalling with the core network.</li>
<li>New InitialContextSetupRequest primitive of the S1 SAP that is received by the eNB RRC when the S1 signalling from the core network is finished.</li>
</ul>
</li>
</ul>
<hr>

View File

@@ -32,6 +32,7 @@ Bugs fixed
- Bug 2992 - lte: Send method of the LteUeNetDevice doesn't use protocolNumber parameter
- Bug 2997 - lte: EpcTft::PacketFilter::Matches does not use ipv6 address to match an IP packet
- Bug 2860 - mobility: Set Z coordinate for position-allocation classes
- Bug 3027 - lte: S1 signalling is done before RRC connection establishment is finished
Known issues
------------

View File

@@ -130,9 +130,12 @@ SOURCEFIGS = \
$(SRC)/wimax/doc/WimaxArchitecture.dia \
$(SRC)/lte/doc/source/figures/epc-ctrl-arch.dia \
$(SRC)/lte/doc/source/figures/epc-data-flow-dl.dia \
$(SRC)/lte/doc/source/figures/epc-data-flow-dl-with-split.dia \
$(SRC)/lte/doc/source/figures/epc-data-flow-ul.dia \
$(SRC)/lte/doc/source/figures/epc-data-flow-ul-with-split.dia \
$(SRC)/lte/doc/source/figures/epc-profiling-scenario.dia \
$(SRC)/lte/doc/source/figures/epc-topology.dia \
$(SRC)/lte/doc/source/figures/epc-topology-with-split.dia \
$(SRC)/lte/doc/source/figures/epc-topology-x2-enhanced.dia \
$(SRC)/lte/doc/source/figures/eutran-profiling-scenario.dia \
$(SRC)/lte/doc/source/figures/ff-example.dia \
@@ -144,7 +147,8 @@ SOURCEFIGS = \
$(SRC)/lte/doc/source/figures/lte-enb-phy.dia \
$(SRC)/lte/doc/source/figures/lte-ue-phy.dia \
$(SRC)/lte/doc/source/figures/lte-epc-x2-handover-seq-diagram.dia \
$(SRC)/lte/doc/source/figures/lte-epc-e2e-data-protocol-stack.dia \
$(SRC)/lte/doc/source/figures/lte-epc-e2e-data-protocol-stack-with-split.dia \
$(SRC)/lte/doc/source/figures/lte-epc-e2e-control-protocol-stack-with-split.dia \
$(SRC)/lte/doc/source/figures/lte-interference-test-scenario.dia \
$(SRC)/lte/doc/source/figures/lte-subframe-structure.dia \
$(SRC)/lte/doc/source/figures/lte-epc-x2-interface.dia \
@@ -319,9 +323,12 @@ IMAGES_EPS = \
$(FIGURES)/WimaxArchitecture.eps \
$(FIGURES)/epc-ctrl-arch.eps \
$(FIGURES)/epc-data-flow-dl.eps \
$(FIGURES)/epc-data-flow-dl-with-split.eps \
$(FIGURES)/epc-data-flow-ul.eps \
$(FIGURES)/epc-data-flow-ul-with-split.eps \
$(FIGURES)/epc-profiling-scenario.eps \
$(FIGURES)/epc-topology.eps \
$(FIGURES)/epc-topology-with-split.eps \
$(FIGURES)/epc-topology-x2-enhanced.eps \
$(FIGURES)/eutran-profiling-scenario.eps \
$(FIGURES)/ff-example.eps \
@@ -343,6 +350,8 @@ IMAGES_EPS = \
$(FIGURES)/lte-enb-phy.eps \
$(FIGURES)/lte-ue-phy.eps \
$(FIGURES)/lte-epc-e2e-data-protocol-stack.eps \
$(FIGURES)/lte-epc-e2e-data-protocol-stack-with-split.eps \
$(FIGURES)/lte-epc-e2e-control-protocol-stack-with-split.eps \
$(FIGURES)/lte-interference-test-scenario.eps \
$(FIGURES)/lte-subframe-structure.eps \
$(FIGURES)/lte-epc-x2-interface.eps \

View File

@@ -13,9 +13,12 @@ FIGURES = $(SOURCE)/figures
IMAGES_DIA = \
$(FIGURES)/epc-ctrl-arch.dia \
$(FIGURES)/epc-data-flow-dl.dia \
$(FIGURES)/epc-data-flow-dl-with-split.dia \
$(FIGURES)/epc-data-flow-ul.dia \
$(FIGURES)/epc-data-flow-ul-with-split.dia \
$(FIGURES)/epc-profiling-scenario.dia \
$(FIGURES)/epc-topology.dia \
$(FIGURES)/epc-topology-with-split.dia \
$(FIGURES)/epc-topology-x2-enhanced.dia \
$(FIGURES)/eutran-profiling-scenario.dia \
$(FIGURES)/ff-example.dia \
@@ -27,7 +30,8 @@ IMAGES_DIA = \
$(FIGURES)/lte-enb-phy.dia \
$(FIGURES)/lte-ue-phy.dia \
$(FIGURES)/lte-epc-x2-handover-seq-diagram.dia \
$(FIGURES)/lte-epc-e2e-data-protocol-stack.dia \
$(FIGURES)/lte-epc-e2e-data-protocol-stack-with-split.dia \
$(FIGURES)/lte-epc-e2e-control-protocol-stack-with-split.dia \
$(FIGURES)/lte-interference-test-scenario.dia \
$(FIGURES)/lte-subframe-structure.dia \
$(FIGURES)/lte-epc-x2-interface.dia \

View File

@@ -1,24 +1,34 @@
diagram {
SimProgram; LteHelper; EpcHelper;
SimProgram ->> LteHelper [label="create"]
SimProgram ->> EpcHelper [label="create"]
EpcHelper ->> EpcHelper [label="create MME and SGW/PGW"]
SimProgram ->> LteHelper [label="InstallEnbDevice"]
LteHelper ->> LteHelper [label="install protocol stack on eNB"]
LteHelper ->> EpcHelper [label="AddEnb"]
EpcHelper ->> EpcHelper [label="setup S1-U, S1-AP and S11"]
SimProgram ->> LteHelper [label="InstallUeDevice"]
LteHelper ->> LteHelper [label="install protocol stack on UE"]
SimProgram ->> LteHelper [label="Attach (UE, eNB)"]
LteHelper ->> LteHelper [label="tell UE NAS to start connection"]
LteHelper ->> EpcHelper [label="ActivateEpsBearer (default)"]
EpcHelper ->> EpcHelper [label="tell MME to activate bearer when UE connects"]
SimProgram ->> LteHelper [label="ActivateDedicatedEpsBearer"]
LteHelper ->> EpcHelper [label="ActivateEpsBearer"]
EpcHelper ->> EpcHelper [label="tell MME to activate bearer when UE connects"]
SimProgram => LteHelper [label="create"]
SimProgram => EpcHelper [label="create"] {
EpcHelper -> EpcHelper [label="create MME, SGW and PGW"]
}
}
SimProgram => LteHelper [label="InstallEnbDevice"] {
LteHelper -> LteHelper [label="install protocol stack on eNB"]
LteHelper => EpcHelper [label="AddEnb"] {
EpcHelper -> EpcHelper [label="setup S1-U, S1-AP, S5 and S11"]
}
}
SimProgram => LteHelper [label="InstallUeDevice"] {
LteHelper -> LteHelper [label="install protocol stack on UE"]
}
SimProgram => LteHelper [label="Attach (UE, eNB)"] {
LteHelper -> LteHelper [label="tell UE NAS to start connection"]
LteHelper => EpcHelper [label="ActivateEpsBearer (default)"] {
EpcHelper -> EpcHelper [label="tell MME to activate bearer when UE connects"]
}
}
SimProgram => LteHelper [label="ActivateDedicatedEpsBearer"] {
LteHelper => EpcHelper [label="ActivateEpsBearer"] {
EpcHelper -> EpcHelper [label="tell MME to activate bearer when UE connects"]
}
}
}

View File

@@ -1,24 +1,25 @@
diagram {
EpcUeNas; LteUeRrc; LteEnbRrc; EpcEnbApplication; EpcSgwPgwApplication; EpcMme;
EpcUeNas; LteUeRrc; LteEnbRrc; EpcEnbApplication; EpcMmeApplication; EpcSgwApplication; EpcPgwApplication;
EpcUeNas ->> LteUeRrc [label="ForceCampedOnEnb (CellId)"];
EpcUeNas ->> LteUeRrc [label="Connect"]
LteUeRrc ->> LteEnbRrc [label="RRC Connection Request"]
LteEnbRrc ->> EpcEnbApplication [label="initial UE message"]
EpcEnbApplication ->> EpcMme [label="S1-AP INITIAL UE MESSAGE"]
EpcMme ->> EpcMme [label="store IMSI->eNB UE id (RNTI) mapping"]
EpcMme ->> EpcSgwPgwApplication [label="S11 CREATE SESSION"]
EpcSgwPgwApplication ->> EpcSgwPgwApplication [label="setup S1-U bearers"]
EpcMme <<- EpcSgwPgwApplication [label="S11 CREATE SESSION RESPONSE"]
EpcEnbApplication <<- EpcMme [label="S1-AP INITIAL CONTEXT SETUP (bearers to be created)"]
EpcEnbApplication ->> EpcMme [label="S1-AP INITIAL CONTEXT SETUP RESPONSE"]
EpcEnbApplication ->> EpcEnbApplication [label="setup S1-U bearers"]
LteEnbRrc <<- EpcEnbApplication [label="DataRadioBearerSetupRequest"]
LteEnbRrc ->> LteEnbRrc [label="setup data radio bearers"]
LteUeRrc <<- LteEnbRrc [label="RRC Connection Reconfiguration"]
LteUeRrc ->> LteUeRrc [label="setup data radio bearers"]
LteUeRrc ->> LteEnbRrc [label="RRC Connection Reconfiguration Completed"]
EpcUeNas ->> LteUeRrc [label="ForceCampedOnEnb (CellId)"]
EpcUeNas ->> LteUeRrc [label="Connect"]
LteUeRrc ->> LteEnbRrc [label="RRC Connection Request"]
LteEnbRrc ->> EpcEnbApplication [label="initial UE message"]
EpcEnbApplication ->> EpcMmeApplication [label="S1-AP INITIAL UE MESSAGE"]
EpcMmeApplication ->> EpcMmeApplication [label="store IMSI->\n eNB UE id (RNTI)\n mapping"]
EpcMmeApplication ->> EpcSgwApplication [label="S11 CREATE SESSION"]
EpcSgwApplication ->> EpcSgwApplication [label="setup S1-U\nbearers"]
EpcSgwApplication ->> EpcPgwApplication [label="S5 CREATE SESSION"]
EpcPgwApplication ->> EpcPgwApplication [label="setup S5 bearers"]
EpcSgwApplication <<- EpcPgwApplication [label="S5 CREATE SESSION\nRESPONSE"]
EpcMmeApplication <<- EpcSgwApplication [label="S11 CREATE SESSION\nRESPONSE"]
EpcEnbApplication <<- EpcMmeApplication [label="S1-AP INITIAL CONTEXT\n SETUP (bearers to be created)"]
EpcEnbApplication ->> EpcEnbApplication [label="setup S1-U\n bearers"]
LteEnbRrc <<- EpcEnbApplication [label="DataRadioBearerSetupRequest"]
LteEnbRrc ->> LteEnbRrc [label="setup data\n radio bearers"]
LteUeRrc <<- LteEnbRrc [label="RRC Connection\n Reconfiguration"]
LteUeRrc ->> LteUeRrc [label="setup data\n radio bearers"]
LteUeRrc ->> LteEnbRrc [label="RRC Connection\n Reconfiguration Completed"]
}

View File

@@ -18,7 +18,7 @@ the figure :ref:`fig-epc-topology`. There are two main components:
stack (RRC, PDCP, RLC, MAC, PHY). These entities reside entirely within the
UE and the eNB nodes.
* the EPC Model. This models includes core network
* the EPC Model. This model includes core network
interfaces, protocols and entities. These entities and protocols
reside within the SGW, PGW and MME nodes, and partially within the
eNB nodes.
@@ -26,7 +26,7 @@ the figure :ref:`fig-epc-topology`. There are two main components:
.. _fig-epc-topology:
.. figure:: figures/epc-topology.*
.. figure:: figures/epc-topology-with-split.*
:align: center
Overview of the LTE-EPC simulation model
@@ -115,16 +115,22 @@ The main objective of the EPC model is to provides means for the
simulation of end-to-end IP connectivity over the LTE model.
To this aim, it supports for the
interconnection of multiple UEs to the Internet, via a radio access
network of multiple eNBs connected to a single SGW/PGW node, as shown
network of multiple eNBs connected to the core network, as shown
in Figure :ref:`fig-epc-topology`.
The following design choices have been made for the EPC model:
#. The Packet Data Network (PDN) type supported is both IPv4 and IPv6.
#. The SGW and PGW functional entities are implemented within a single
node, which is hence referred to as the SGW/PGW node.
#. The scenarios with inter-SGW mobility are not of interests. Hence, a
single SGW/PGW node will be present in all simulations scenarios
In other words, the end-to-end connections between the UEs and the remote
hosts can be IPv4 and IPv6. However, the networks between the core network
elements (MME, SGWs and PGWs) are IPv4-only.
#. The SGW and PGW functional entities are implemented in different
nodes, which are hence referred to as the SGW node and PGW node,
respectively.
#. The MME functional entities is implemented as a network node,
which is hence referred to as the MME node.
#. The scenarios with inter-SGW mobility are not of interest. But
several SGW nodes may be present in simulations scenarios.
#. A requirement for the EPC model is that it can be used to simulate the
end-to-end performance of realistic applications. Hence, it should
be possible to use with the EPC model any regular ns-3 application
@@ -133,19 +139,20 @@ The following design choices have been made for the EPC model:
with the presence of multiple eNBs, some of which might be
equipped with a backhaul connection with limited capabilities. In
order to simulate such scenarios, the user data plane
protocols being used between the eNBs and the SGW/PGW should be
protocols being used between the eNBs and the SGW should be
modeled accurately.
#. It should be possible for a single UE to use different applications
with different QoS profiles. Hence, multiple EPS bearers should be
supported for each UE. This includes the necessary classification
of TCP/UDP traffic over IP done at the UE in the uplink and at the
PGW in the downlink.
#. The focus of the EPC model is mainly on the EPC data plane. The
accurate modeling of the EPC control plane is,
for the time being, not a requirement; hence, the necessary control plane
interactions can be modeled in a simplified way by leveraging on direct
interaction among the different simulation objects via the
provided helper objects.
#. The initial focus of the EPC model is mainly on the EPC data plane.
The accurate modeling of the EPC control plane is,
for the time being, not a requirement; however, the necessary control
plane interactions among the different network nodes of the core network
are realized by implementing control protocols/messages among them.
Direct interaction among the different simulation objects via the
provided helper objects should be avoided as much as possible.
#. The focus of the EPC model is on simulations of active users in ECM
connected mode. Hence, all the functionality that is only relevant
for ECM idle mode (in particular, tracking area update and paging)
@@ -255,54 +262,44 @@ EPC Model
EPC data plane
--------------
In Figure :ref:`fig-lte-epc-e2e-data-protocol-stack`, we represent the
In Figure :ref:`fig-lte-epc-e2e-data-protocol-stack-with-split`, we represent the
end-to-end LTE-EPC data plane protocol stack as it is modeled in the
simulator. From the figure, it is evident that the
biggest simplification introduced in the data plane model
is the inclusion of the SGW and PGW functionality within a single
SGW/PGW node, which removes the need for the S5 or S8 interfaces
specified by 3GPP. On the other hand, for both the S1-U protocol stack and
the LTE radio protocol stack all the protocol layers specified by 3GPP
are present.
simulator. The figure shows all nodes in the data path, i.e. UE, eNB,
SGW, PGW and a remote host in the Internet. All protocol stacks
(S5 protocol stack, S1-U protocol stack and the LTE radio protocol stack)
specified by 3GPP are present.
.. _fig-lte-epc-e2e-data-protocol-stack:
.. _fig-lte-epc-e2e-data-protocol-stack-with-split:
.. figure:: figures/lte-epc-e2e-data-protocol-stack.*
.. figure:: figures/lte-epc-e2e-data-protocol-stack-with-split.*
:align: center
LTE-EPC data plane protocol stack
EPC control plane
-----------------
The architecture of the implementation of the control plane model is
shown in figure :ref:`fig-epc-ctrl-arch`. The control interfaces that are
modeled explicitly are the S1-AP, the X2-AP and the S11 interfaces.
shown in figure :ref:`fig-lte-epc-e2e-control-protocol-stack-with-split`.
The control interfaces that are modeled explicitly are the S1-MME, the S11, and the S5
interfaces. The X2 interface is also modeled explicitly and it is described in more
detail in section :ref:`sec-x2`
We note that the S1-AP and the S11 interfaces are modeled in a simplified
fashion, by using just one pair of interface classes to model the
interaction between entities that reside on different nodes (the eNB
and the MME for the S1-AP interface, and the MME and the SGW for the
S11 interface). In practice, this means that the primitives of these
interfaces are mapped to a direct function call between the two
objects. On the other hand, the X2-AP interface is being modeled using
protocol data units sent over an X2 link (modeled as a point-to-point
link); for this reason, the X2-AP interface model is more realistic.
The S1-MME, the S11 and the S5 interfaces are modeled using procotol data units sent
over its respective links. These interfaces use the SCTP protocol as transport protocol
but currently, the SCTP protocol is not modeled in the ns-3 simulator, so the
UDP protocol is used instead of the SCTP protocol.
.. _fig-lte-epc-e2e-control-protocol-stack-with-split:
.. _fig-epc-ctrl-arch:
.. figure:: figures/epc-ctrl-arch.*
.. figure:: figures/lte-epc-e2e-control-protocol-stack-with-split.*
:align: center
EPC control model
LTE-EPC control plane protocol stack
@@ -3036,6 +3033,7 @@ The following RRC SAP have been implemented:
\clearpage
.. _sec-nas:
---
NAS
@@ -3044,9 +3042,9 @@ NAS
The focus of the LTE-EPC model is on the NAS Active state, which corresponds to EMM Registered, ECM connected, and RRC connected. Because of this, the following simplifications are made:
- EMM and ECM are not modeled explicitly; instead, the NAS entity at the UE will interact directly with the MME to perform actions that are equivalent (with gross simplifications) to taking the UE to the states EMM Connected and ECM Connected;
- EMM and ECM are not modeled explicitly; instead, the NAS entity at the UE will interact directly with the MME to perform actions that are equivalent (with gross simplifications) to taking the UE to the states EMM Connected and ECM Connected;
- the NAS also takes care of multiplexing uplink data packets coming from the upper layers into the appropriate EPS bearer by using the Traffic Flow Template classifier (TftClassifier).
- the NAS also takes care of multiplexing uplink data packets coming from the upper layers into the appropriate EPS bearer by using the Traffic Flow Template classifier (TftClassifier).
- the NAS does not support PLMN and CSG selection
@@ -3080,88 +3078,108 @@ procedure.
-----------------
S1
-----------------
----------------
S1, S5 and S11
----------------
S1-U
+++++++++
S1-U and S5 (user plane)
+++++++++++++++++++++++++
The S1-U interface is modeled in a realistic way by encapsulating
The S1-U and S5 interfaces are modeled in a realistic way by encapsulating
data packets over GTP/UDP/IP, as done in real LTE-EPC systems. The
corresponding protocol stack is shown in Figure
:ref:`fig-lte-epc-e2e-data-protocol-stack`. As shown in the figure,
:ref:`fig-lte-epc-e2e-data-protocol-stack-with-split`. As shown in the figure,
there are two different layers of
IP networking. The first one is the end-to-end layer, which provides end-to-end
connectivity to the users; this layers involves the UEs, the PGW and
connectivity to the users; this layer involves the UEs, the PGW and
the remote host (including eventual internet routers and hosts in
between), but does not involve the eNB. In this version of LTE, the EPC
between), but does not involve the eNB and the SGW. In this version of LTE, the EPC
supports both IPv4 and IPv6 type users. The 3GPP unique 64 bit IPv6 prefix
allocation process for each UE and PGW is followed here. Each EPC is assigned
an unique 16 bit IPv4 and a 48 bit IPv6 network address from the pool of
a unique 16 bit IPv4 and a 48 bit IPv6 network address from the pool of
7.0.0.0/8 and 7777:f00d::/32 respectively. In the end-to-end IP connection
between UE and PGW, all addresses are configured using these prefixes.
The PGW's address is used by all UEs as the gateway to reach the internet.
The second layer of IP networking is the EPC local area network. This
involves all eNB nodes and the SGW/PGW node. This network is
involves all eNB nodes, SGW nodes and PGW nodes. This network is
implemented as a set of point-to-point links which connect each eNB
with the SGW/PGW node; thus, the SGW/PGW has a set of point-to-point
devices, each providing connectivity to a different eNB. By default, a
10.x.y.z/30 subnet is assigned to each point-to-point link (a /30
subnet is the smallest subnet that allows for two distinct host
addresses).
with its corresponding SGW node and a point-to-point link which connect
each SGW node with its corresponding PGW node;
thus, each SGW has a set of point-to-point devices, each providing
connectivity to a different eNB. By default, a 10.x.y.z/30 subnet
is assigned to each point-to-point link (a /30 subnet is the smallest
subnet that allows for two distinct host addresses).
As specified by 3GPP, the end-to-end IP
communications is tunneled over the local EPC IP network using
GTP/UDP/IP. In the following, we explain how this tunneling is
implemented in the EPC model. The explanation is done by discussing the
end-to-end flow of data packets.
end-to-end flow of data packets.
.. _fig-epc-data-flow-dl:
.. _fig-epc-data-flow-dl-with-split:
.. figure:: figures/epc-data-flow-dl.*
.. figure:: figures/epc-data-flow-dl-with-split.*
:align: center
Data flow in the downlink between the internet and the UE
To begin with, we consider the case of the downlink, which is depicted
in Figure :ref:`fig-epc-data-flow-dl`.
in Figure :ref:`fig-epc-data-flow-dl-with-split`.
Downlink IPv4/IPv6 packets are generated from a generic remote host, and
addressed to one of the UE device. Internet routing will take care of
forwarding the packet to the generic NetDevice of the SGW/PGW node
forwarding the packet to the generic NetDevice of the PGW node
which is connected to the internet (this is the Gi interface according
to 3GPP terminology). The SGW/PGW has a VirtualNetDevice which is
to 3GPP terminology). The PGW has a VirtualNetDevice which is
assigned the base IPv4 address of the EPC network; hence, static
routing rules will cause the incoming packet from the internet to be
routed through this VirtualNetDevice. In case of IPv6 address as destination,
a manual route towards the VirtualNetDevice is inserted in the routing table,
containing the 48 bit IPv6 prefix from which all the IPv6 addresses of the UEs
and PGW are configured. Such device starts the GTP/UDP/IP tunneling procedure,
by forwarding the packet to a dedicated application in the SGW/PGW node which
is called EpcSgwPgwApplication. This application does the following operations:
by forwarding the packet to a dedicated application in the PGW node which
is called EpcPgwApplication. This application does the following operations:
#. it determines the eNB node to which the UE is attached, by looking
at the IP destination address (which is the address of the UE);
#. it determines the SGW node to which it must route the traffic
for this UE, by looking at the IP destination address
(which is the address of the UE);
#. it classifies the packet using Traffic Flow Templates (TFTs) to
identify to which EPS Bearer it belongs. EPS bearers have a
one-to-one mapping to S1-U Bearers, so this operation returns the
one-to-one mapping to S5 Bearers, so this operation returns the
GTP-U Tunnel Endpoint Identifier (TEID) to which the packet
belongs;
#. it adds the corresponding GTP-U protocol header to the packet;
#. finally, it sends the packet over an UDP socket to the S1-U
#. finally, it sends the packet over a UDP socket to the S5
point-to-point NetDevice, addressed to the appropriate SGW.
As a consequence, the end-to-end IP packet with newly added IP, UDP
and GTP headers is sent through one of the S5 links to the SGW, where
it is received and delivered locally (as the destination address of
the outermost IP header matches the SGW IP address). The local delivery
process will forward the packet, via an UDP socket, to a dedicated
application called EpcSgwApplication. This application then performs
the following operations:
#. it determines the eNB node to which the UE is attached, by looking
at the S5 TEID;
#. it maps the S5 TEID to get the S1 TEID. EPS bearers have a
one-to-one mapping to S1-U Bearers, so this operation returns the
S1 GTP-U Tunnel Endpoint Identifier (TEID) to which the packet
belongs;
#. it adds a new GTP-U protocol header to the packet;
#. finally, it sends the packet over a UDP socket to the S1-U
point-to-point NetDevice, addressed to the eNB to which the UE is
attached.
As a consequence, the end-to-end IP packet with newly added IP, UDP
Finally, the end-to-end IP packet with newly added IP, UDP
and GTP headers is sent through one of the S1 links to the eNB, where
it is received and delivered locally (as the destination address of
the outmost IP header matches the eNB IP address). The local delivery
the outermost IP header matches the eNB IP address). The local delivery
process will forward the packet, via an UDP socket, to a dedicated
application called EpcEnbApplication. This application then performs
the following operations:
#. it removes the GTP header and retrieves the TEID which is
#. it removes the GTP header and retrieves the S1 TEID which is
contained in it;
#. leveraging on the one-to-one mapping between S1-U bearers and
Radio Bearers (which is a 3GPP requirement), it determines the
@@ -3185,15 +3203,15 @@ the UE, which is the end point of the downlink communication.
.. _fig-epc-data-flow-ul:
.. _fig-epc-data-flow-ul-with-split:
.. figure:: figures/epc-data-flow-ul.*
.. figure:: figures/epc-data-flow-ul-with-split.*
:align: center
Data flow in the uplink between the UE and the internet
The case of the uplink is depicted in Figure :ref:`fig-epc-data-flow-ul`.
The case of the uplink is depicted in Figure :ref:`fig-epc-data-flow-ul-with-split`.
Uplink IP packets are generated by a generic application inside the UE,
and forwarded by the local TCP/IP stack to the LteUeNetDevice of the
UE. The LteUeNetDevice then performs the following operations:
@@ -3221,27 +3239,45 @@ following operations:
Bearers;
#. it adds a GTP-U header on the packet, including the TEID
determined previously;
#. it sends the packet to the SGW/PGW node via the UDP socket
#. it sends the packet to the SGW node via the UDP socket
connected to the S1-U point-to-point net device.
At this point, the packet contains the S1-U IP, UDP and GTP headers in
addition to the original end-to-end IP header. When the packet is
received by the corresponding S1-U point-to-point NetDevice of the
SGW/PGW node, it is delivered locally (as the destination address of
SGW node, it is delivered locally (as the destination address of
the outmost IP header matches the address of the point-to-point net
device). The local delivery process will forward the packet to the
EpcSgwPgwApplication via the corresponding UDP socket. The
EpcSgwPgwApplication then removes the GTP header and forwards the
EpcSgwApplication via the corresponding UDP socket. The
EpcSgwApplication then perfoms the following operations:
#. it removes the GTP header and retrieves the S1-U TEID;
#. it maps the S1-U TEID to get the S5 TEID to which the packet
belongs;
#. it determines the PGW to which it must send the packet from
the TEID mapping;
#. it add a new GTP-U protocol header to the packet;
#. finally, it sends the packet over a UDP socket to the S5
point-to-point NetDevice, addressed to the corresponding PGW.
At this point, the packet contains the S5 IP, UDP and GTP headers in
addition to the original end-to-end IP header. When the packet is
received by the corresponding S5 point-to-point NetDevice of the
PGW node, it is delivered locally (as the destination address of
the outmost IP header matches the address of the point-to-point net
device). The local delivery process will forward the packet to the
EpcPgwApplication via the corresponding UDP socket. The
EpcPgwApplication then removes the GTP header and forwards the
packet to the VirtualNetDevice. At this point, the outmost header
of the packet is the end-to-end IP header. Hence, if the destination
address within this header is a remote host on the internet, the
packet is sent to the internet via the corresponding NetDevice of the
SGW/PGW. In the event that the packet is addressed to another UE, the
IP stack of the SGW/PGW will redirect the packet again to the
VirtualNetDevice, and the packet will go through the dowlink delivery
PGW. In the event that the packet is addressed to another UE, the
IP stack of the PGW will redirect the packet again to the
VirtualNetDevice, and the packet will go through the downlink delivery
process in order to reach its destination UE.
Note that the EPS Bearer QoS is not enforced on the S1-U
Note that the EPS Bearer QoS is not enforced on the S1-U and S5
links, it is assumed that the overprovisioning of the link bandwidth
is sufficient to meet the QoS requirements of all bearers.
@@ -3250,11 +3286,9 @@ S1AP
+++++
The S1-AP interface provides control plane interaction between the eNB
and the MME. In the simulator, this interface is modeled in an ideal
fashion, with direct interaction between the eNB and the MME objects,
without actually implementing the encoding of S1AP messages and
information elements specified in [TS36413]_ and without actually
transmitting any PDU on any link.
and the MME. In the simulator, this interface is modeled in a realistic
fashion transmitting the encoded S1AP messages and information elements
specified in [TS36413]_ on the S1-MME link.
The S1-AP primitives that are modeled are:
@@ -3264,6 +3298,37 @@ The S1-AP primitives that are modeled are:
* PATH SWITCH REQUEST
* PATH SWITCH REQUEST ACKNOWLEDGE
S5 and S11
+++++++++++
The S5 interface provides control plane interaction between the SGW
and the PGW. The S11 interface provides control plane interaction between
the SGw and the MME. Both interfaces use the GPRS Tunneling Protocol (GTPv2-C)
to tunnel signalling messages [TS29274]_ and use UDP as transport protocol.
In the simulator, these interfaces and protocol are modeled in a realistic
fashion transmitting the encoded GTP-C messages.
The GTPv2-C primitives that are modeled are:
* CREATE SESSION REQUEST
* CREATE SESSION RESPONSE
* MODIFY BEARER REQUEST
* MODIFY BEARER RESPONSE
* DELETE SESSION REQUEST
* DELETE SESSION RESPONSE
* DELETE BEARER COMMAND
* DELETE BEARER REQUEST
* DELETE BEARER RESPONSE
Of these primitives, the first two are used upon initial UE attachment for the establishment
of the S1-U and S5 bearers. Section :ref:`sec-nas` shows the implementation of the attach
procedure. The other primitives are used during the handover to switch the S1-U bearers from
the source eNB to the target eNB as a consequence of the reception by the MME of a
PATH SWITCH REQUEST S1-AP message.
.. only:: latex
.. raw:: latex

View File

@@ -6,7 +6,7 @@ References
.. [TS25814] 3GPP TS 25.814 "Physical layer aspect for evolved Universal Terrestrial Radio Access"
.. [TS29274] 3GPP TS 29.274 "Tunnelling Protocol for Control plane (GTPv2-C)"
.. [TS29274] 3GPP TS 29.274 "GPRS Tunnelling Protocol for Control plane (GTPv2-C)"
.. [TS36101] 3GPP TS 36.101 "E-UTRA User Equipment (UE) radio transmission and reception"

View File

@@ -15,36 +15,33 @@
* 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 <jaume.nin@cttc.cat>
* Authors: Jaume Nin <jaume.nin@cttc.cat>
* Manuel Requena <manuel.requena@cttc.es>
*/
#include "ns3/lte-helper.h"
#include "ns3/epc-helper.h"
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/ipv4-global-routing-helper.h"
#include "ns3/point-to-point-module.h"
#include "ns3/internet-module.h"
#include "ns3/mobility-module.h"
#include "ns3/lte-module.h"
#include "ns3/applications-module.h"
#include "ns3/point-to-point-helper.h"
#include "ns3/config-store.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. It instantiates several eNodeB,
* attaches one UE per eNodeB starts a flow for each UE to and from a remote host.
* It also starts yet another flow between each UE pair.
* Sample simulation script for LTE+EPC. It instantiates several eNodeBs,
* attaches one UE per eNodeB starts a flow for each UE to and from a remote host.
* It also starts another flow between each UE pair.
*/
NS_LOG_COMPONENT_DEFINE ("EpcFirstExample");
NS_LOG_COMPONENT_DEFINE ("LenaSimpleEpc");
int
main (int argc, char *argv[])
{
uint16_t numberOfNodes = 2;
uint16_t numNodePairs = 2;
Time simTime = MilliSeconds (1100);
double distance = 60.0;
Time interPacketInterval = MilliSeconds (100);
@@ -55,7 +52,7 @@ main (int argc, char *argv[])
// Command line arguments
CommandLine cmd;
cmd.AddValue ("numberOfNodes", "Number of eNodeBs + UE pairs", numberOfNodes);
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);
@@ -63,6 +60,12 @@ main (int argc, char *argv[])
cmd.AddValue ("disableDl", "Disable downlink data flows", disableDl);
cmd.AddValue ("disableUl", "Disable uplink data flows", disableUl);
cmd.AddValue ("disablePl", "Disable data flows between peer UEs", disablePl);
cmd.Parse (argc, argv);
ConfigStore inputConfig;
inputConfig.ConfigureDefaults ();
// parse again so you can override default values from the command line
cmd.Parse(argc, argv);
if (useCa)
@@ -73,15 +76,9 @@ main (int argc, char *argv[])
}
Ptr<LteHelper> lteHelper = CreateObject<LteHelper> ();
Ptr<PointToPointEpcHelper> epcHelper = CreateObject<PointToPointEpcHelper> ();
Ptr<PointToPointEpcHelper> epcHelper = CreateObject<PointToPointEpcHelper> ();
lteHelper->SetEpcHelper (epcHelper);
ConfigStore inputConfig;
inputConfig.ConfigureDefaults();
// parse again so you can override default values from the command line
cmd.Parse(argc, argv);
Ptr<Node> pgw = epcHelper->GetPgwNode ();
// Create a single RemoteHost
@@ -109,14 +106,14 @@ main (int argc, char *argv[])
NodeContainer ueNodes;
NodeContainer enbNodes;
enbNodes.Create(numberOfNodes);
ueNodes.Create(numberOfNodes);
enbNodes.Create (numNodePairs);
ueNodes.Create (numNodePairs);
// Install Mobility Model
Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
for (uint16_t i = 0; i < numberOfNodes; i++)
for (uint16_t i = 0; i < numNodePairs; i++)
{
positionAlloc->Add (Vector(distance * i, 0, 0));
positionAlloc->Add (Vector (distance * i, 0, 0));
}
MobilityHelper mobility;
mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
@@ -142,7 +139,7 @@ main (int argc, char *argv[])
}
// Attach one UE per eNodeB
for (uint16_t i = 0; i < numberOfNodes; i++)
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
@@ -160,7 +157,7 @@ main (int argc, char *argv[])
if (!disableDl)
{
PacketSinkHelper dlPacketSinkHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), dlPort));
serverApps.Add (dlPacketSinkHelper.Install (ueNodes.Get(u)));
serverApps.Add (dlPacketSinkHelper.Install (ueNodes.Get (u)));
UdpClientHelper dlClient (ueIpIface.GetAddress (u), dlPort);
dlClient.SetAttribute ("Interval", TimeValue (interPacketInterval));
@@ -180,21 +177,21 @@ main (int argc, char *argv[])
clientApps.Add (ulClient.Install (ueNodes.Get(u)));
}
if (!disablePl && numberOfNodes > 1)
if (!disablePl && numNodePairs > 1)
{
++otherPort;
PacketSinkHelper packetSinkHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), otherPort));
serverApps.Add (packetSinkHelper.Install (ueNodes.Get(u)));
serverApps.Add (packetSinkHelper.Install (ueNodes.Get (u)));
UdpClientHelper client (ueIpIface.GetAddress (u), otherPort);
client.SetAttribute ("Interval", TimeValue (interPacketInterval));
client.SetAttribute ("MaxPackets", UintegerValue (1000000));
clientApps.Add (client.Install (ueNodes.Get ((u + 1) % numberOfNodes)));
clientApps.Add (client.Install (ueNodes.Get ((u + 1) % numNodePairs)));
}
}
serverApps.Start (MilliSeconds (10));
clientApps.Start (MilliSeconds (40));
serverApps.Start (MilliSeconds (500));
clientApps.Start (MilliSeconds (500));
lteHelper->EnableTraces ();
// Uncomment to enable PCAP tracing
//p2ph.EnablePcapAll("lena-simple-epc");

View File

@@ -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-2018 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
@@ -33,14 +33,16 @@
#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/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/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/ipv4-address-generator.h>
#include <ns3/ipv6-address-generator.h>
@@ -54,18 +56,29 @@ NS_OBJECT_ENSURE_REGISTERED (PointToPointEpcHelper);
PointToPointEpcHelper::PointToPointEpcHelper ()
: m_gtpuUdpPort (2152) // fixed by the standard
: 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 ());
// since we use point-to-point links for all S1-U links,
int retval;
// since we use point-to-point links for all 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");
@@ -73,24 +86,23 @@ PointToPointEpcHelper::PointToPointEpcHelper ()
// we use a /64 IPv6 net all UEs
m_uePgwAddressHelper6.SetBase ("7777:f00d::", Ipv6Prefix (64));
// create SgwPgwNode
m_sgwPgw = CreateObject<Node> ();
// Create PGW, SGW and MME nodes
m_pgw = CreateObject<Node> ();
m_sgw = CreateObject<Node> ();
m_mme = CreateObject<Node> ();
InternetStackHelper internet;
internet.Install (m_sgwPgw);
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_sgwPgw->GetObject<Ipv6> ());
Ptr<Ipv6StaticRouting> pgwStaticRouting = ipv6RoutingHelper.GetStaticRouting (m_pgw->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 implementing tunneling of user data over GTP-U/UDP/IP
// create TUN device implementing tunneling of user data over GTP-U/UDP/IP in the PGW
m_tunDevice = CreateObject<VirtualNetDevice> ();
// allow jumbo packets
@@ -99,10 +111,9 @@ PointToPointEpcHelper::PointToPointEpcHelper ()
// yes we need this
m_tunDevice->SetAddress (Mac48Address::Allocate ());
m_sgwPgw->AddDevice (m_tunDevice);
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.
@@ -119,18 +130,106 @@ PointToPointEpcHelper::PointToPointEpcHelper ()
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 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 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 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 ()
@@ -141,6 +240,7 @@ PointToPointEpcHelper::~PointToPointEpcHelper ()
TypeId
PointToPointEpcHelper::GetTypeId (void)
{
NS_LOG_FUNCTION_NOARGS ();
static TypeId tid = TypeId ("ns3::PointToPointEpcHelper")
.SetParent<EpcHelper> ()
.SetGroupName("Lte")
@@ -160,6 +260,36 @@ PointToPointEpcHelper::GetTypeId (void)
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")),
@@ -211,8 +341,12 @@ PointToPointEpcHelper::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 ();
m_sgwApp = 0;
m_sgw->Dispose ();
m_pgwApp = 0;
m_pgw->Dispose ();
m_mmeApp = 0;
m_mme->Dispose ();
}
@@ -231,14 +365,14 @@ PointToPointEpcHelper::AddEnb (Ptr<Node> enb, Ptr<NetDevice> lteEnbNetDevice, ui
// 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_sgwPgw);
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_sgwPgw);
NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB after installing p2p dev: " << enb->GetObject<Ipv4> ()->GetNInterfaces ());
NetDeviceContainer enbSgwDevices = p2ph.Install (enb, m_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);
@@ -251,21 +385,24 @@ PointToPointEpcHelper::AddEnb (Ptr<Node> enb, Ptr<NetDevice> lteEnbNetDevice, ui
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 enbAddress = enbSgwIpIfaces.GetAddress (0);
Ipv4Address sgwAddress = enbSgwIpIfaces.GetAddress (1);
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 (enbAddress, m_gtpuUdpPort));
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);
NS_ASSERT (retval == 0);
PacketSocketAddress enbLteSocketConnectAddress;
enbLteSocketConnectAddress.SetPhysicalAddress (Mac48Address::GetBroadcast ());
enbLteSocketConnectAddress.SetSingleDevice (lteEnbNetDevice->GetIfIndex ());
@@ -287,22 +424,21 @@ PointToPointEpcHelper::AddEnb (Ptr<Node> enb, Ptr<NetDevice> lteEnbNetDevice, ui
retval = enbLteSocket6->Connect (enbLteSocketConnectAddress6);
NS_ASSERT (retval == 0);
NS_LOG_INFO ("create EpcEnbApplication");
Ptr<EpcEnbApplication> enbApp = CreateObject<EpcEnbApplication> (enbLteSocket, enbLteSocket6, enbS1uSocket, enbAddress, sgwAddress, cellId);
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_mme->AddEnb (cellId, enbAddress, enbApp->GetS1apSapEnb ());
m_sgwPgwApp->AddEnb (cellId, enbAddress, sgwAddress);
enbApp->SetS1apSapMme (m_mme->GetS1apSapMme ());
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 ());
}
@@ -361,12 +497,10 @@ PointToPointEpcHelper::AddX2Interface (Ptr<Node> enb1, Ptr<Node> enb2)
void
PointToPointEpcHelper::AddUe (Ptr<NetDevice> ueDevice, uint64_t imsi)
{
NS_LOG_FUNCTION (this << imsi << ueDevice );
m_mme->AddUe (imsi);
m_sgwPgwApp->AddUe (imsi);
NS_LOG_FUNCTION (this << imsi << ueDevice);
m_mmeApp->AddUe (imsi);
m_pgwApp->AddUe (imsi);
}
uint8_t
@@ -389,7 +523,7 @@ PointToPointEpcHelper::ActivateEpsBearer (Ptr<NetDevice> ueDevice, uint64_t imsi
{
Ipv4Address ueAddr = ueIpv4->GetAddress (interface, 0).GetLocal ();
NS_LOG_LOGIC (" UE IPv4 address: " << ueAddr);
m_sgwPgwApp->SetUeAddress (imsi, ueAddr);
m_pgwApp->SetUeAddress (imsi, ueAddr);
}
}
if (ueIpv6)
@@ -399,10 +533,10 @@ PointToPointEpcHelper::ActivateEpsBearer (Ptr<NetDevice> ueDevice, uint64_t imsi
{
Ipv6Address ueAddr6 = ueIpv6->GetAddress (interface6, 1).GetAddress ();
NS_LOG_LOGIC (" UE IPv6 address: " << ueAddr6);
m_sgwPgwApp->SetUeAddress6 (imsi, ueAddr6);
m_pgwApp->SetUeAddress6 (imsi, ueAddr6);
}
}
uint8_t bearerId = m_mme->AddBearer (imsi, tft, bearer);
uint8_t bearerId = m_mmeApp->AddBearer (imsi, tft, bearer);
Ptr<LteUeNetDevice> ueLteDevice = ueDevice->GetObject<LteUeNetDevice> ();
if (ueLteDevice)
{
@@ -414,7 +548,7 @@ PointToPointEpcHelper::ActivateEpsBearer (Ptr<NetDevice> ueDevice, uint64_t imsi
Ptr<Node>
PointToPointEpcHelper::GetPgwNode ()
{
return m_sgwPgw;
return m_pgw;
}
Ipv4InterfaceContainer
@@ -440,14 +574,14 @@ Ipv4Address
PointToPointEpcHelper::GetUeDefaultGatewayAddress ()
{
// return the address of the tun device
return m_sgwPgw->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ();
return m_pgw->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ();
}
Ipv6Address
PointToPointEpcHelper::GetUeDefaultGatewayAddress6 ()
{
// return the address of the tun device
return m_sgwPgw->GetObject<Ipv6> ()->GetAddress (1, 1).GetAddress ();
return m_pgw->GetObject<Ipv6> ()->GetAddress (1, 1).GetAddress ();
}
} // namespace ns3

View File

@@ -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-2018 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
@@ -36,31 +36,31 @@ namespace ns3 {
class Node;
class NetDevice;
class VirtualNetDevice;
class EpcSgwPgwApplication;
class EpcSgwApplication;
class EpcPgwApplication;
class EpcMmeApplication;
class EpcX2;
class EpcMme;
/**
* \ingroup lte
* \brief Create an EPC network with PointToPoint links
*
* This Helper will create an EPC network topology comprising of a
* single node that implements both the SGW and PGW functionality, and
* an MME node. The S1-U, X2-U and X2-C interfaces are realized over
* 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.
*/
class PointToPointEpcHelper : public EpcHelper
{
public:
/**
/**
* Constructor
*/
PointToPointEpcHelper ();
/**
/**
* Destructor
*/
*/
virtual ~PointToPointEpcHelper ();
// inherited from Object
@@ -96,31 +96,46 @@ private:
Ipv6AddressHelper m_uePgwAddressHelper6;
/**
* SGW-PGW network element
* SGW network element
*/
Ptr<Node> m_sgwPgw;
Ptr<Node> m_sgw;
/**
* SGW-PGW application
* PGW network element
*/
Ptr<EpcSgwPgwApplication> m_sgwPgwApp;
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;
/**
* MME network element
*/
Ptr<EpcMme> m_mme;
/**
* S1-U interfaces
*/
/**
* helper to assign addresses to S1-U NetDevices
/**
* Helper to assign addresses to S1-U NetDevices
*/
Ipv4AddressHelper m_s1uIpv4AddressHelper;
@@ -146,6 +161,59 @@ private:
* 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
*/
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

View File

@@ -206,18 +206,17 @@ void
EpcEnbApplication::DoInitialContextSetupRequest (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<EpcS1apSapEnb::ErabToBeSetupItem> erabToBeSetupList)
{
NS_LOG_FUNCTION (this);
uint64_t imsi = mmeUeS1Id;
std::map<uint64_t, uint16_t>::iterator imsiIt = m_imsiRntiMap.find (imsi);
NS_ASSERT_MSG (imsiIt != m_imsiRntiMap.end (), "unknown IMSI");
uint16_t rnti = imsiIt->second;
for (std::list<EpcS1apSapEnb::ErabToBeSetupItem>::iterator erabIt = erabToBeSetupList.begin ();
erabIt != erabToBeSetupList.end ();
++erabIt)
{
// request the RRC to setup a radio bearer
uint64_t imsi = mmeUeS1Id;
std::map<uint64_t, uint16_t>::iterator imsiIt = m_imsiRntiMap.find (imsi);
NS_ASSERT_MSG (imsiIt != m_imsiRntiMap.end (), "unknown IMSI");
uint16_t rnti = imsiIt->second;
struct EpcEnbS1SapUser::DataRadioBearerSetupRequestParameters params;
params.rnti = rnti;
params.bearer = erabIt->erabLevelQosParameters;
@@ -229,8 +228,12 @@ EpcEnbApplication::DoInitialContextSetupRequest (uint64_t mmeUeS1Id, uint16_t en
// side effect: create entries if not exist
m_rbidTeidMap[rnti][erabIt->erabId] = params.gtpTeid;
m_teidRbidMap[params.gtpTeid] = rbid;
}
// Send Initial Context Setup Request to RRC
struct EpcEnbS1SapUser::InitialContextSetupRequestParameters params;
params.rnti = rnti;
m_s1SapUser->InitialContextSetupRequest (params);
}
void

View File

@@ -22,7 +22,6 @@
#define EPC_ENB_S1_SAP_H
#include <list>
#include <stdint.h>
#include <ns3/eps-bearer.h>
#include <ns3/ipv4-address.h>
@@ -105,17 +104,30 @@ class EpcEnbS1SapUser
{
public:
virtual ~EpcEnbS1SapUser ();
/**
* Parameters passed to InitialContextSetupRequest ()
*/
struct InitialContextSetupRequestParameters
{
uint16_t rnti; /**< the RNTI identifying the UE */
};
/**
* Initial context setup request
*
* \param params
*/
virtual void InitialContextSetupRequest (InitialContextSetupRequestParameters params) = 0;
/**
* Parameters passed to DataRadioBearerSetupRequest ()
*
*/
struct DataRadioBearerSetupRequestParameters
{
uint16_t rnti; /**< the RNTI identifying the UE for which the
DataRadioBearer is to be created */
EpsBearer bearer; /**< the characteristics of the bearer to be set
up */
DataRadioBearer is to be created */
EpsBearer bearer; /**< the characteristics of the bearer to be setup */
uint8_t bearerId; /**< the EPS Bearer Identifier */
uint32_t gtpTeid; /**< S1-bearer GTP tunnel endpoint identifier, see 36.423 9.2.1 */
Ipv4Address transportLayerAddress; /**< IP Address of the SGW, see 36.423 9.2.1 */
@@ -228,6 +240,7 @@ public:
MemberEpcEnbS1SapUser (C* owner);
// inherited from EpcEnbS1SapUser
virtual void InitialContextSetupRequest (InitialContextSetupRequestParameters params);
virtual void DataRadioBearerSetupRequest (DataRadioBearerSetupRequestParameters params);
virtual void PathSwitchRequestAcknowledge (PathSwitchRequestAcknowledgeParameters params);
@@ -247,6 +260,12 @@ MemberEpcEnbS1SapUser<C>::MemberEpcEnbS1SapUser ()
{
}
template <class C>
void MemberEpcEnbS1SapUser<C>::InitialContextSetupRequest (InitialContextSetupRequestParameters params)
{
m_owner->DoInitialContextSetupRequest (params);
}
template <class C>
void MemberEpcEnbS1SapUser<C>::DataRadioBearerSetupRequest (DataRadioBearerSetupRequestParameters params)
{

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,475 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2018 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>
*/
#ifndef EPC_GTPC_HEADER_H
#define EPC_GTPC_HEADER_H
#include "ns3/header.h"
#include "ns3/epc-tft.h"
#include "ns3/eps-bearer.h"
namespace ns3 {
/**
* \ingroup lte
*
* \brief Header of the GTPv2-C protocol
*
* Implementation of the GPRS Tunnelling Protocol for Control Plane (GTPv2-C) header
* according to the 3GPP TS 29.274 document
*/
class GtpcHeader : public Header
{
public:
GtpcHeader ();
virtual ~GtpcHeader ();
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
virtual TypeId GetInstanceTypeId (void) const;
virtual uint32_t GetSerializedSize (void) const;
virtual void Serialize (Buffer::Iterator start) const;
virtual uint32_t Deserialize (Buffer::Iterator start);
virtual void Print (std::ostream &os) const;
virtual uint32_t GetMessageSize (void) const;
/**
* Get message type
* \returns the message type
*/
uint8_t GetMessageType () const;
/**
* Get message length
* \returns the message length
*/
uint16_t GetMessageLength () const;
/**
* Get TEID
* \returns the TEID
*/
uint32_t GetTeid () const;
/**
* Get sequence number
* \returns the sequence number
*/
uint32_t GetSequenceNumber () const;
/**
* Set message type
* \param messageType the message type
*/
void SetMessageType (uint8_t messageType);
/**
* Set message length
* \param messageLength the message length
*/
void SetMessageLength (uint16_t messageLength);
/**
* Set TEID
* \param teid the TEID
*/
void SetTeid (uint32_t teid);
/**
* Set sequence number
* \param sequenceNumber the sequence number
*/
void SetSequenceNumber (uint32_t sequenceNumber);
/**
* Set IEs length. It is used to compute the message length
* \param iesLength the IEs length
*/
void SetIesLength (uint16_t iesLength);
void ComputeMessageLength (void);
/// Interface Type enumeration
enum InterfaceType_t
{
S1U_ENB_GTPU = 0,
S5_SGW_GTPU = 4,
S5_PGW_GTPU = 5,
S5_SGW_GTPC = 6,
S5_PGW_GTPC = 7,
S11_MME_GTPC = 10,
};
/// FTEID structure
struct Fteid_t
{
InterfaceType_t interfaceType;
Ipv4Address addr;
uint32_t teid;
};
/// Message Type enumeration
enum MessageType_t
{
Reserved = 0,
CreateSessionRequest = 32,
CreateSessionResponse = 33,
ModifyBearerRequest = 34,
ModifyBearerResponse = 35,
DeleteSessionRequest = 36,
DeleteSessionResponse = 37,
DeleteBearerCommand = 66,
DeleteBearerRequest = 99,
DeleteBearerResponse = 100,
};
private:
/**
* Version of the GTPv2-C protocol.
* The version number shall be set to 2.
*/
uint8_t m_version;
/**
* TEID flag.
* This flag indicates if TEID field is present or not
*/
bool m_teidFlag;
/**
* Message type field.
* It can be one of the values of MessageType_t
*/
uint8_t m_messageType;
/**
* Message length field.
* This field indicates the length of the message in octets excluding
* the mandatory part of the GTP-C header (the first 4 octets)
*/
uint16_t m_messageLength;
/**
* Tunnel Endpoint Identifier (TEID) field
*/
uint32_t m_teid;
/**
* GTP Sequence number field
*/
uint32_t m_sequenceNumber;
protected:
/**
* Serialize the GTP-C header in the GTP-C messages
* \param i the buffer iterator
*/
void PreSerialize (Buffer::Iterator &i) const;
/**
* Deserialize the GTP-C header in the GTP-C messages
* \param i the buffer iterator
*/
uint32_t PreDeserialize (Buffer::Iterator &i);
};
class GtpcIes
{
public:
enum Cause_t
{
RESERVED = 0,
REQUEST_ACCEPTED = 16,
};
const uint32_t serializedSizeImsi = 12;
const uint32_t serializedSizeCause = 6;
const uint32_t serializedSizeEbi = 5;
const uint32_t serializedSizeBearerQos = 26;
const uint32_t serializedSizePacketFilter = 3 + 9 + 9 + 5 + 5 + 3;
uint32_t GetSerializedSizeBearerTft (std::list<EpcTft::PacketFilter> packetFilters) const;
const uint32_t serializedSizeUliEcgi = 12;
const uint32_t serializedSizeFteid = 13;
const uint32_t serializedSizeBearerContextHeader = 4;
void SerializeImsi (Buffer::Iterator &i, uint64_t imsi) const;
uint32_t DeserializeImsi (Buffer::Iterator &i, uint64_t &imsi);
void SerializeCause (Buffer::Iterator &i, Cause_t cause) const;
uint32_t DeserializeCause (Buffer::Iterator &i, Cause_t &cause);
void SerializeEbi (Buffer::Iterator &i, uint8_t epsBearerId) const;
uint32_t DeserializeEbi (Buffer::Iterator &i, uint8_t &epsBearerId);
void WriteHtonU40 (Buffer::Iterator &i, uint64_t data) const;
uint64_t ReadNtohU40 (Buffer::Iterator &i);
void SerializeBearerQos (Buffer::Iterator &i, EpsBearer bearerQos) const;
uint32_t DeserializeBearerQos (Buffer::Iterator &i, EpsBearer &bearerQos);
void SerializeBearerTft (Buffer::Iterator &i, std::list<EpcTft::PacketFilter> packetFilters) const;
uint32_t DeserializeBearerTft (Buffer::Iterator &i, Ptr<EpcTft> epcTft);
void SerializeUliEcgi (Buffer::Iterator &i, uint32_t uliEcgi) const;
uint32_t DeserializeUliEcgi (Buffer::Iterator &i, uint32_t &uliEcgi);
void SerializeFteid (Buffer::Iterator &i, GtpcHeader::Fteid_t fteid) const;
uint32_t DeserializeFteid (Buffer::Iterator &i, GtpcHeader::Fteid_t &fteid);
void SerializeBearerContextHeader (Buffer::Iterator &i, uint16_t length) const;
uint32_t DeserializeBearerContextHeader (Buffer::Iterator &i, uint16_t &length);
};
class GtpcCreateSessionRequestMessage : public GtpcHeader, public GtpcIes
{
public:
GtpcCreateSessionRequestMessage ();
virtual ~GtpcCreateSessionRequestMessage ();
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
virtual TypeId GetInstanceTypeId (void) const;
virtual uint32_t GetSerializedSize (void) const;
virtual void Serialize (Buffer::Iterator start) const;
virtual uint32_t Deserialize (Buffer::Iterator start);
virtual void Print (std::ostream &os) const;
virtual uint32_t GetMessageSize (void) const;
uint64_t GetImsi () const;
void SetImsi (uint64_t imsi);
uint32_t GetUliEcgi () const;
void SetUliEcgi (uint32_t uliEcgi);
GtpcHeader::Fteid_t GetSenderCpFteid () const;
void SetSenderCpFteid (GtpcHeader::Fteid_t fteid);
struct BearerContextToBeCreated
{
GtpcHeader::Fteid_t sgwS5uFteid; ///< FTEID
uint8_t epsBearerId; ///< EPS bearer ID
Ptr<EpcTft> tft; ///< traffic flow template
EpsBearer bearerLevelQos; ///< bearer QOS level
};
std::list<BearerContextToBeCreated> GetBearerContextsToBeCreated () const;
void SetBearerContextsToBeCreated (std::list<BearerContextToBeCreated> bearerContexts);
private:
uint64_t m_imsi;
uint32_t m_uliEcgi;
GtpcHeader::Fteid_t m_senderCpFteid;
std::list<BearerContextToBeCreated> m_bearerContextsToBeCreated;
};
class GtpcCreateSessionResponseMessage : public GtpcHeader, public GtpcIes
{
public:
GtpcCreateSessionResponseMessage ();
virtual ~GtpcCreateSessionResponseMessage ();
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
virtual TypeId GetInstanceTypeId (void) const;
virtual uint32_t GetSerializedSize (void) const;
virtual void Serialize (Buffer::Iterator start) const;
virtual uint32_t Deserialize (Buffer::Iterator start);
virtual void Print (std::ostream &os) const;
virtual uint32_t GetMessageSize (void) const;
Cause_t GetCause () const;
void SetCause (Cause_t cause);
GtpcHeader::Fteid_t GetSenderCpFteid () const;
void SetSenderCpFteid (GtpcHeader::Fteid_t fteid);
struct BearerContextCreated
{
uint8_t epsBearerId; ///< EPS bearer ID
uint8_t cause; ///< Cause
Ptr<EpcTft> tft; ///< Bearer traffic flow template
GtpcHeader::Fteid_t fteid; ///< FTEID
EpsBearer bearerLevelQos; ///< Bearer QOS level
};
std::list<BearerContextCreated> GetBearerContextsCreated () const;
void SetBearerContextsCreated (std::list<BearerContextCreated> bearerContexts);
private:
Cause_t m_cause;
GtpcHeader::Fteid_t m_senderCpFteid;
std::list<BearerContextCreated> m_bearerContextsCreated;
};
class GtpcModifyBearerRequestMessage : public GtpcHeader, public GtpcIes
{
public:
GtpcModifyBearerRequestMessage ();
virtual ~GtpcModifyBearerRequestMessage ();
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
virtual TypeId GetInstanceTypeId (void) const;
virtual uint32_t GetSerializedSize (void) const;
virtual void Serialize (Buffer::Iterator start) const;
virtual uint32_t Deserialize (Buffer::Iterator start);
virtual void Print (std::ostream &os) const;
virtual uint32_t GetMessageSize (void) const;
uint8_t GetImsi () const;
void SetImsi (uint8_t imsi);
uint32_t GetUliEcgi () const;
void SetUliEcgi (uint32_t uliEcgi);
struct BearerContextToBeModified
{
uint8_t epsBearerId; ///< EPS bearer ID
GtpcHeader::Fteid_t fteid; ///< FTEID
};
std::list<BearerContextToBeModified> GetBearerContextsToBeModified () const;
void SetBearerContextsToBeModified (std::list<BearerContextToBeModified> bearerContexts);
private:
uint64_t m_imsi;
uint32_t m_uliEcgi;
std::list<BearerContextToBeModified> m_bearerContextsToBeModified;
};
class GtpcModifyBearerResponseMessage : public GtpcHeader, public GtpcIes
{
public:
GtpcModifyBearerResponseMessage ();
virtual ~GtpcModifyBearerResponseMessage ();
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
virtual TypeId GetInstanceTypeId (void) const;
virtual uint32_t GetSerializedSize (void) const;
virtual void Serialize (Buffer::Iterator start) const;
virtual uint32_t Deserialize (Buffer::Iterator start);
virtual void Print (std::ostream &os) const;
virtual uint32_t GetMessageSize (void) const;
Cause_t GetCause () const;
void SetCause (Cause_t cause);
private:
Cause_t m_cause;
};
class GtpcDeleteBearerCommandMessage : public GtpcHeader, public GtpcIes
{
public:
GtpcDeleteBearerCommandMessage ();
virtual ~GtpcDeleteBearerCommandMessage ();
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
virtual TypeId GetInstanceTypeId (void) const;
virtual uint32_t GetSerializedSize (void) const;
virtual void Serialize (Buffer::Iterator start) const;
virtual uint32_t Deserialize (Buffer::Iterator start);
virtual void Print (std::ostream &os) const;
virtual uint32_t GetMessageSize (void) const;
struct BearerContext
{
uint8_t m_epsBearerId; ///< EPS bearer ID
};
std::list<BearerContext> GetBearerContexts () const;
void SetBearerContexts (std::list<BearerContext> bearerContexts);
private:
std::list<BearerContext> m_bearerContexts;
};
class GtpcDeleteBearerRequestMessage : public GtpcHeader, public GtpcIes
{
public:
GtpcDeleteBearerRequestMessage ();
virtual ~GtpcDeleteBearerRequestMessage ();
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
virtual TypeId GetInstanceTypeId (void) const;
virtual uint32_t GetSerializedSize (void) const;
virtual void Serialize (Buffer::Iterator start) const;
virtual uint32_t Deserialize (Buffer::Iterator start);
virtual void Print (std::ostream &os) const;
virtual uint32_t GetMessageSize (void) const;
std::list<uint8_t> GetEpsBearerIds () const;
void SetEpsBearerIds (std::list<uint8_t> epsBearerIds);
private:
std::list<uint8_t> m_epsBearerIds;
};
class GtpcDeleteBearerResponseMessage : public GtpcHeader, public GtpcIes
{
public:
GtpcDeleteBearerResponseMessage ();
virtual ~GtpcDeleteBearerResponseMessage ();
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
virtual TypeId GetInstanceTypeId (void) const;
virtual uint32_t GetSerializedSize (void) const;
virtual void Serialize (Buffer::Iterator start) const;
virtual uint32_t Deserialize (Buffer::Iterator start);
virtual void Print (std::ostream &os) const;
virtual uint32_t GetMessageSize (void) const;
Cause_t GetCause () const;
void SetCause (Cause_t cause);
std::list<uint8_t> GetEpsBearerIds () const;
void SetEpsBearerIds (std::list<uint8_t> epsBearerIds);
private:
Cause_t m_cause;
std::list<uint8_t> m_epsBearerIds;
};
} // namespace ns3
#endif // EPC_GTPC_HEADER_H

View File

@@ -0,0 +1,367 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2017-2018 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>
*/
#include "ns3/log.h"
#include "ns3/epc-gtpc-header.h"
#include "ns3/epc-mme-application.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("EpcMmeApplication");
NS_OBJECT_ENSURE_REGISTERED (EpcMmeApplication);
EpcMmeApplication::EpcMmeApplication ()
: m_gtpcUdpPort (2123) //fixed by the standard
{
NS_LOG_FUNCTION (this);
m_s1apSapMme = new MemberEpcS1apSapMme<EpcMmeApplication> (this);
}
EpcMmeApplication::~EpcMmeApplication ()
{
NS_LOG_FUNCTION (this);
}
void
EpcMmeApplication::DoDispose ()
{
NS_LOG_FUNCTION (this);
delete m_s1apSapMme;
}
TypeId
EpcMmeApplication::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::EpcMmeApplication")
.SetParent<Object> ()
.SetGroupName ("Lte")
.AddConstructor<EpcMmeApplication> ();
return tid;
}
EpcS1apSapMme*
EpcMmeApplication::GetS1apSapMme ()
{
return m_s1apSapMme;
}
void
EpcMmeApplication::AddSgw (Ipv4Address sgwS11Addr, Ipv4Address mmeS11Addr, Ptr<Socket> mmeS11Socket)
{
NS_LOG_FUNCTION (this << sgwS11Addr << mmeS11Addr << mmeS11Socket);
m_sgwS11Addr = sgwS11Addr;
m_mmeS11Addr = mmeS11Addr;
m_s11Socket = mmeS11Socket;
m_s11Socket->SetRecvCallback (MakeCallback (&EpcMmeApplication::RecvFromS11Socket, this));
}
void
EpcMmeApplication::AddEnb (uint16_t gci, Ipv4Address enbS1uAddr, EpcS1apSapEnb* enbS1apSap)
{
NS_LOG_FUNCTION (this << gci << enbS1uAddr << enbS1apSap);
Ptr<EnbInfo> enbInfo = Create<EnbInfo> ();
enbInfo->gci = gci;
enbInfo->s1uAddr = enbS1uAddr;
enbInfo->s1apSapEnb = enbS1apSap;
m_enbInfoMap[gci] = enbInfo;
}
void
EpcMmeApplication::AddUe (uint64_t imsi)
{
NS_LOG_FUNCTION (this << imsi);
Ptr<UeInfo> ueInfo = Create<UeInfo> ();
ueInfo->imsi = imsi;
ueInfo->mmeUeS1Id = imsi;
ueInfo->bearerCounter = 0;
m_ueInfoMap[imsi] = ueInfo;
}
uint8_t
EpcMmeApplication::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
EpcMmeApplication::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;
GtpcCreateSessionRequestMessage msg;
msg.SetImsi (imsi);
msg.SetUliEcgi (gci);
GtpcHeader::Fteid_t mmeS11Fteid;
mmeS11Fteid.interfaceType = GtpcHeader::S11_MME_GTPC;
mmeS11Fteid.teid = imsi;
mmeS11Fteid.addr = m_mmeS11Addr;
msg.SetSenderCpFteid (mmeS11Fteid); // S11 MME GTP-C F-TEID
std::list<GtpcCreateSessionRequestMessage::BearerContextToBeCreated> bearerContexts;
for (std::list<BearerInfo>::iterator bit = it->second->bearersToBeActivated.begin ();
bit != it->second->bearersToBeActivated.end ();
++bit)
{
GtpcCreateSessionRequestMessage::BearerContextToBeCreated bearerContext;
bearerContext.epsBearerId = bit->bearerId;
bearerContext.tft = bit->tft;
bearerContext.bearerLevelQos = bit->bearer;
bearerContexts.push_back (bearerContext);
}
NS_LOG_DEBUG ("BearerContextToBeCreated size = " << bearerContexts.size ());
msg.SetBearerContextsToBeCreated (bearerContexts);
msg.SetTeid (0);
msg.ComputeMessageLength ();
Ptr<Packet> packet = Create <Packet> ();
packet->AddHeader (msg);
NS_LOG_DEBUG ("Send CreateSessionRequest to SGW " << m_sgwS11Addr);
m_s11Socket->SendTo (packet, 0, InetSocketAddress (m_sgwS11Addr, m_gtpcUdpPort));
}
void
EpcMmeApplication::DoInitialContextSetupResponse (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<EpcS1apSapMme::ErabSetupItem> erabSetupList)
{
NS_LOG_FUNCTION (this << mmeUeS1Id << enbUeS1Id);
NS_FATAL_ERROR ("unimplemented");
}
void
EpcMmeApplication::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;
GtpcModifyBearerRequestMessage msg;
msg.SetImsi (imsi);
msg.SetUliEcgi (gci);
std::list<GtpcModifyBearerRequestMessage::BearerContextToBeModified> bearerContexts;
for (auto &erab : erabToBeSwitchedInDownlinkList)
{
NS_LOG_DEBUG ("erabId " << erab.erabId <<
" eNB " << erab.enbTransportLayerAddress <<
" TEID " << erab.enbTeid);
GtpcModifyBearerRequestMessage::BearerContextToBeModified bearerContext;
bearerContext.epsBearerId = erab.erabId;
bearerContext.fteid.interfaceType = GtpcHeader::S1U_ENB_GTPU;
bearerContext.fteid.addr = erab.enbTransportLayerAddress;
bearerContext.fteid.teid = erab.enbTeid;
bearerContexts.push_back (bearerContext);
}
msg.SetBearerContextsToBeModified (bearerContexts);
msg.SetTeid (imsi);
msg.ComputeMessageLength ();
Ptr<Packet> packet = Create <Packet> ();
packet->AddHeader (msg);
NS_LOG_DEBUG ("Send ModifyBearerRequest to SGW " << m_sgwS11Addr);
m_s11Socket->SendTo (packet, 0, InetSocketAddress (m_sgwS11Addr, m_gtpcUdpPort));
}
void
EpcMmeApplication::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);
GtpcDeleteBearerCommandMessage msg;
std::list<GtpcDeleteBearerCommandMessage::BearerContext> bearerContexts;
for (auto &erab : erabToBeReleaseIndication)
{
NS_LOG_DEBUG ("erabId " << (uint16_t)erab.erabId);
GtpcDeleteBearerCommandMessage::BearerContext bearerContext;
bearerContext.m_epsBearerId = erab.erabId;
bearerContexts.push_back (bearerContext);
}
msg.SetBearerContexts (bearerContexts);
msg.SetTeid (imsi);
msg.ComputeMessageLength ();
Ptr<Packet> packet = Create <Packet> ();
packet->AddHeader (msg);
NS_LOG_DEBUG ("Send DeleteBearerCommand to SGW " << m_sgwS11Addr);
m_s11Socket->SendTo (packet, 0, InetSocketAddress (m_sgwS11Addr, m_gtpcUdpPort));
}
void
EpcMmeApplication::RemoveBearer (Ptr<UeInfo> ueInfo, uint8_t epsBearerId)
{
NS_LOG_FUNCTION (this << epsBearerId);
std::list<BearerInfo>::iterator bit = ueInfo->bearersToBeActivated.begin ();
while (bit != ueInfo->bearersToBeActivated.end ())
{
if (bit->bearerId == epsBearerId)
{
ueInfo->bearersToBeActivated.erase (bit);
break;
}
++bit;
}
}
void
EpcMmeApplication::RecvFromS11Socket (Ptr<Socket> socket)
{
NS_LOG_FUNCTION (this << socket);
NS_ASSERT (socket == m_s11Socket);
Ptr<Packet> packet = socket->Recv ();
GtpcHeader header;
packet->PeekHeader (header);
uint16_t msgType = header.GetMessageType ();
switch (msgType)
{
case GtpcHeader::CreateSessionResponse:
DoRecvCreateSessionResponse (header, packet);
break;
case GtpcHeader::ModifyBearerResponse:
DoRecvModifyBearerResponse (header, packet);
break;
case GtpcHeader::DeleteBearerRequest:
DoRecvDeleteBearerRequest (header, packet);
break;
default:
NS_FATAL_ERROR ("GTP-C message not supported");
break;
}
}
void
EpcMmeApplication::DoRecvCreateSessionResponse (GtpcHeader &header, Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this << header);
uint64_t imsi = header.GetTeid ();
NS_LOG_DEBUG ("TEID/IMSI " << 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);
uint16_t cellId = it->second->cellId;
uint16_t enbUeS1Id = it->second->enbUeS1Id;
uint64_t mmeUeS1Id = it->second->mmeUeS1Id;
NS_LOG_DEBUG ("cellId " << cellId << " mmeUeS1Id " << mmeUeS1Id << " enbUeS1Id " << enbUeS1Id);
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);
GtpcCreateSessionResponseMessage msg;
packet->RemoveHeader (msg);
std::list<EpcS1apSapEnb::ErabToBeSetupItem> erabToBeSetupList;
std::list<GtpcCreateSessionResponseMessage::BearerContextCreated> bearerContexts =
msg.GetBearerContextsCreated ();
NS_LOG_DEBUG ("BearerContextsCreated size = " << bearerContexts.size ());
for (auto &bearerContext : bearerContexts)
{
EpcS1apSapEnb::ErabToBeSetupItem erab;
erab.erabId = bearerContext.epsBearerId;
erab.erabLevelQosParameters = bearerContext.bearerLevelQos;
erab.transportLayerAddress = bearerContext.fteid.addr; // SGW S1U address
erab.sgwTeid = bearerContext.fteid.teid;
NS_LOG_DEBUG ("SGW " << erab.transportLayerAddress << " TEID " << erab.sgwTeid);
erabToBeSetupList.push_back (erab);
}
NS_LOG_DEBUG ("Send InitialContextSetupRequest to eNB " << jt->second->s1apSapEnb);
jt->second->s1apSapEnb->InitialContextSetupRequest (mmeUeS1Id, enbUeS1Id, erabToBeSetupList);
}
void
EpcMmeApplication::DoRecvModifyBearerResponse (GtpcHeader &header, Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this << header);
GtpcModifyBearerResponseMessage msg;
packet->RemoveHeader (msg);
NS_ASSERT (msg.GetCause () == GtpcModifyBearerResponseMessage::REQUEST_ACCEPTED);
uint64_t imsi = header.GetTeid ();
NS_LOG_DEBUG ("TEID/IMSI " << 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);
uint16_t cellId = it->second->cellId;
uint16_t enbUeS1Id = it->second->enbUeS1Id;
uint64_t mmeUeS1Id = it->second->mmeUeS1Id;
NS_LOG_DEBUG ("cellId " << cellId << " mmeUeS1Id " << mmeUeS1Id << " enbUeS1Id " << enbUeS1Id);
std::list<EpcS1apSapEnb::ErabSwitchedInUplinkItem> erabToBeSwitchedInUplinkList; // unused for now
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);
NS_LOG_DEBUG ("Send PathSwitchRequestAcknowledge to eNB " << jt->second->s1apSapEnb);
jt->second->s1apSapEnb->PathSwitchRequestAcknowledge (enbUeS1Id, mmeUeS1Id, cellId, erabToBeSwitchedInUplinkList);
}
void
EpcMmeApplication::DoRecvDeleteBearerRequest (GtpcHeader &header, Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this << header);
uint64_t imsi = header.GetTeid ();
NS_LOG_DEBUG ("TEID/IMSI " << 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);
GtpcDeleteBearerRequestMessage msg;
packet->RemoveHeader (msg);
GtpcDeleteBearerResponseMessage msgOut;
std::list<uint8_t> epsBearerIds;
for (auto &ebid : msg.GetEpsBearerIds ())
{
epsBearerIds.push_back (ebid);
RemoveBearer (it->second, ebid); //schedules function to erase, context of de-activated bearer
}
msgOut.SetEpsBearerIds (epsBearerIds);
msgOut.SetTeid (imsi);
msgOut.ComputeMessageLength ();
Ptr<Packet> packetOut = Create <Packet> ();
packetOut->AddHeader (msgOut);
NS_LOG_DEBUG ("Send DeleteBearerResponse to SGW " << m_sgwS11Addr);
m_s11Socket->SendTo (packetOut, 0, InetSocketAddress (m_sgwS11Addr, m_gtpcUdpPort));
}
} // namespace ns3

View File

@@ -0,0 +1,240 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2017-2018 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>
*/
#ifndef EPC_MME_APPLICATION_H
#define EPC_MME_APPLICATION_H
#include "ns3/application.h"
#include "ns3/socket.h"
#include "ns3/epc-s1ap-sap.h"
namespace ns3 {
/**
* \ingroup lte
*
* This application implements the Mobility Management Entity (MME) according to
* the 3GPP TS 23.401 document.
*
* This Application implements the MME side of the S1-MME interface between
* the MME node and the eNB nodes and the MME side of the S11 interface between
* the MME node and the SGW node. It supports the following functions and messages:
*
* - Bearer management functions including dedicated bearer establishment
* - NAS signalling
* - Tunnel Management messages
*
* Others functions enumerated in section 4.4.2 of 3GPP TS 23.401 are not supported.
*/
class EpcMmeApplication : public Application
{
/// allow MemberEpcS1apSapMme<EpcMme> class friend access
friend class MemberEpcS1apSapMme<EpcMmeApplication>;
public:
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
virtual void DoDispose ();
/** Constructor */
EpcMmeApplication ();
/** Destructor */
virtual ~EpcMmeApplication ();
/**
*
* \return the MME side of the S1-AP SAP
*/
EpcS1apSapMme* GetS1apSapMme ();
/**
* Add a new SGW to the MME
*
* \param sgwS11Addr IPv4 address of the SGW S11 interface
* \param mmeS11Addr IPv4 address of the MME S11 interface
* \param mmeS11Socket socket of the MME S11 interface
*/
void AddSgw (Ipv4Address sgwS11Addr, Ipv4Address mmeS11Addr, Ptr<Socket> mmeS11Socket);
/**
* Add a new eNB to the MME
*
* \param ecgi E-UTRAN Cell Global ID, the unique identifier of the eNodeB
* \param enbS1UAddr IPv4 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
/**
* Process the S1 Initial UE Message received from an eNB
* \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);
/**
* Process the S1 Initial Context Setup Response received from an eNB
* \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);
/**
* Process the S1 Path Switch Request received from an eNB
* \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);
/**
* Process ERAB Release Indication received from an eNB
* \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);
// Methods to read/process GTP-C messages of the S11 interface
/**
* Reads the S11 messages from a socket
* \param socket the socket
*/
void RecvFromS11Socket (Ptr<Socket> socket);
/**
* Process GTP-C Create Session Response message
* \param header the GTP-C header
* \param packet the packet containing the message
*/
void DoRecvCreateSessionResponse (GtpcHeader &header, Ptr<Packet> packet);
/**
* Process GTP-C Modify Bearer Response message
* \param header the GTP-C header
* \param packet the packet containing the message
*/
void DoRecvModifyBearerResponse (GtpcHeader &header, Ptr<Packet> packet);
/**
* Process GTP-C Delete Bearer Request message
* \param header the GTP-C header
* \param packet the packet containing the message
*/
void DoRecvDeleteBearerRequest (GtpcHeader &header, Ptr<Packet> packet);
/**
* 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 imsi; ///< UE identifier
uint64_t mmeUeS1Id; ///< mmeUeS1Id
uint16_t enbUeS1Id; ///< enbUeS1Id
uint16_t cellId; ///< cell ID
uint16_t bearerCounter; ///< bearer counter
std::list<BearerInfo> bearersToBeActivated; ///< list of bearers to be activated
};
/**
* 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 an ENB
*/
struct EnbInfo : public SimpleRefCount<EnbInfo>
{
uint16_t gci; ///< GCI
Ipv4Address s1uAddr; ///< IP address of the S1-U interface
EpcS1apSapEnb* s1apSapEnb; ///< EpcS1apSapEnb
};
/**
* EnbInfo stored by EGCI
*/
std::map<uint16_t, Ptr<EnbInfo> > m_enbInfoMap;
EpcS1apSapMme* m_s1apSapMme; ///< EpcS1apSapMme
Ptr<Socket> m_s11Socket; ///< Socket to send/receive messages in the S11 interface
Ipv4Address m_mmeS11Addr; ///< IPv4 address of the MME S11 interface
Ipv4Address m_sgwS11Addr; ///< IPv4 address of the SGW S11 interface
uint16_t m_gtpcUdpPort; ///< UDP port for GTP-C protocol. Fixed by the standard to port 2123
};
} // namespace ns3
#endif // EPC_MME_APPLICATION_H

View File

@@ -0,0 +1,507 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2018 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 epc-sgw-pgw-application.cc)
*/
#include "ns3/log.h"
#include "ns3/abort.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/epc-pgw-application.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("EpcPgwApplication");
/////////////////////////
// UeInfo
/////////////////////////
EpcPgwApplication::UeInfo::UeInfo ()
{
NS_LOG_FUNCTION (this);
}
void
EpcPgwApplication::UeInfo::AddBearer (uint8_t bearerId, uint32_t teid, Ptr<EpcTft> tft)
{
NS_LOG_FUNCTION (this << (uint16_t) bearerId << teid << tft);
m_teidByBearerIdMap[bearerId] = teid;
return m_tftClassifier.Add (tft, teid);
}
void
EpcPgwApplication::UeInfo::RemoveBearer (uint8_t bearerId)
{
NS_LOG_FUNCTION (this << (uint16_t) bearerId);
m_teidByBearerIdMap.erase (bearerId);
}
uint32_t
EpcPgwApplication::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
EpcPgwApplication::UeInfo::GetSgwAddr ()
{
return m_sgwAddr;
}
void
EpcPgwApplication::UeInfo::SetSgwAddr (Ipv4Address sgwAddr)
{
m_sgwAddr = sgwAddr;
}
Ipv4Address
EpcPgwApplication::UeInfo::GetUeAddr ()
{
return m_ueAddr;
}
void
EpcPgwApplication::UeInfo::SetUeAddr (Ipv4Address ueAddr)
{
m_ueAddr = ueAddr;
}
Ipv6Address
EpcPgwApplication::UeInfo::GetUeAddr6 ()
{
return m_ueAddr6;
}
void
EpcPgwApplication::UeInfo::SetUeAddr6 (Ipv6Address ueAddr)
{
m_ueAddr6 = ueAddr;
}
/////////////////////////
// EpcPgwApplication
/////////////////////////
TypeId
EpcPgwApplication::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::EpcPgwApplication")
.SetParent<Object> ()
.SetGroupName ("Lte")
.AddTraceSource ("RxFromTun",
"Receive data packets from internet in Tunnel NetDevice",
MakeTraceSourceAccessor (&EpcPgwApplication::m_rxTunPktTrace),
"ns3::EpcPgwApplication::RxTracedCallback")
.AddTraceSource ("RxFromS1u",
"Receive data packets from S5 Socket",
MakeTraceSourceAccessor (&EpcPgwApplication::m_rxS5PktTrace),
"ns3::EpcPgwApplication::RxTracedCallback")
;
return tid;
}
void
EpcPgwApplication::DoDispose ()
{
NS_LOG_FUNCTION (this);
m_s5uSocket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket> > ());
m_s5uSocket = 0;
m_s5cSocket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket> > ());
m_s5cSocket = 0;
}
EpcPgwApplication::EpcPgwApplication (const Ptr<VirtualNetDevice> tunDevice, Ipv4Address s5Addr,
const Ptr<Socket> s5uSocket, const Ptr<Socket> s5cSocket)
: m_pgwS5Addr (s5Addr),
m_s5uSocket (s5uSocket),
m_s5cSocket (s5cSocket),
m_tunDevice (tunDevice),
m_gtpuUdpPort (2152), // fixed by the standard
m_gtpcUdpPort (2123) // fixed by the standard
{
NS_LOG_FUNCTION (this << tunDevice << s5Addr << s5uSocket << s5cSocket);
m_s5uSocket->SetRecvCallback (MakeCallback (&EpcPgwApplication::RecvFromS5uSocket, this));
m_s5cSocket->SetRecvCallback (MakeCallback (&EpcPgwApplication::RecvFromS5cSocket, this));
}
EpcPgwApplication::~EpcPgwApplication ()
{
NS_LOG_FUNCTION (this);
}
bool
EpcPgwApplication::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 ());
// get IP address of UE
if (protocolNumber == Ipv4L3Protocol::PROT_NUMBER)
{
Ipv4Header ipv4Header;
packet->PeekHeader (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 sgwAddr = it->second->GetSgwAddr ();
uint32_t teid = it->second->Classify (packet, protocolNumber);
if (teid == 0)
{
NS_LOG_WARN ("no matching bearer for this packet");
}
else
{
SendToS5uSocket (packet, sgwAddr, teid);
}
}
}
else if (protocolNumber == Ipv6L3Protocol::PROT_NUMBER)
{
Ipv6Header ipv6Header;
packet->PeekHeader (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 sgwAddr = it->second->GetSgwAddr ();
uint32_t teid = it->second->Classify (packet, protocolNumber);
if (teid == 0)
{
NS_LOG_WARN ("no matching bearer for this packet");
}
else
{
SendToS5uSocket (packet, sgwAddr, teid);
}
}
}
else
{
NS_ABORT_MSG ("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
EpcPgwApplication::RecvFromS5uSocket (Ptr<Socket> socket)
{
NS_LOG_FUNCTION (this << socket);
NS_ASSERT (socket == m_s5uSocket);
Ptr<Packet> packet = socket->Recv ();
m_rxS5PktTrace (packet->Copy ());
GtpuHeader gtpu;
packet->RemoveHeader (gtpu);
uint32_t teid = gtpu.GetTeid ();
SendToTunDevice (packet, teid);
}
void
EpcPgwApplication::RecvFromS5cSocket (Ptr<Socket> socket)
{
NS_LOG_FUNCTION (this << socket);
NS_ASSERT (socket == m_s5cSocket);
Ptr<Packet> packet = socket->Recv ();
GtpcHeader header;
packet->PeekHeader (header);
uint16_t msgType = header.GetMessageType ();
switch (msgType)
{
case GtpcHeader::CreateSessionRequest:
DoRecvCreateSessionRequest (packet);
break;
case GtpcHeader::ModifyBearerRequest:
DoRecvModifyBearerRequest (packet);
break;
case GtpcHeader::DeleteBearerCommand:
DoRecvDeleteBearerCommand (packet);
break;
case GtpcHeader::DeleteBearerResponse:
DoRecvDeleteBearerResponse (packet);
break;
default:
NS_FATAL_ERROR ("GTP-C message not supported");
break;
}
}
void
EpcPgwApplication::DoRecvCreateSessionRequest (Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this);
GtpcCreateSessionRequestMessage msg;
packet->RemoveHeader (msg);
uint64_t imsi = msg.GetImsi ();
uint16_t cellId = msg.GetUliEcgi ();
NS_LOG_DEBUG ("cellId " << cellId << " imsi " << (uint16_t)imsi);
std::map<uint64_t, Ptr<UeInfo> >::iterator ueit = m_ueInfoByImsiMap.find (imsi);
NS_ASSERT_MSG (ueit != m_ueInfoByImsiMap.end (), "unknown IMSI " << imsi);
ueit->second->SetSgwAddr (m_sgwS5Addr);
GtpcHeader::Fteid_t sgwS5cFteid = msg.GetSenderCpFteid ();
NS_ASSERT_MSG (sgwS5cFteid.interfaceType == GtpcHeader::S5_SGW_GTPC,
"Wrong interface type");
GtpcCreateSessionResponseMessage msgOut;
msgOut.SetTeid (sgwS5cFteid.teid);
msgOut.SetCause (GtpcCreateSessionResponseMessage::REQUEST_ACCEPTED);
GtpcHeader::Fteid_t pgwS5cFteid;
pgwS5cFteid.interfaceType = GtpcHeader::S5_PGW_GTPC;
pgwS5cFteid.teid = sgwS5cFteid.teid;
pgwS5cFteid.addr = m_pgwS5Addr;
msgOut.SetSenderCpFteid (pgwS5cFteid);
std::list<GtpcCreateSessionRequestMessage::BearerContextToBeCreated> bearerContexts =
msg.GetBearerContextsToBeCreated ();
NS_LOG_DEBUG ("BearerContextsToBeCreated size = " << bearerContexts.size ());
std::list<GtpcCreateSessionResponseMessage::BearerContextCreated> bearerContextsCreated;
for (auto &bearerContext : bearerContexts)
{
uint32_t teid = bearerContext.sgwS5uFteid.teid;
NS_LOG_DEBUG ("bearerId " << (uint16_t)bearerContext.epsBearerId <<
" SGW " << bearerContext.sgwS5uFteid.addr << " TEID " << teid);
ueit->second->AddBearer (bearerContext.epsBearerId, teid, bearerContext.tft);
GtpcCreateSessionResponseMessage::BearerContextCreated bearerContextOut;
bearerContextOut.fteid.interfaceType = GtpcHeader::S5_PGW_GTPU;
bearerContextOut.fteid.teid = teid;
bearerContextOut.fteid.addr = m_pgwS5Addr;
bearerContextOut.epsBearerId = bearerContext.epsBearerId;
bearerContextOut.bearerLevelQos = bearerContext.bearerLevelQos;
bearerContextOut.tft = bearerContext.tft;
bearerContextsCreated.push_back (bearerContextOut);
}
NS_LOG_DEBUG ("BearerContextsCreated size = " << bearerContextsCreated.size ());
msgOut.SetBearerContextsCreated (bearerContextsCreated);
msgOut.SetTeid (sgwS5cFteid.teid);
msgOut.ComputeMessageLength ();
Ptr<Packet> packetOut = Create <Packet> ();
packetOut->AddHeader (msgOut);
NS_LOG_DEBUG ("Send CreateSessionResponse to SGW " << sgwS5cFteid.addr);
m_s5cSocket->SendTo (packetOut, 0, InetSocketAddress (sgwS5cFteid.addr, m_gtpcUdpPort));
}
void
EpcPgwApplication::DoRecvModifyBearerRequest (Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this);
GtpcModifyBearerRequestMessage msg;
packet->RemoveHeader (msg);
uint8_t imsi = msg.GetImsi ();
uint16_t cellId = msg.GetUliEcgi ();
NS_LOG_DEBUG ("cellId " << cellId << "IMSI " << (uint16_t)imsi);
std::map<uint64_t, Ptr<UeInfo> >::iterator ueit = m_ueInfoByImsiMap.find (imsi);
NS_ASSERT_MSG (ueit != m_ueInfoByImsiMap.end (), "unknown IMSI " << imsi);
ueit->second->SetSgwAddr (m_sgwS5Addr);
std::list<GtpcModifyBearerRequestMessage::BearerContextToBeModified> bearerContexts =
msg.GetBearerContextsToBeModified ();
NS_LOG_DEBUG ("BearerContextsToBeModified size = " << bearerContexts.size ());
for (auto &bearerContext : bearerContexts)
{
Ipv4Address sgwAddr = bearerContext.fteid.addr;
uint32_t teid = bearerContext.fteid.teid;
NS_LOG_DEBUG ("bearerId " << (uint16_t)bearerContext.epsBearerId <<
" SGW " << sgwAddr << " TEID " << teid);
}
GtpcModifyBearerResponseMessage msgOut;
msgOut.SetCause (GtpcIes::REQUEST_ACCEPTED);
msgOut.SetTeid (imsi);
msgOut.ComputeMessageLength ();
Ptr<Packet> packetOut = Create <Packet> ();
packetOut->AddHeader (msgOut);
NS_LOG_DEBUG ("Send ModifyBearerResponse to SGW " << m_sgwS5Addr);
m_s5cSocket->SendTo (packetOut, 0, InetSocketAddress (m_sgwS5Addr, m_gtpcUdpPort));
}
void
EpcPgwApplication::DoRecvDeleteBearerCommand (Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this);
GtpcDeleteBearerCommandMessage msg;
packet->RemoveHeader (msg);
std::list<uint8_t> epsBearerIds;
for (auto &bearerContext : msg.GetBearerContexts ())
{
NS_LOG_DEBUG ("ebid " << bearerContext.m_epsBearerId);
epsBearerIds.push_back (bearerContext.m_epsBearerId);
}
GtpcDeleteBearerRequestMessage msgOut;
msgOut.SetEpsBearerIds (epsBearerIds);
msgOut.SetTeid (msg.GetTeid ());
msgOut.ComputeMessageLength ();
Ptr<Packet> packetOut = Create <Packet> ();
packetOut->AddHeader (msgOut);
NS_LOG_DEBUG ("Send DeleteBearerRequest to SGW " << m_sgwS5Addr);
m_s5cSocket->SendTo (packetOut, 0, InetSocketAddress (m_sgwS5Addr, m_gtpcUdpPort));
}
void
EpcPgwApplication::DoRecvDeleteBearerResponse (Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this);
GtpcDeleteBearerResponseMessage msg;
packet->RemoveHeader (msg);
uint64_t imsi = msg.GetTeid ();
std::map<uint64_t, Ptr<UeInfo> >::iterator ueit = m_ueInfoByImsiMap.find (imsi);
NS_ASSERT_MSG (ueit != m_ueInfoByImsiMap.end (), "unknown IMSI " << imsi);
for (auto &epsBearerId : msg.GetEpsBearerIds ())
{
// Remove de-activated bearer contexts from PGW side
ueit->second->RemoveBearer (epsBearerId);
}
}
void
EpcPgwApplication::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;
uint16_t protocol = 0;
if (ipType == 0x04)
{
protocol = 0x0800;
}
else if (ipType == 0x06)
{
protocol = 0x86DD;
}
else
{
NS_ABORT_MSG ("Unknown IP type");
}
m_tunDevice->Receive (packet, protocol, m_tunDevice->GetAddress (), m_tunDevice->GetAddress (), NetDevice::PACKET_HOST);
}
void
EpcPgwApplication::SendToS5uSocket (Ptr<Packet> packet, Ipv4Address sgwAddr, uint32_t teid)
{
NS_LOG_FUNCTION (this << packet << sgwAddr << 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_s5uSocket->SendTo (packet, flags, InetSocketAddress (sgwAddr, m_gtpuUdpPort));
}
void
EpcPgwApplication::AddSgw (Ipv4Address sgwS5Addr)
{
NS_LOG_FUNCTION (this << sgwS5Addr);
m_sgwS5Addr = sgwS5Addr;
}
void
EpcPgwApplication::AddUe (uint64_t imsi)
{
NS_LOG_FUNCTION (this << imsi);
Ptr<UeInfo> ueInfo = Create<UeInfo> ();
m_ueInfoByImsiMap[imsi] = ueInfo;
}
void
EpcPgwApplication::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);
ueit->second->SetUeAddr (ueAddr);
m_ueInfoByAddrMap[ueAddr] = ueit->second;
}
void
EpcPgwApplication::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);
}
} // namespace ns3

View File

@@ -0,0 +1,343 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2018 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 epc-sgw-pgw-application.h)
*/
#ifndef EPC_PGW_APPLICATION_H
#define EPC_PGW_APPLICATION_H
#include "ns3/virtual-net-device.h"
#include "ns3/socket.h"
#include "ns3/application.h"
#include "ns3/epc-tft-classifier.h"
#include "ns3/epc-gtpc-header.h"
namespace ns3 {
/**
* \ingroup lte
*
* This application implements the Packet Data Network (PDN) Gateway Entity (PGW)
* according to the 3GPP TS 23.401 document.
*
* This Application implements the PGW side of the S5 interface between
* the PGW node and the SGW nodes and the PGW side of the SGi interface between
* the PGW node and the internet hosts. It supports the following functions and messages:
*
* - S5 connectivity (i.e. GTPv2-C signalling and GTP-U data plane)
* - Bearer management functions including dedicated bearer establishment
* - Per-user based packet filtering
* - UL and DL bearer binding
* - Tunnel Management messages
*
* Others functions enumerated in section 4.4.3.3 of 3GPP TS 23.401 are not supported.
*/
class EpcPgwApplication : public Application
{
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 SGi interface of the PGW in the internet
* over GTP-U/UDP/IP on the S5 interface
* \param s5Addr IP address of the PGW S5 interface
* \param s5uSocket socket used to send GTP-U packets to the peer SGW
* \param s5cSocket socket used to send GTP-C packets to the peer SGW
*/
EpcPgwApplication (const Ptr<VirtualNetDevice> tunDevice, Ipv4Address s5Addr,
const Ptr<Socket> s5uSocket, const Ptr<Socket> s5cSocket);
/** Destructor */
virtual ~EpcPgwApplication (void);
/**
* Method to be assigned to the callback of the SGi TUN VirtualNetDevice.
* It is called when the PGW receives a data packet from the
* internet (including IP headers) that is to be sent to the UE via
* its associated SGW and 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 receiver callback of the S5-U socket.
* It is called when the PGW receives a data packet from the SGW
* that is to be forwarded to the internet.
*
* \param socket pointer to the S5-U socket
*/
void RecvFromS5uSocket (Ptr<Socket> socket);
/**
* Method to be assigned to the receiver callback of the S5-C socket.
* It is called when the PGW receives a control packet from the SGW.
*
* \param socket pointer to the S5-C socket
*/
void RecvFromS5cSocket (Ptr<Socket> socket);
/**
* Send a data packet to the internet via the SGi interface of the PGW
*
* \param packet packet to be sent
* \param teid the Tunnel Enpoint Identifier
*/
void SendToTunDevice (Ptr<Packet> packet, uint32_t teid);
/**
* Send a data packet to the SGW via the S5-U interface
*
* \param packet packet to be sent
* \param sgwS5uAddress the address of the SGW
* \param teid the Tunnel Enpoint IDentifier
*/
void SendToS5uSocket (Ptr<Packet> packet, Ipv4Address sgwS5uAddress, uint32_t teid);
/**
* Let the PGW be aware of a new SGW
*
* \param sgwS5Addr the address of the SGW S5 interface
*/
void AddSgw (Ipv4Address sgwS5Addr);
/**
* Let the PGW 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:
/**
* Process Create Session Request message
* \param packet GTPv2-C Create Session Request message
*/
void DoRecvCreateSessionRequest (Ptr<Packet> packet);
/**
* Process Modify Bearer Request message
* \param packet GTPv2-C Modify Bearer Request message
*/
void DoRecvModifyBearerRequest (Ptr<Packet> packet);
/**
* Process Delete Bearer Command message
* \param packet GTPv2-C Delete Bearer Command message
*/
void DoRecvDeleteBearerCommand (Ptr<Packet> packet);
/**
* Process Delete Bearer Response message
* \param packet GTPv2-C Delete Bearer Response message
*/
void DoRecvDeleteBearerResponse (Ptr<Packet> packet);
/**
* store info for each UE connected to this PGW
*/
class UeInfo : public SimpleRefCount<UeInfo>
{
public:
UeInfo ();
/**
* Add a bearer for this UE on PGW side
*
* \param bearerId the ID of the EPS Bearer to be activated
* \param teid the TEID of the new bearer
* \param tft the Traffic Flow Template of the new bearer to be added
*/
void AddBearer (uint8_t bearerId, uint32_t teid, Ptr<EpcTft> tft);
/**
* Delete context of bearer for this UE on PGW side
*
* \param bearerId the ID of the EPS Bearer whose contexts is to be removed
*/
void RemoveBearer (uint8_t bearerId);
/**
* Classify the packet according to TFTs of this UE
*
* \param p the IPv4 or IPv6 packet from the internet to be classified
* \param protocolNumber identifies the type of packet.
* Only IPv4 and IPv6 packets are allowed.
*
* \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);
/**
* Get the address of the SGW to which the UE is connected
*
* \return the address of the SGW
*/
Ipv4Address GetSgwAddr ();
/**
* Set the address of the eNB to which the UE is connected
*
* \param addr the address of the SGW
*/
void SetSgwAddr (Ipv4Address addr);
/**
* Get the IPv4 address of the UE
*
* \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);
/**
* Get the IPv6 address of the UE
*
* \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:
Ipv4Address m_ueAddr; ///< UE IPv4 address
Ipv6Address m_ueAddr6; ///< UE IPv6 address
Ipv4Address m_sgwAddr; ///< SGW IPv4 address
EpcTftClassifier m_tftClassifier; ///< TFT classifier
std::map<uint8_t, uint32_t> m_teidByBearerIdMap; ///< TEID By bearer ID Map
};
/**
* PGW address of the S5 interface
*/
Ipv4Address m_pgwS5Addr;
/**
* UDP socket to send/receive GTP-U packets to/from the S5 interface
*/
Ptr<Socket> m_s5uSocket;
/**
* UDP socket to send/receive GTPv2-C packets to/from the S5 interface
*/
Ptr<Socket> m_s5cSocket;
/**
* TUN VirtualNetDevice used for tunneling/detunneling IP packets
* from/to the internet over GTP-U/UDP/IP on the S5 interface
*/
Ptr<VirtualNetDevice> m_tunDevice;
/**
* UeInfo stored by UE IPv4 address
*/
std::map<Ipv4Address, Ptr<UeInfo> > m_ueInfoByAddrMap;
/**
* UeInfo stored by UE IPv6 address
*/
std::map<Ipv6Address, Ptr<UeInfo> > m_ueInfoByAddrMap6;
/**
* UeInfo stored by IMSI
*/
std::map<uint64_t, Ptr<UeInfo> > m_ueInfoByImsiMap;
/**
* UDP port to be used for GTP-U
*/
uint16_t m_gtpuUdpPort;
/**
* UDP port to be used for GTPv2-C
*/
uint16_t m_gtpcUdpPort;
/**
* SGW address of the S5 interface
*/
Ipv4Address m_sgwS5Addr;
/**
* \brief Callback to trace received data packets at Tun NetDevice from internet.
*/
TracedCallback<Ptr<Packet> > m_rxTunPktTrace;
/**
* \brief Callback to trace received data packets from S5 socket.
*/
TracedCallback<Ptr<Packet> > m_rxS5PktTrace;
};
} // namespace ns3
#endif // EPC_PGW_APPLICATION_H

View File

@@ -0,0 +1,480 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2017-2018 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>
*/
#include "ns3/log.h"
#include "ns3/epc-gtpu-header.h"
#include "ns3/epc-sgw-application.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("EpcSgwApplication");
NS_OBJECT_ENSURE_REGISTERED (EpcSgwApplication);
EpcSgwApplication::EpcSgwApplication (const Ptr<Socket> s1uSocket, Ipv4Address s5Addr,
const Ptr<Socket> s5uSocket, const Ptr<Socket> s5cSocket)
: m_s5Addr (s5Addr),
m_s5uSocket (s5uSocket),
m_s5cSocket (s5cSocket),
m_s1uSocket (s1uSocket),
m_gtpuUdpPort (2152), // fixed by the standard
m_gtpcUdpPort (2123), // fixed by the standard
m_teidCount (0)
{
NS_LOG_FUNCTION (this << s1uSocket << s5Addr << s5uSocket << s5cSocket);
m_s1uSocket->SetRecvCallback (MakeCallback (&EpcSgwApplication::RecvFromS1uSocket, this));
m_s5uSocket->SetRecvCallback (MakeCallback (&EpcSgwApplication::RecvFromS5uSocket, this));
m_s5cSocket->SetRecvCallback (MakeCallback (&EpcSgwApplication::RecvFromS5cSocket, this));
}
EpcSgwApplication::~EpcSgwApplication ()
{
NS_LOG_FUNCTION (this);
}
void
EpcSgwApplication::DoDispose ()
{
NS_LOG_FUNCTION (this);
m_s1uSocket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket> > ());
m_s1uSocket = 0;
m_s5uSocket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket> > ());
m_s5uSocket = 0;
m_s5cSocket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket> > ());
m_s5cSocket = 0;
}
TypeId
EpcSgwApplication::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::EpcSgwApplication")
.SetParent<Object> ()
.SetGroupName("Lte");
return tid;
}
void
EpcSgwApplication::AddMme (Ipv4Address mmeS11Addr, Ptr<Socket> s11Socket)
{
NS_LOG_FUNCTION (this << mmeS11Addr << s11Socket);
m_mmeS11Addr = mmeS11Addr;
m_s11Socket = s11Socket;
m_s11Socket->SetRecvCallback (MakeCallback (&EpcSgwApplication::RecvFromS11Socket, this));
}
void
EpcSgwApplication::AddPgw (Ipv4Address pgwAddr)
{
NS_LOG_FUNCTION (this << pgwAddr);
m_pgwAddr = pgwAddr;
}
void
EpcSgwApplication::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
EpcSgwApplication::RecvFromS11Socket (Ptr<Socket> socket)
{
NS_LOG_FUNCTION (this << socket);
NS_ASSERT (socket == m_s11Socket);
Ptr<Packet> packet = socket->Recv ();
GtpcHeader header;
packet->PeekHeader (header);
uint16_t msgType = header.GetMessageType ();
switch (msgType)
{
case GtpcHeader::CreateSessionRequest:
DoRecvCreateSessionRequest (packet);
break;
case GtpcHeader::ModifyBearerRequest:
DoRecvModifyBearerRequest (packet);
break;
case GtpcHeader::DeleteBearerCommand:
DoRecvDeleteBearerCommand (packet);
break;
case GtpcHeader::DeleteBearerResponse:
DoRecvDeleteBearerResponse (packet);
break;
default:
NS_FATAL_ERROR ("GTP-C message not supported");
break;
}
}
void
EpcSgwApplication::RecvFromS5uSocket (Ptr<Socket> socket)
{
NS_LOG_FUNCTION (this << socket);
NS_ASSERT (socket == m_s5uSocket);
Ptr<Packet> packet = socket->Recv ();
GtpuHeader gtpu;
packet->RemoveHeader (gtpu);
uint32_t teid = gtpu.GetTeid ();
Ipv4Address enbAddr = m_enbByTeidMap[teid];
NS_LOG_DEBUG ("eNB " << enbAddr << " TEID " << teid);
SendToS1uSocket (packet, enbAddr, teid);
}
void
EpcSgwApplication::RecvFromS5cSocket (Ptr<Socket> socket)
{
NS_LOG_FUNCTION (this << socket);
NS_ASSERT (socket == m_s5cSocket);
Ptr<Packet> packet = socket->Recv ();
GtpcHeader header;
packet->PeekHeader (header);
uint16_t msgType = header.GetMessageType ();
switch (msgType)
{
case GtpcHeader::CreateSessionResponse:
DoRecvCreateSessionResponse (packet);
break;
case GtpcHeader::ModifyBearerResponse:
DoRecvModifyBearerResponse (packet);
break;
case GtpcHeader::DeleteBearerRequest:
DoRecvDeleteBearerRequest (packet);
break;
default:
NS_FATAL_ERROR ("GTP-C message not supported");
break;
}
}
void
EpcSgwApplication::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 ();
SendToS5uSocket (packet, m_pgwAddr, teid);
}
void
EpcSgwApplication::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);
m_s1uSocket->SendTo (packet, 0, InetSocketAddress (enbAddr, m_gtpuUdpPort));
}
void
EpcSgwApplication::SendToS5uSocket (Ptr<Packet> packet, Ipv4Address pgwAddr, uint32_t teid)
{
NS_LOG_FUNCTION (this << packet << pgwAddr << 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);
m_s5uSocket->SendTo (packet, 0, InetSocketAddress (pgwAddr, m_gtpuUdpPort));
}
///////////////////////////////////
// Process messages from the MME
///////////////////////////////////
void
EpcSgwApplication::DoRecvCreateSessionRequest (Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this);
GtpcCreateSessionRequestMessage msg;
packet->RemoveHeader (msg);
uint8_t imsi = msg.GetImsi ();
uint16_t cellId = msg.GetUliEcgi ();
NS_LOG_DEBUG ("IMSI " << (uint16_t)imsi << " cellId " << cellId);
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;
NS_LOG_DEBUG ("eNB " << enbAddr);
GtpcHeader::Fteid_t mmeS11Fteid = msg.GetSenderCpFteid ();
NS_ASSERT_MSG (mmeS11Fteid.interfaceType == GtpcHeader::S11_MME_GTPC,
"wrong interface type");
GtpcCreateSessionRequestMessage msgOut;
msgOut.SetImsi (imsi);
msgOut.SetUliEcgi (cellId);
GtpcHeader::Fteid_t sgwS5cFteid;
sgwS5cFteid.interfaceType = GtpcHeader::S5_SGW_GTPC;
sgwS5cFteid.teid = imsi;
m_mmeS11FteidBySgwS5cTeid[sgwS5cFteid.teid] = mmeS11Fteid;
sgwS5cFteid.addr = m_s5Addr;
msgOut.SetSenderCpFteid (sgwS5cFteid); // S5 SGW GTP-C TEID
std::list<GtpcCreateSessionRequestMessage::BearerContextToBeCreated> bearerContexts =
msg.GetBearerContextsToBeCreated ();
NS_LOG_DEBUG ("BearerContextToBeCreated size = " << bearerContexts.size ());
std::list<GtpcCreateSessionRequestMessage::BearerContextToBeCreated> bearerContextsOut;
for (auto &bearerContext : bearerContexts)
{
// 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;
NS_LOG_DEBUG (" TEID " << teid);
m_enbByTeidMap[teid] = enbAddr;
GtpcCreateSessionRequestMessage::BearerContextToBeCreated bearerContextOut;
bearerContextOut.sgwS5uFteid.interfaceType = GtpcHeader::S5_SGW_GTPU;
bearerContextOut.sgwS5uFteid.teid = teid; // S5U SGW FTEID
bearerContextOut.sgwS5uFteid.addr = enbit->second.sgwAddr;
bearerContextOut.epsBearerId = bearerContext.epsBearerId;
bearerContextOut.bearerLevelQos = bearerContext.bearerLevelQos;
bearerContextOut.tft = bearerContext.tft;
bearerContextsOut.push_back (bearerContextOut);
}
msgOut.SetBearerContextsToBeCreated (bearerContextsOut);
msgOut.SetTeid (0);
msgOut.ComputeMessageLength ();
Ptr<Packet> packetOut = Create <Packet> ();
packetOut->AddHeader (msgOut);
NS_LOG_DEBUG ("Send CreateSessionRequest to PGW " << m_pgwAddr);
m_s5cSocket->SendTo (packetOut, 0, InetSocketAddress (m_pgwAddr, m_gtpcUdpPort));
}
void
EpcSgwApplication::DoRecvModifyBearerRequest (Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this);
GtpcModifyBearerRequestMessage msg;
packet->RemoveHeader (msg);
uint8_t imsi = msg.GetImsi ();
uint16_t cellId = msg.GetUliEcgi ();
NS_LOG_DEBUG ("IMSI " << (uint16_t)imsi << " cellId " << cellId);
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;
NS_LOG_DEBUG ("eNB " << enbAddr);
GtpcModifyBearerRequestMessage msgOut;
msgOut.SetImsi (imsi);
msgOut.SetUliEcgi (cellId);
std::list<GtpcModifyBearerRequestMessage::BearerContextToBeModified> bearerContextsOut;
std::list<GtpcModifyBearerRequestMessage::BearerContextToBeModified> bearerContexts
= msg.GetBearerContextsToBeModified ();
NS_LOG_DEBUG ("BearerContextsToBeModified size = " << bearerContexts.size ());
for (auto &bearerContext : bearerContexts)
{
NS_ASSERT_MSG (bearerContext.fteid.interfaceType == GtpcHeader::S1U_ENB_GTPU,
"Wrong FTEID in ModifyBearerRequest msg");
uint32_t teid = bearerContext.fteid.teid;
Ipv4Address enbAddr = bearerContext.fteid.addr;
NS_LOG_DEBUG ("bearerId " << (uint16_t)bearerContext.epsBearerId <<
" TEID " << teid);
std::map<uint32_t, Ipv4Address>::iterator addrit = m_enbByTeidMap.find (teid);
NS_ASSERT_MSG (addrit != m_enbByTeidMap.end (), "unknown TEID " << teid);
addrit->second = enbAddr;
GtpcModifyBearerRequestMessage::BearerContextToBeModified bearerContextOut;
bearerContextOut.epsBearerId = bearerContext.epsBearerId;
bearerContextOut.fteid.interfaceType = GtpcHeader::S5_SGW_GTPU;
bearerContextOut.fteid.addr = m_s5Addr;
bearerContextOut.fteid.teid = bearerContext.fteid.teid;
bearerContextsOut.push_back (bearerContextOut);
}
msgOut.SetTeid (imsi);
msgOut.ComputeMessageLength ();
Ptr<Packet> packetOut = Create <Packet> ();
packetOut->AddHeader (msgOut);
NS_LOG_DEBUG ("Send ModifyBearerRequest to PGW " << m_pgwAddr);
m_s5cSocket->SendTo (packetOut, 0, InetSocketAddress (m_pgwAddr, m_gtpcUdpPort));
}
void
EpcSgwApplication::DoRecvDeleteBearerCommand (Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this);
GtpcDeleteBearerCommandMessage msg;
packet->RemoveHeader (msg);
std::list<GtpcDeleteBearerCommandMessage::BearerContext> bearerContextsOut;
for (auto &bearerContext : msg.GetBearerContexts ())
{
NS_LOG_DEBUG ("ebid " << bearerContext.m_epsBearerId);
GtpcDeleteBearerCommandMessage::BearerContext bearerContextOut;
bearerContextOut.m_epsBearerId = bearerContext.m_epsBearerId;
bearerContextsOut.push_back (bearerContextOut);
}
GtpcDeleteBearerCommandMessage msgOut;
msgOut.SetBearerContexts (bearerContextsOut);
msgOut.SetTeid (msg.GetTeid ());
msgOut.ComputeMessageLength ();
Ptr<Packet> packetOut = Create <Packet> ();
packetOut->AddHeader (msgOut);
NS_LOG_DEBUG ("Send DeleteBearerCommand to PGW " << m_pgwAddr);
m_s11Socket->SendTo (packetOut, 0, InetSocketAddress (m_pgwAddr, m_gtpcUdpPort));
}
void
EpcSgwApplication::DoRecvDeleteBearerResponse (Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this);
GtpcDeleteBearerResponseMessage msg;
packet->RemoveHeader (msg);
GtpcDeleteBearerResponseMessage msgOut;
msgOut.SetEpsBearerIds (msg.GetEpsBearerIds ());
msgOut.SetTeid (msg.GetTeid ());
msgOut.ComputeMessageLength ();
Ptr<Packet> packetOut = Create <Packet> ();
packetOut->AddHeader (msgOut);
NS_LOG_DEBUG ("Send DeleteBearerResponse to PGW " << m_pgwAddr);
m_s5cSocket->SendTo (packetOut, 0, InetSocketAddress (m_pgwAddr, m_gtpcUdpPort));
}
////////////////////////////////////////////
// Process messages received from the PGW
////////////////////////////////////////////
void
EpcSgwApplication::DoRecvCreateSessionResponse (Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this);
GtpcCreateSessionResponseMessage msg;
packet->RemoveHeader (msg);
GtpcHeader::Fteid_t pgwS5cFteid = msg.GetSenderCpFteid ();
NS_ASSERT_MSG (pgwS5cFteid.interfaceType == GtpcHeader::S5_PGW_GTPC,
"wrong interface type");
GtpcCreateSessionResponseMessage msgOut;
msgOut.SetCause (GtpcCreateSessionResponseMessage::REQUEST_ACCEPTED);
uint32_t teid = msg.GetTeid ();
GtpcHeader::Fteid_t mmeS11Fteid = m_mmeS11FteidBySgwS5cTeid[teid];
std::list<GtpcCreateSessionResponseMessage::BearerContextCreated> bearerContexts =
msg.GetBearerContextsCreated ();
NS_LOG_DEBUG ("BearerContextsCreated size = " << bearerContexts.size ());
std::list<GtpcCreateSessionResponseMessage::BearerContextCreated> bearerContextsOut;
for (auto &bearerContext : bearerContexts)
{
GtpcCreateSessionResponseMessage::BearerContextCreated bearerContextOut;
bearerContextOut.fteid.interfaceType = GtpcHeader::S5_SGW_GTPU;
bearerContextOut.fteid.teid = bearerContext.fteid.teid;
bearerContextOut.fteid.addr = m_s5Addr;
bearerContextOut.epsBearerId = bearerContext.epsBearerId;
bearerContextOut.bearerLevelQos = bearerContext.bearerLevelQos;
bearerContextOut.tft = bearerContext.tft;
bearerContextsOut.push_back (bearerContext);
}
msgOut.SetBearerContextsCreated (bearerContextsOut);
msgOut.SetTeid (mmeS11Fteid.teid);
msgOut.ComputeMessageLength ();
Ptr<Packet> packetOut = Create <Packet> ();
packetOut->AddHeader (msgOut);
NS_LOG_DEBUG ("Send CreateSessionResponse to MME " << mmeS11Fteid.addr);
m_s11Socket->SendTo (packetOut, 0, InetSocketAddress (mmeS11Fteid.addr, m_gtpcUdpPort));
}
void
EpcSgwApplication::DoRecvModifyBearerResponse (Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this);
GtpcModifyBearerResponseMessage msg;
packet->RemoveHeader (msg);
GtpcModifyBearerResponseMessage msgOut;
msgOut.SetCause (GtpcIes::REQUEST_ACCEPTED);
msgOut.SetTeid (msg.GetTeid ());
msgOut.ComputeMessageLength ();
Ptr<Packet> packetOut = Create <Packet> ();
packetOut->AddHeader (msgOut);
NS_LOG_DEBUG ("Send ModifyBearerResponse to MME " << m_mmeS11Addr);
m_s11Socket->SendTo (packetOut, 0, InetSocketAddress (m_mmeS11Addr, m_gtpcUdpPort));
}
void
EpcSgwApplication::DoRecvDeleteBearerRequest (Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this);
GtpcDeleteBearerRequestMessage msg;
packet->RemoveHeader (msg);
GtpcDeleteBearerRequestMessage msgOut;
msgOut.SetEpsBearerIds (msg.GetEpsBearerIds ());
msgOut.SetTeid (msg.GetTeid ());
msgOut.ComputeMessageLength ();
Ptr<Packet> packetOut = Create <Packet> ();
packetOut->AddHeader (msgOut);
NS_LOG_DEBUG ("Send DeleteBearerRequest to MME " << m_mmeS11Addr);
m_s11Socket->SendTo (packetOut, 0, InetSocketAddress (m_mmeS11Addr, m_gtpcUdpPort));
}
} // namespace ns3

View File

@@ -0,0 +1,277 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2017-2018 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>
*/
#ifndef EPC_SGW_APPLICATION_H
#define EPC_SGW_APPLICATION_H
#include "ns3/application.h"
#include "ns3/address.h"
#include "ns3/socket.h"
#include "ns3/epc-gtpc-header.h"
namespace ns3 {
/**
* \ingroup lte
*
* This application implements the Serving Gateway Entity (SGW)
* according to the 3GPP TS 23.401 document.
*
* This Application implements the SGW side of the S5 interface between
* the SGW node and the PGW node and the SGW side of the S11 interface between
* the SGW node and the MME node hosts. It supports the following functions and messages:
*
* - S5 connectivity (i.e. GTPv2-C signalling and GTP-U data plane)
* - Bearer management functions including dedicated bearer establishment
* - UL and DL bearer binding
* - Tunnel Management messages
*
* Others functions enumerated in section 4.4.3.2 of 3GPP TS 23.401 are not supported.
*/
class EpcSgwApplication : public Application
{
public:
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
virtual void DoDispose ();
/**
* Constructor that binds callback methods of sockets.
*
* \param s1uSocket socket used to send/receive GTP-U packets to/from the eNBs
* \param s5Addr IPv4 address of the S5 interface
* \param s5uSocket socket used to send/receive GTP-U packets to/from the PGW
* \param s5cSocket socket used to send/receive GTP-C packets to/from the PGW
*/
EpcSgwApplication (const Ptr<Socket> s1uSocket, Ipv4Address s5Addr,
const Ptr<Socket> s5uSocket, const Ptr<Socket> s5cSocket);
/** Destructor */
virtual ~EpcSgwApplication (void);
/**
* Let the SGW be aware of an MME
*
* \param mmeS11Addr the address of the MME
* \param s11Socket the socket to send/receive messages from the MME
*/
void AddMme (Ipv4Address mmeS11Addr, Ptr<Socket> s11Socket);
/**
* Let the SGW be aware of a PGW
*
* \param pgwAddr the address of the PGW
*/
void AddPgw (Ipv4Address pgwAddr);
/**
* 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);
private:
/**
* Method to be assigned to the recv callback of the S11 socket.
* It is called when the SGW receives a control packet from the MME.
*
* \param socket pointer to the S11 socket
*/
void RecvFromS11Socket (Ptr<Socket> socket);
/**
* Method to be assigned to the recv callback of the S5-U socket.
* It is called when the SGW receives a data packet from the PGW
* that is to be forwarded to an eNB.
*
* \param socket pointer to the S5-U socket
*/
void RecvFromS5uSocket (Ptr<Socket> socket);
/**
* Method to be assigned to the recv callback of the S5-C socket.
* It is called when the SGW receives a control packet from the PGW.
*
* \param socket pointer to the S5-C socket
*/
void RecvFromS5cSocket (Ptr<Socket> socket);
/**
* Method to be assigned to the recv callback of the S1-U socket.
* It is called when the SGW receives a data packet from the eNB
* that is to be forwarded to the PGW.
*
* \param socket pointer to the S1-U socket
*/
void RecvFromS1uSocket (Ptr<Socket> socket);
/**
* Send a data packet to the PGW via the S5 interface
*
* \param packet packet to be sent
* \param pgwAddr the address of the PGW
* \param teid the Tunnel Enpoint Identifier
*/
void SendToS5uSocket (Ptr<Packet> packet, Ipv4Address pgwAddr, uint32_t teid);
/**
* Send a data packet to an eNB 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);
// Process messages received from the MME
/**
* Process GTP-C Create Session Request message
* \param packet the packet containing the message
*/
void DoRecvCreateSessionRequest (Ptr<Packet> packet);
/**
* Process GTP-C Modify Bearer Request message
* \param packet the packet containing the message
*/
void DoRecvModifyBearerRequest (Ptr<Packet> packet);
/**
* Process GTP-C Delete Bearer Command message
* \param packet the packet containing the message
*/
void DoRecvDeleteBearerCommand (Ptr<Packet> packet);
/**
* Process GTP-C Delete Bearer Response message
* \param packet the packet containing the message
*/
void DoRecvDeleteBearerResponse (Ptr<Packet> packet);
// Process messages received from the PGW
/**
* Process GTP-C Create Session Response message
* \param packet the packet containing the message
*/
void DoRecvCreateSessionResponse (Ptr<Packet> packet);
/**
* Process GTP-C Modify Bearer Response message
* \param packet the packet containing the message
*/
void DoRecvModifyBearerResponse (Ptr<Packet> packet);
/**
* Process GTP-C Delete Bearer Request message
* \param packet the packet containing the message
*/
void DoRecvDeleteBearerRequest (Ptr<Packet> packet);
/**
* SGW address in the S5 interface
*/
Ipv4Address m_s5Addr;
/**
* MME address in the S11 interface
*/
Ipv4Address m_mmeS11Addr;
/**
* UDP socket to send/receive control messages to/from the S11 interface
*/
Ptr<Socket> m_s11Socket;
/**
* PGW address in the S5 interface
*/
Ipv4Address m_pgwAddr;
/**
* UDP socket to send/receive GTP-U packets to/from the S5 interface
*/
Ptr<Socket> m_s5uSocket;
/**
* UDP socket to send/receive GTP-C packets to/from the S5 interface
*/
Ptr<Socket> m_s5cSocket;
/**
* UDP socket to send/receive GTP-U packets to/from the S1-U interface
*/
Ptr<Socket> m_s1uSocket;
/**
* UDP port to be used for GTP-U
*/
uint16_t m_gtpuUdpPort;
/**
* UDP port to be used for GTP-C
*/
uint16_t m_gtpcUdpPort;
/**
* TEID count
*/
uint32_t m_teidCount;
/// EnbInfo structure
struct EnbInfo
{
Ipv4Address enbAddr; ///< eNB address
Ipv4Address sgwAddr; ///< SGW address
};
/**
* Map for eNB info by cell ID
*/
std::map<uint16_t, EnbInfo> m_enbInfoByCellId;
/**
* Map for eNB address by TEID
*/
std::map<uint32_t, Ipv4Address> m_enbByTeidMap;
/**
* MME S11 FTEID by SGW S5C TEID
*/
std::map<uint32_t, GtpcHeader::Fteid_t> m_mmeS11FteidBySgwS5cTeid;
};
} // namespace ns3
#endif // EPC_SGW_APPLICATION_H

View File

@@ -295,5 +295,11 @@ EpcTft::Matches (Direction direction,
return false;
}
std::list<EpcTft::PacketFilter>
EpcTft::GetPacketFilters () const
{
NS_LOG_FUNCTION (this);
return m_filters;
};
} // namespace ns3

View File

@@ -195,6 +195,8 @@ public:
uint8_t typeOfService);
std::list<PacketFilter> GetPacketFilters () const;
private:
std::list<PacketFilter> m_filters; ///< packet filter list

View File

@@ -636,7 +636,7 @@ FdTbfqFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::S
newRar.m_grant.m_tpc = 0;
newRar.m_grant.m_cqiRequest = false;
newRar.m_grant.m_ulDelay = false;
NS_LOG_INFO (this << " UL grant allocated to RNTI " << (*itRach).m_rnti << " rbStart " << rbStart << " rbLen " << rbLen << " MCS " << m_ulGrantMcs << " tbSize " << newRar.m_grant.m_tbSize);
NS_LOG_INFO (this << " UL grant allocated to RNTI " << (*itRach).m_rnti << " rbStart " << rbStart << " rbLen " << rbLen << " MCS " << (uint16_t) m_ulGrantMcs << " tbSize " << newRar.m_grant.m_tbSize);
for (uint16_t i = rbStart; i < rbStart + rbLen; i++)
{
m_rachAllocationMap.at (i) = (*itRach).m_rnti;
@@ -1385,7 +1385,7 @@ FdTbfqFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::S
newDci.m_mcs.push_back (m_amc->GetMcsFromCqi (worstCqi.at (j)));
int tbSize = (m_amc->GetDlTbSizeFromMcs (newDci.m_mcs.at (j), RgbPerRnti * rbgSize) / 8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
newDci.m_tbsSize.push_back (tbSize);
NS_LOG_INFO (this << " Layer " << (uint16_t)j << " MCS selected" << m_amc->GetMcsFromCqi (worstCqi.at (j)));
NS_LOG_INFO (this << " Layer " << (uint16_t)j << " MCS selected" << (uint16_t) m_amc->GetMcsFromCqi (worstCqi.at (j)));
bytesTxed += tbSize;
}

View File

@@ -114,6 +114,7 @@ static const std::string g_ueManagerStateName[UeManager::NUM_STATES] =
"INITIAL_RANDOM_ACCESS",
"CONNECTION_SETUP",
"CONNECTION_REJECTED",
"ATTACH_REQUEST",
"CONNECTED_NORMALLY",
"CONNECTION_RECONFIGURATION",
"CONNECTION_REESTABLISHMENT",
@@ -362,6 +363,21 @@ UeManager::SetImsi (uint64_t imsi)
m_imsi = imsi;
}
void
UeManager::InitialContextSetupRequest ()
{
NS_LOG_FUNCTION (this << m_rnti);
if (m_state == ATTACH_REQUEST)
{
SwitchToState (CONNECTED_NORMALLY);
}
else
{
NS_FATAL_ERROR ("method unexpected in state " << ToString (m_state));
}
}
void
UeManager::SetupDataRadioBearer (EpsBearer bearer, uint8_t bearerId, uint32_t gtpTeid, Ipv4Address transportLayerAddress)
{
@@ -554,6 +570,7 @@ UeManager::ScheduleRrcConnectionReconfiguration ()
{
case INITIAL_RANDOM_ACCESS:
case CONNECTION_SETUP:
case ATTACH_REQUEST:
case CONNECTION_RECONFIGURATION:
case CONNECTION_REESTABLISHMENT:
case HANDOVER_PREPARATION:
@@ -878,10 +895,6 @@ UeManager::RecvRrcConnectionRequest (LteRrcSap::RrcConnectionRequest msg)
if (m_rrc->m_admitRrcConnectionRequest == true)
{
m_imsi = msg.ueIdentity;
if (m_rrc->m_s1SapProvider != 0)
{
m_rrc->m_s1SapProvider->InitialUeMessage (m_imsi, m_rnti);
}
// send RRC CONNECTION SETUP to UE
LteRrcSap::RrcConnectionSetup msg2;
@@ -931,12 +944,16 @@ UeManager::RecvRrcConnectionSetupCompleted (LteRrcSap::RrcConnectionSetupComplet
m_pendingRrcConnectionReconfiguration = true; // Force Reconfiguration
m_pendingStartDataRadioBearers = true;
}
if (m_rrc->m_s1SapProvider != 0)
{
m_rrc->m_s1SapProvider->InitialUeMessage (m_imsi, m_rnti);
SwitchToState (ATTACH_REQUEST);
}
else
{
m_pendingStartDataRadioBearers = false;
StartDataRadioBearers ();
SwitchToState (CONNECTED_NORMALLY);
}
SwitchToState (CONNECTED_NORMALLY);
m_rrc->m_connectionEstablishedTrace (m_imsi, m_rrc->ComponentCarrierToCellId (m_componentCarrierId), m_rnti);
break;
@@ -1291,6 +1308,7 @@ UeManager::BuildRrcConnectionReconfiguration ()
LteRrcSap::RadioResourceConfigDedicated
UeManager::BuildRadioResourceConfigDedicated ()
{
NS_LOG_FUNCTION (this);
LteRrcSap::RadioResourceConfigDedicated rrcd;
if (m_srb1 != 0)
@@ -1322,6 +1340,7 @@ UeManager::BuildRadioResourceConfigDedicated ()
uint8_t
UeManager::GetNewRrcTransactionIdentifier ()
{
NS_LOG_FUNCTION (this);
++m_lastRrcTransactionIdentifier;
m_lastRrcTransactionIdentifier %= 4;
return m_lastRrcTransactionIdentifier;
@@ -1385,6 +1404,9 @@ UeManager::SwitchToState (State newState)
case CONNECTION_SETUP:
break;
case ATTACH_REQUEST:
break;
case CONNECTED_NORMALLY:
{
if (m_pendingRrcConnectionReconfiguration == true)
@@ -2272,9 +2294,18 @@ LteEnbRrc::DoRecvMeasurementReport (uint16_t rnti, LteRrcSap::MeasurementReport
GetUeManager (rnti)->RecvMeasurementReport (msg);
}
void
LteEnbRrc::DoInitialContextSetupRequest (EpcEnbS1SapUser::InitialContextSetupRequestParameters msg)
{
NS_LOG_FUNCTION (this);
Ptr<UeManager> ueManager = GetUeManager (msg.rnti);
ueManager->InitialContextSetupRequest ();
}
void
LteEnbRrc::DoDataRadioBearerSetupRequest (EpcEnbS1SapUser::DataRadioBearerSetupRequestParameters request)
{
NS_LOG_FUNCTION (this);
Ptr<UeManager> ueManager = GetUeManager (request.rnti);
ueManager->SetupDataRadioBearer (request.bearer, request.bearerId, request.gtpTeid, request.transportLayerAddress);
}
@@ -2282,6 +2313,7 @@ LteEnbRrc::DoDataRadioBearerSetupRequest (EpcEnbS1SapUser::DataRadioBearerSetupR
void
LteEnbRrc::DoPathSwitchRequestAcknowledge (EpcEnbS1SapUser::PathSwitchRequestAcknowledgeParameters params)
{
NS_LOG_FUNCTION (this);
Ptr<UeManager> ueManager = GetUeManager (params.rnti);
ueManager->SendUeContextRelease ();
}

View File

@@ -86,6 +86,7 @@ public:
INITIAL_RANDOM_ACCESS = 0,
CONNECTION_SETUP,
CONNECTION_REJECTED,
ATTACH_REQUEST,
CONNECTED_NORMALLY,
CONNECTION_RECONFIGURATION,
CONNECTION_REESTABLISHMENT,
@@ -139,6 +140,12 @@ public:
*/
void SetImsi (uint64_t imsi);
/**
* Process Initial context setup request message from the MME.
* It triggers RRC connection reconfiguration.
*/
void InitialContextSetupRequest ();
/**
* Setup a new data radio bearer, including both the configuration
* within the eNB and the necessary RRC signaling with the UE
@@ -1086,6 +1093,12 @@ private:
// S1 SAP methods
/**
* Initial context setup request function
*
* \param params EpcEnbS1SapUser::InitialContextSetupRequestParameters
*/
void DoInitialContextSetupRequest (EpcEnbS1SapUser::InitialContextSetupRequestParameters params);
/**
* Data radio beaerer setup request function
*

View File

@@ -620,7 +620,7 @@ PssFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::Sche
newRar.m_grant.m_tpc = 0;
newRar.m_grant.m_cqiRequest = false;
newRar.m_grant.m_ulDelay = false;
NS_LOG_INFO (this << " UL grant allocated to RNTI " << (*itRach).m_rnti << " rbStart " << rbStart << " rbLen " << rbLen << " MCS " << m_ulGrantMcs << " tbSize " << newRar.m_grant.m_tbSize);
NS_LOG_INFO (this << " UL grant allocated to RNTI " << (*itRach).m_rnti << " rbStart " << rbStart << " rbLen " << rbLen << " MCS " << (uint16_t)m_ulGrantMcs << " tbSize " << newRar.m_grant.m_tbSize);
for (uint16_t i = rbStart; i < rbStart + rbLen; i++)
{
m_rachAllocationMap.at (i) = (*itRach).m_rnti;

View File

@@ -160,6 +160,7 @@ EpcS1uDlTestCase::DoRun ()
NodeContainer enbs;
uint16_t cellIdCounter = 0;
uint64_t imsiCounter = 0;
for (std::vector<EnbDlTestData>::iterator enbit = m_enbDlTestData.begin ();
enbit < m_enbDlTestData.end ();
@@ -194,6 +195,7 @@ EpcS1uDlTestCase::DoRun ()
Ptr<EpcEnbApplication> enbApp = enb->GetApplication (0)->GetObject<EpcEnbApplication> ();
NS_ASSERT_MSG (enbApp != 0, "cannot retrieve EpcEnbApplication");
Ptr<EpcTestRrc> rrc = CreateObject<EpcTestRrc> ();
enb->AggregateObject (rrc);
rrc->SetS1SapProvider (enbApp->GetS1SapProvider ());
enbApp->SetS1SapUser (rrc->GetS1SapUser ());
@@ -231,10 +233,12 @@ EpcS1uDlTestCase::DoRun ()
apps.Stop (Seconds (10.0));
enbit->ues[u].clientApp = apps.Get (0);
uint64_t imsi = u+1;
uint64_t imsi = ++imsiCounter;
epcHelper->AddUe (ueLteDevice, imsi);
epcHelper->ActivateEpsBearer (ueLteDevice, imsi, EpcTft::Default (), EpsBearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT));
enbApp->GetS1SapProvider ()->InitialUeMessage (imsi, (uint16_t) imsi);
Simulator::Schedule (MilliSeconds (10),
&EpcEnbS1SapProvider::InitialUeMessage,
enbApp->GetS1SapProvider (), imsi, (uint16_t) imsi);
}
}

View File

@@ -378,6 +378,7 @@ EpcS1uUlTestCase::DoRun ()
NodeContainer enbs;
uint16_t cellIdCounter = 0;
uint64_t imsiCounter = 0;
for (std::vector<EnbUlTestData>::iterator enbit = m_enbUlTestData.begin ();
enbit < m_enbUlTestData.end ();
@@ -412,6 +413,7 @@ EpcS1uUlTestCase::DoRun ()
Ptr<EpcEnbApplication> enbApp = enb->GetApplication (0)->GetObject<EpcEnbApplication> ();
NS_ASSERT_MSG (enbApp != 0, "cannot retrieve EpcEnbApplication");
Ptr<EpcTestRrc> rrc = CreateObject<EpcTestRrc> ();
enb->AggregateObject (rrc);
rrc->SetS1SapProvider (enbApp->GetS1SapProvider ());
enbApp->SetS1SapUser (rrc->GetS1SapUser ());
@@ -475,11 +477,12 @@ EpcS1uUlTestCase::DoRun ()
clientApp.Stop (Seconds (10.0));
enbit->ues[u].clientApp = client;
uint64_t imsi = u+1;
uint64_t imsi = ++imsiCounter;
epcHelper->AddUe (ueLteDevice, imsi);
epcHelper->ActivateEpsBearer (ueLteDevice, imsi, EpcTft::Default (), EpsBearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT));
enbApp->GetS1SapProvider ()->InitialUeMessage (imsi, (uint16_t) imsi);
Simulator::Schedule (MilliSeconds (10),
&EpcEnbS1SapProvider::InitialUeMessage,
enbApp->GetS1SapProvider (), imsi, enbit->ues[u].rnti);
// need this since all sinks are installed in the same node
++udpSinkPort;
}

View File

@@ -725,6 +725,12 @@ EpcTestRrc::GetS1SapUser ()
return m_s1SapUser;
}
void
EpcTestRrc::DoInitialContextSetupRequest (EpcEnbS1SapUser::InitialContextSetupRequestParameters request)
{
}
void
EpcTestRrc::DoDataRadioBearerSetupRequest (EpcEnbS1SapUser::DataRadioBearerSetupRequestParameters request)
{

View File

@@ -446,6 +446,11 @@ public:
private:
// S1 SAP methods
/**
* Initial context setup request
* \param params EpcEnbS1SapUser::InitialContextSetupRequestParameters
*/
void DoInitialContextSetupRequest (EpcEnbS1SapUser::InitialContextSetupRequestParameters params);
/**
* Data radio bearer setup request
* \param params EpcEnbS1SapUser::DataRadioBearerSetupRequestParameters

View File

@@ -1801,12 +1801,12 @@ LteUeMeasurementsHandoverTestCase::DoRun ()
lteHelper->AddX2Interface (enbNodes);
// Connect to trace sources in source eNodeB
Config::Connect ("/NodeList/1/DeviceList/0/LteEnbRrc/RecvMeasurementReport",
Config::Connect ("/NodeList/3/DeviceList/0/LteEnbRrc/RecvMeasurementReport",
MakeCallback (&LteUeMeasurementsHandoverTestCase::RecvMeasurementReportCallback,
this));
// Connect to trace sources in target eNodeB
Config::Connect ("/NodeList/2/DeviceList/0/LteEnbRrc/RecvMeasurementReport",
Config::Connect ("/NodeList/4/DeviceList/0/LteEnbRrc/RecvMeasurementReport",
MakeCallback (&LteUeMeasurementsHandoverTestCase::RecvMeasurementReportCallback,
this));

View File

@@ -84,9 +84,13 @@ def build(bld):
'model/pss-ff-mac-scheduler.cc',
'model/cqa-ff-mac-scheduler.cc',
'model/epc-gtpu-header.cc',
'model/epc-gtpc-header.cc',
'model/trace-fading-loss-model.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',
'model/epc-x2-sap.cc',
'model/epc-x2-header.cc',
'model/epc-x2.cc',
@@ -276,8 +280,12 @@ def build(bld):
'model/cqa-ff-mac-scheduler.h',
'model/trace-fading-loss-model.h',
'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',
'model/lte-vendor-specific-parameters.h',
'model/epc-x2-sap.h',
'model/epc-x2-header.h',