diff --git a/CHANGES.html b/CHANGES.html
index 35824a2fc..50000293c 100644
--- a/CHANGES.html
+++ b/CHANGES.html
@@ -83,6 +83,21 @@ us a note on ns-developers mailing list.
Changed behavior:
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.
+
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:
+
+
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.
+
+
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index bfd5857af..8dd8915bd 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -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
------------
diff --git a/doc/models/Makefile b/doc/models/Makefile
index d95dbef8c..4c9dd791b 100644
--- a/doc/models/Makefile
+++ b/doc/models/Makefile
@@ -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 \
diff --git a/src/lte/doc/Makefile b/src/lte/doc/Makefile
index 0e4db44ce..eb303204d 100644
--- a/src/lte/doc/Makefile
+++ b/src/lte/doc/Makefile
@@ -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 \
diff --git a/src/lte/doc/source/figures/helpers.seqdiag b/src/lte/doc/source/figures/helpers.seqdiag
index f7db1c60d..4a2ae22e7 100644
--- a/src/lte/doc/source/figures/helpers.seqdiag
+++ b/src/lte/doc/source/figures/helpers.seqdiag
@@ -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"]
+}
-}
\ No newline at end of file
+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"]
+ }
+}
+
+}
diff --git a/src/lte/doc/source/figures/nas-attach.seqdiag b/src/lte/doc/source/figures/nas-attach.seqdiag
index e3df38269..1e414d9ac 100644
--- a/src/lte/doc/source/figures/nas-attach.seqdiag
+++ b/src/lte/doc/source/figures/nas-attach.seqdiag
@@ -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"]
}
-
diff --git a/src/lte/doc/source/lte-design.rst b/src/lte/doc/source/lte-design.rst
index 27183b980..945e8bdba 100644
--- a/src/lte/doc/source/lte-design.rst
+++ b/src/lte/doc/source/lte-design.rst
@@ -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
diff --git a/src/lte/doc/source/lte-references.rst b/src/lte/doc/source/lte-references.rst
index 6c55a90fc..c3709bc82 100644
--- a/src/lte/doc/source/lte-references.rst
+++ b/src/lte/doc/source/lte-references.rst
@@ -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"
diff --git a/src/lte/examples/lena-simple-epc.cc b/src/lte/examples/lena-simple-epc.cc
index dcd0cdb59..f21e06193 100644
--- a/src/lte/examples/lena-simple-epc.cc
+++ b/src/lte/examples/lena-simple-epc.cc
@@ -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
+ * Authors: Jaume Nin
+ * Manuel Requena
*/
-#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 = CreateObject ();
- Ptr epcHelper = CreateObject ();
+ Ptr epcHelper = CreateObject ();
lteHelper->SetEpcHelper (epcHelper);
- ConfigStore inputConfig;
- inputConfig.ConfigureDefaults();
-
- // parse again so you can override default values from the command line
- cmd.Parse(argc, argv);
-
Ptr 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 positionAlloc = CreateObject ();
- 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");
diff --git a/src/lte/helper/point-to-point-epc-helper.cc b/src/lte/helper/point-to-point-epc-helper.cc
index 8fd0cb156..380e7036b 100644
--- a/src/lte/helper/point-to-point-epc-helper.cc
+++ b/src/lte/helper/point-to-point-epc-helper.cc
@@ -1,6 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2011-2013 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ * Copyright (c) 2011-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
#include
#include
-#include
#include "ns3/ipv6-static-routing.h"
#include "ns3/ipv6-static-routing-helper.h"
+#include
+#include
+#include
+
#include
#include
#include
#include
-#include
#include
#include
#include
@@ -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 ();
+ // Create PGW, SGW and MME nodes
+ m_pgw = CreateObject ();
+ m_sgw = CreateObject ();
+ m_mme = CreateObject ();
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 pgwStaticRouting = ipv6RoutingHelper.GetStaticRouting (m_sgwPgw->GetObject ());
+ Ptr pgwStaticRouting = ipv6RoutingHelper.GetStaticRouting (m_pgw->GetObject ());
pgwStaticRouting->AddNetworkRouteTo ("7777:f00d::", Ipv6Prefix (64), Ipv6Address ("::"), 1, 0);
-
- // create S1-U socket
- Ptr 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 ();
// 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 (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 ()->GetNInterfaces ());
+ NS_LOG_LOGIC ("IPv4 ifaces of the SGW after installing p2p dev: " << m_sgw->GetObject ()->GetNInterfaces ());
+ Ptr pgwDev = pgwSgwDevices.Get (0);
+ Ptr 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 ()->GetNInterfaces ());
+ NS_LOG_LOGIC ("IPv4 ifaces of the SGW after assigning Ipv4 addr to S5 dev: " << m_sgw->GetObject ()->GetNInterfaces ());
+
+ Ipv4Address pgwS5Address = pgwSgwIpIfaces.GetAddress (0);
+ Ipv4Address sgwS5Address = pgwSgwIpIfaces.GetAddress (1);
+
+ // Create S5-U socket in the PGW
+ Ptr 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 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 (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 ();
- m_mme->SetS11SapSgw (m_sgwPgwApp->GetS11SapSgw ());
- m_sgwPgwApp->SetS11SapMme (m_mme->GetS11SapMme ());
+ // Create S5-U socket in the SGW
+ Ptr 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 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 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 (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 ()->GetNInterfaces ());
+ NS_LOG_LOGIC ("SGW's IPv4 ifaces after installing p2p dev: " << m_sgw->GetObject ()->GetNInterfaces ());
+ Ptr mmeDev = mmeSgwDevices.Get (0);
+ Ptr 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 ()->GetNInterfaces ());
+ NS_LOG_LOGIC ("SGW's IPv4 ifaces after assigning Ipv4 addr to S11 dev: " << m_sgw->GetObject ()->GetNInterfaces ());
+
+ Ipv4Address mmeS11Address = mmeSgwIpIfaces.GetAddress (0);
+ Ipv4Address sgwS11Address = mmeSgwIpIfaces.GetAddress (1);
+
+ // Create S11 socket in the MME
+ Ptr 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 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 ();
+ 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 ()
.SetGroupName("Lte")
@@ -160,6 +260,36 @@ PointToPointEpcHelper::GetTypeId (void)
UintegerValue (2000),
MakeUintegerAccessor (&PointToPointEpcHelper::m_s1uLinkMtu),
MakeUintegerChecker ())
+ .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 ())
+ .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 ())
.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, 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 enb, Ptr 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 ()->GetNInterfaces ());
+ NetDeviceContainer enbSgwDevices = p2ph.Install (enb, m_sgw);
+ NS_LOG_LOGIC ("Ipv4 ifaces of the eNB after installing p2p dev: " << enb->GetObject ()->GetNInterfaces ());
Ptr enbDev = enbSgwDevices.Get (0);
Ptr sgwDev = enbSgwDevices.Get (1);
@@ -251,21 +385,24 @@ PointToPointEpcHelper::AddEnb (Ptr enb, Ptr 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 ()->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 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 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 enb, Ptr lteEnbNetDevice, ui
retval = enbLteSocket6->Connect (enbLteSocketConnectAddress6);
NS_ASSERT (retval == 0);
- NS_LOG_INFO ("create EpcEnbApplication");
- Ptr enbApp = CreateObject (enbLteSocket, enbLteSocket6, enbS1uSocket, enbAddress, sgwAddress, cellId);
+ NS_LOG_INFO ("Create EpcEnbApplication");
+ Ptr enbApp = CreateObject (enbLteSocket, enbLteSocket6, enbS1uSocket, enbS1uAddress, sgwS1uAddress, cellId);
enb->AddApplication (enbApp);
NS_ASSERT (enb->GetNApplications () == 1);
NS_ASSERT_MSG (enb->GetApplication (0)->GetObject () != 0, "cannot retrieve EpcEnbApplication");
NS_LOG_LOGIC ("enb: " << enb << ", enb->GetApplication (0): " << enb->GetApplication (0));
-
NS_LOG_INFO ("Create EpcX2 entity");
Ptr x2 = CreateObject ();
enb->AggregateObject (x2);
- 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 enb1, Ptr enb2)
void
PointToPointEpcHelper::AddUe (Ptr 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 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 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 ueLteDevice = ueDevice->GetObject ();
if (ueLteDevice)
{
@@ -414,7 +548,7 @@ PointToPointEpcHelper::ActivateEpsBearer (Ptr ueDevice, uint64_t imsi
Ptr
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 ()->GetAddress (1, 0).GetLocal ();
+ return m_pgw->GetObject ()->GetAddress (1, 0).GetLocal ();
}
Ipv6Address
PointToPointEpcHelper::GetUeDefaultGatewayAddress6 ()
{
// return the address of the tun device
- return m_sgwPgw->GetObject ()->GetAddress (1, 1).GetAddress ();
+ return m_pgw->GetObject ()->GetAddress (1, 1).GetAddress ();
}
} // namespace ns3
diff --git a/src/lte/helper/point-to-point-epc-helper.h b/src/lte/helper/point-to-point-epc-helper.h
index c6da63591..980d8bc78 100644
--- a/src/lte/helper/point-to-point-epc-helper.h
+++ b/src/lte/helper/point-to-point-epc-helper.h
@@ -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 m_sgwPgw;
+ Ptr m_sgw;
/**
- * SGW-PGW application
+ * PGW network element
*/
- Ptr m_sgwPgwApp;
+ Ptr m_pgw;
+
+ /**
+ * MME network element
+ */
+ Ptr m_mme;
+
+ /**
+ * SGW application
+ */
+ Ptr m_sgwApp;
+
+ /**
+ * PGW application
+ */
+ Ptr m_pgwApp;
+
+ /**
+ * MME application
+ */
+ Ptr m_mmeApp;
/**
* TUN device implementing tunneling of user data over GTP-U/UDP/IP
*/
Ptr m_tunDevice;
- /**
- * MME network element
- */
- Ptr 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
diff --git a/src/lte/model/epc-enb-application.cc b/src/lte/model/epc-enb-application.cc
index dcc5dc517..e78fa0e01 100644
--- a/src/lte/model/epc-enb-application.cc
+++ b/src/lte/model/epc-enb-application.cc
@@ -206,18 +206,17 @@ void
EpcEnbApplication::DoInitialContextSetupRequest (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list erabToBeSetupList)
{
NS_LOG_FUNCTION (this);
-
+
+ uint64_t imsi = mmeUeS1Id;
+ std::map::iterator imsiIt = m_imsiRntiMap.find (imsi);
+ NS_ASSERT_MSG (imsiIt != m_imsiRntiMap.end (), "unknown IMSI");
+ uint16_t rnti = imsiIt->second;
+
for (std::list::iterator erabIt = erabToBeSetupList.begin ();
erabIt != erabToBeSetupList.end ();
++erabIt)
{
// request the RRC to setup a radio bearer
-
- uint64_t imsi = mmeUeS1Id;
- std::map::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
diff --git a/src/lte/model/epc-enb-s1-sap.h b/src/lte/model/epc-enb-s1-sap.h
index 6b474826d..1ac4aa697 100644
--- a/src/lte/model/epc-enb-s1-sap.h
+++ b/src/lte/model/epc-enb-s1-sap.h
@@ -22,7 +22,6 @@
#define EPC_ENB_S1_SAP_H
#include
-#include
#include
#include
@@ -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::MemberEpcEnbS1SapUser ()
{
}
+template
+void MemberEpcEnbS1SapUser::InitialContextSetupRequest (InitialContextSetupRequestParameters params)
+{
+ m_owner->DoInitialContextSetupRequest (params);
+}
+
template
void MemberEpcEnbS1SapUser::DataRadioBearerSetupRequest (DataRadioBearerSetupRequestParameters params)
{
diff --git a/src/lte/model/epc-gtpc-header.cc b/src/lte/model/epc-gtpc-header.cc
new file mode 100644
index 000000000..e699cd9fb
--- /dev/null
+++ b/src/lte/model/epc-gtpc-header.cc
@@ -0,0 +1,1287 @@
+/* -*- 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
+ */
+
+#include "ns3/epc-gtpc-header.h"
+#include "ns3/log.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("GtpcHeader");
+
+NS_OBJECT_ENSURE_REGISTERED (GtpcHeader);
+
+TypeId
+GtpcHeader::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::GtpcHeader")
+ .SetParent ()
+ .SetGroupName ("Lte")
+ .AddConstructor ();
+ return tid;
+}
+
+GtpcHeader::GtpcHeader ()
+ : m_teidFlag (false),
+ m_messageType (0),
+ m_messageLength (4),
+ m_teid (0),
+ m_sequenceNumber (0)
+{
+}
+
+GtpcHeader::~GtpcHeader ()
+{
+}
+
+TypeId
+GtpcHeader::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+
+uint32_t
+GtpcHeader::GetSerializedSize (void) const
+{
+ return m_teidFlag ? 12 : 8;
+}
+
+void
+GtpcHeader::Serialize (Buffer::Iterator start) const
+{
+ NS_FATAL_ERROR ("Serialize GTP-C header is forbidden");
+}
+
+void
+GtpcHeader::PreSerialize (Buffer::Iterator &i) const
+{
+ i.WriteU8 ((2 << 5) | (1 << 3));
+ i.WriteU8 (m_messageType);
+ i.WriteHtonU16 (m_messageLength);
+ i.WriteHtonU32 (m_teid);
+ i.WriteU8 ((m_sequenceNumber & 0x00ff0000) >> 16);
+ i.WriteU8 ((m_sequenceNumber & 0x0000ff00) >> 8);
+ i.WriteU8 (m_sequenceNumber & 0x000000ff);
+ i.WriteU8 (0);
+}
+
+uint32_t
+GtpcHeader::Deserialize (Buffer::Iterator start)
+{
+ return PreDeserialize (start);
+}
+
+uint32_t
+GtpcHeader::PreDeserialize (Buffer::Iterator &i)
+{
+ uint8_t firstByte = i.ReadU8 ();
+ uint8_t version = (firstByte >> 5) & 0x07;
+ if (version != 2)
+ {
+ NS_FATAL_ERROR ("GTP-C version not supported");
+ return 0;
+ }
+
+ m_teidFlag = ((firstByte >> 3) & 0x01) == 1;
+ if (!m_teidFlag)
+ {
+ NS_FATAL_ERROR ("TEID is missing");
+ return 0;
+ }
+
+ m_messageType = i.ReadU8 ();
+ m_messageLength = i.ReadNtohU16 ();
+ if (m_teidFlag)
+ {
+ m_teid = i.ReadNtohU32 ();
+ }
+ m_sequenceNumber = i.ReadU8 () << 16 | i.ReadU8 () << 8 | i.ReadU8 ();
+ i.ReadU8();
+
+ return GtpcHeader::GetSerializedSize ();
+}
+
+void
+GtpcHeader::Print (std::ostream &os) const
+{
+ os << " messageType " << (uint32_t) m_messageType << " messageLength " << m_messageLength;
+ os << " TEID " << m_teid << " sequenceNumber " << m_sequenceNumber;
+}
+
+uint32_t
+GtpcHeader::GetMessageSize (void) const
+{
+ return 0;
+}
+
+uint8_t
+GtpcHeader::GetMessageType () const
+{
+ return m_messageType;
+}
+
+uint16_t
+GtpcHeader::GetMessageLength () const
+{
+ return m_messageLength;
+}
+
+uint32_t
+GtpcHeader::GetTeid () const
+{
+ return m_teid;
+}
+
+uint32_t
+GtpcHeader::GetSequenceNumber () const
+{
+ return m_sequenceNumber;
+}
+
+void
+GtpcHeader::SetMessageType (uint8_t messageType)
+{
+ m_messageType = messageType;
+}
+
+void
+GtpcHeader::SetMessageLength (uint16_t messageLength)
+{
+ m_messageLength = messageLength;
+}
+
+void
+GtpcHeader::SetTeid (uint32_t teid)
+{
+ m_teidFlag = true;
+ m_teid = teid;
+ m_messageLength = m_teidFlag ? 8 : 4;
+}
+
+void
+GtpcHeader::SetSequenceNumber (uint32_t sequenceNumber)
+{
+ m_sequenceNumber = sequenceNumber;
+}
+
+void
+GtpcHeader::SetIesLength (uint16_t iesLength)
+{
+ m_messageLength = iesLength;
+ m_messageLength += (m_teidFlag) ? 8 : 4;
+}
+
+void
+GtpcHeader::ComputeMessageLength (void)
+{
+ SetIesLength (GetMessageSize ());
+}
+/////////////////////////////////////////////////////////////////////
+
+void
+GtpcIes::SerializeImsi (Buffer::Iterator &i, uint64_t imsi) const
+{
+ i.WriteU8 (1); // IE Type = IMSI
+ i.WriteHtonU16 (8); // Length
+ i.WriteU8 (0); // Spare + Instance
+ i.WriteHtonU64 (imsi);
+}
+
+uint32_t
+GtpcIes::DeserializeImsi (Buffer::Iterator &i, uint64_t &imsi)
+{
+ uint8_t type = i.ReadU8 ();
+ NS_ASSERT_MSG (type == 1, "Wrong IMSI IE type = " << (uint16_t) type);
+ uint16_t length = i.ReadNtohU16 ();
+ NS_ASSERT_MSG (length == 8, "Wrong IMSI IE length");
+ uint8_t instance = i.ReadU8 () & 0x0f;
+ NS_ASSERT_MSG (instance == 0, "Wrong IMSI IE instance");
+ imsi = i.ReadNtohU64 ();
+
+ return serializedSizeImsi;
+}
+
+void
+GtpcIes::SerializeCause (Buffer::Iterator &i, Cause_t cause) const
+{
+ i.WriteU8 (2); // IE Type = Cause
+ i.WriteHtonU16 (2); // Length
+ i.WriteU8 (0); // Spare + Instance
+ i.WriteU8 (cause); // Cause value
+ i.WriteU8 (0); // Spare + CS
+}
+
+uint32_t
+GtpcIes::DeserializeCause (Buffer::Iterator &i, Cause_t &cause)
+{
+ uint8_t type = i.ReadU8 ();
+ NS_ASSERT_MSG (type == 2, "Wrong Cause IE type = " << (uint16_t) type);
+ uint16_t length = i.ReadNtohU16 ();
+ NS_ASSERT_MSG (length == 2, "Wrong Cause IE length");
+ uint8_t instance = i.ReadU8 () & 0x0f;
+ NS_ASSERT_MSG (instance == 0, "Wrong Cause IE instance");
+ cause = Cause_t (i.ReadU8 ());
+ i.ReadU8 ();
+
+ return serializedSizeCause;
+}
+
+void
+GtpcIes::SerializeEbi (Buffer::Iterator &i, uint8_t epsBearerId) const
+{
+ i.WriteU8 (73); // IE Type = EPS Bearer ID (EBI)
+ i.WriteHtonU16 (1); // Length
+ i.WriteU8 (0); // Spare + Instance
+ i.WriteU8 (epsBearerId & 0x0f);
+}
+
+uint32_t
+GtpcIes::DeserializeEbi (Buffer::Iterator &i, uint8_t &epsBearerId)
+{
+ uint8_t type = i.ReadU8 ();
+ NS_ASSERT_MSG (type == 73, "Wrong EBI IE type = " << (uint16_t) type);
+ uint16_t length = i.ReadNtohU16 ();
+ NS_ASSERT_MSG (length == 1, "Wrong EBI IE length");
+ uint8_t instance = i.ReadU8 ();
+ NS_ASSERT_MSG (instance == 0, "Wrong EBI IE instance");
+ epsBearerId = i.ReadU8 () & 0x0f;
+
+ return serializedSizeEbi;
+}
+
+void
+GtpcIes::WriteHtonU40 (Buffer::Iterator &i, uint64_t data) const
+{
+ i.WriteU8 ((data >> 32) & 0xff);
+ i.WriteU8 ((data >> 24) & 0xff);
+ i.WriteU8 ((data >> 16) & 0xff);
+ i.WriteU8 ((data >> 8) & 0xff);
+ i.WriteU8 ((data >> 0) & 0xff);
+}
+
+uint64_t
+GtpcIes::ReadNtohU40 (Buffer::Iterator &i)
+{
+ uint64_t retval = 0;
+ retval |= i.ReadU8 ();
+ retval <<= 8;
+ retval |= i.ReadU8 ();
+ retval <<= 8;
+ retval |= i.ReadU8 ();
+ retval <<= 8;
+ retval |= i.ReadU8 ();
+ retval <<= 8;
+ retval |= i.ReadU8 ();
+ return retval;
+}
+
+void
+GtpcIes::SerializeBearerQos (Buffer::Iterator &i, EpsBearer bearerQos) const
+{
+ i.WriteU8 (80); // IE Type = Bearer QoS
+ i.WriteHtonU16 (22); // Length
+ i.WriteU8 (0); // Spare + Instance
+ i.WriteU8 (0); // MRE TODO: bearerQos.arp
+ i.WriteU8 (bearerQos.qci);
+ WriteHtonU40 (i, bearerQos.gbrQosInfo.mbrUl);
+ WriteHtonU40 (i, bearerQos.gbrQosInfo.mbrDl);
+ WriteHtonU40 (i, bearerQos.gbrQosInfo.gbrUl);
+ WriteHtonU40 (i, bearerQos.gbrQosInfo.gbrDl);
+}
+
+uint32_t
+GtpcIes::DeserializeBearerQos (Buffer::Iterator &i, EpsBearer &bearerQos)
+{
+ uint8_t type = i.ReadU8 ();
+ NS_ASSERT_MSG (type == 80, "Wrong Bearer QoS IE type = " << (uint16_t) type);
+ uint16_t length = i.ReadNtohU16 ();
+ NS_ASSERT_MSG (length == 22, "Wrong Bearer QoS IE length");
+ uint8_t instance = i.ReadU8 ();
+ NS_ASSERT_MSG (instance == 0, "Wrong Bearer QoS IE instance");
+ i.ReadU8 ();
+ bearerQos.qci = EpsBearer::Qci (i.ReadU8 ());
+ bearerQos.gbrQosInfo.mbrUl = ReadNtohU40 (i);
+ bearerQos.gbrQosInfo.mbrDl = ReadNtohU40 (i);
+ bearerQos.gbrQosInfo.gbrUl = ReadNtohU40 (i);
+ bearerQos.gbrQosInfo.gbrDl = ReadNtohU40 (i);
+ return serializedSizeBearerQos;
+}
+
+void
+GtpcIes::SerializeBearerTft (Buffer::Iterator &i, std::list packetFilters) const
+{
+ i.WriteU8 (84); // IE Type = EPS Bearer Level Fraffic Flow Template (Bearer TFT)
+ i.WriteHtonU16 (1 + packetFilters.size () * serializedSizePacketFilter);
+ i.WriteU8 (0); // Spare + Instance
+ i.WriteU8 (0x20 + (packetFilters.size () & 0x0f)); // Create new TFT + Number of packet filters
+
+ for (auto &pf : packetFilters)
+ {
+ i.WriteU8 ((pf.direction << 4) & 0x30);
+ i.WriteU8 (pf.precedence);
+ i.WriteU8 (serializedSizePacketFilter - 3); // Length of Packet filter contents
+
+ i.WriteU8 (0x10); // IPv4 remote address type
+ i.WriteHtonU32 (pf.remoteAddress.Get ());
+ i.WriteHtonU32 (pf.remoteMask.Get ());
+ i.WriteU8 (0x11); // IPv4 local address type
+ i.WriteHtonU32 (pf.localAddress.Get ());
+ i.WriteHtonU32 (pf.localMask.Get ());
+ i.WriteU8 (0x41); // Local port range type
+ i.WriteHtonU16 (pf.localPortStart);
+ i.WriteHtonU16 (pf.localPortEnd);
+ i.WriteU8 (0x51); // Remote port range type
+ i.WriteHtonU16 (pf.remotePortStart);
+ i.WriteHtonU16 (pf.remotePortEnd);
+ i.WriteU8 (0x70); // Type of service
+ i.WriteU8 (pf.typeOfService);
+ i.WriteU8 (pf.typeOfServiceMask);
+ }
+}
+
+uint32_t
+GtpcIes::DeserializeBearerTft (Buffer::Iterator &i, Ptr epcTft)
+{
+ uint8_t type = i.ReadU8 ();
+ NS_ASSERT_MSG (type == 84, "Wrong Bearer TFT IE type = " << (uint16_t) type);
+ i.ReadNtohU16 ();
+ i.ReadU8 ();
+ uint8_t numberOfPacketFilters = i.ReadU8 () & 0x0f;
+
+ for (uint8_t pf = 0; pf < numberOfPacketFilters; ++pf)
+ {
+ EpcTft::PacketFilter packetFilter;
+ packetFilter.direction = EpcTft::Direction ((i.ReadU8 () & 0x30) >> 4);
+ packetFilter.precedence = i.ReadU8 ();
+ i.ReadU8 (); // Length of Packet filter contents
+ i.ReadU8 ();
+ packetFilter.remoteAddress = Ipv4Address (i.ReadNtohU32 ());
+ packetFilter.remoteMask = Ipv4Mask (i.ReadNtohU32 ());
+ i.ReadU8 ();
+ packetFilter.localAddress = Ipv4Address (i.ReadNtohU32 ());
+ packetFilter.localMask = Ipv4Mask (i.ReadNtohU32 ());
+ i.ReadU8 ();
+ packetFilter.localPortStart = i.ReadNtohU16 ();
+ packetFilter.localPortEnd = i.ReadNtohU16 ();
+ i.ReadU8 ();
+ packetFilter.remotePortStart = i.ReadNtohU16 ();
+ packetFilter.remotePortEnd = i.ReadNtohU16 ();
+ i.ReadU8 ();
+ packetFilter.typeOfService = i.ReadU8 ();
+ packetFilter.typeOfServiceMask = i.ReadU8 ();
+ epcTft->Add (packetFilter);
+ }
+
+ return GetSerializedSizeBearerTft (epcTft->GetPacketFilters ());
+}
+
+inline uint32_t
+GtpcIes::GetSerializedSizeBearerTft (std::list packetFilters) const
+{
+ return (5 + packetFilters.size () * serializedSizePacketFilter);
+}
+
+void
+GtpcIes::SerializeUliEcgi (Buffer::Iterator &i, uint32_t uliEcgi) const
+{
+ i.WriteU8 (86); // IE Type = ULI (ECGI)
+ i.WriteHtonU16 (8); // Length
+ i.WriteU8 (0); // Spare + Instance
+ i.WriteU8 (0x10); // ECGI flag
+ i.WriteU8 (0); // Dummy MCC and MNC
+ i.WriteU8 (0); // Dummy MCC and MNC
+ i.WriteU8 (0); // Dummy MCC and MNC
+ i.WriteHtonU32 (uliEcgi);
+}
+
+uint32_t
+GtpcIes::DeserializeUliEcgi (Buffer::Iterator &i, uint32_t &uliEcgi)
+{
+ uint8_t type = i.ReadU8 ();
+ NS_ASSERT_MSG (type == 86, "Wrong ULI ECGI IE type = " << (uint16_t) type);
+ uint16_t length = i.ReadNtohU16 ();
+ NS_ASSERT_MSG (length == 8, "Wrong ULI ECGI IE length");
+ uint8_t instance = i.ReadU8 () & 0x0f;
+ NS_ASSERT_MSG (instance == 0, "Wrong ULI ECGI IE instance");
+ i.Next (4);
+ uliEcgi = i.ReadNtohU32 () & 0x0fffffff;
+
+ return serializedSizeUliEcgi;
+}
+
+void
+GtpcIes::SerializeFteid (Buffer::Iterator &i, GtpcHeader::Fteid_t fteid) const
+{
+ i.WriteU8 (87); // IE Type = Fully Qualified TEID (F-TEID)
+ i.WriteHtonU16 (9); // Length
+ i.WriteU8 (0); // Spare + Instance
+ i.WriteU8 (0x80 | ((uint8_t) fteid.interfaceType & 0x1f)); // IP version flag + Iface type
+ i.WriteHtonU32 (fteid.teid); // TEID
+ i.WriteHtonU32 (fteid.addr.Get ()); // IPv4 address
+}
+
+uint32_t
+GtpcIes::DeserializeFteid (Buffer::Iterator &i, GtpcHeader::Fteid_t &fteid)
+{
+ uint8_t type = i.ReadU8 ();
+ NS_ASSERT_MSG (type == 87, "Wrong FTEID IE type = " << (uint16_t) type);
+ uint16_t length = i.ReadNtohU16 ();
+ NS_ASSERT_MSG (length == 9, "Wrong FTEID IE length");
+ uint8_t instance = i.ReadU8 () & 0x0f;
+ NS_ASSERT_MSG (instance == 0, "Wrong FTEID IE instance");
+ uint8_t flags = i.ReadU8 (); // IP version flag + Iface type
+ fteid.interfaceType = GtpcHeader::InterfaceType_t (flags & 0x1f);
+ fteid.teid = i.ReadNtohU32 (); // TEID
+ fteid.addr.Set (i.ReadNtohU32 ()); // IPv4 address
+
+ return serializedSizeFteid;
+}
+
+void
+GtpcIes::SerializeBearerContextHeader (Buffer::Iterator &i, uint16_t length) const
+{
+ i.WriteU8 (93); // IE Type = Bearer Context
+ i.WriteU16 (length);
+ i.WriteU8 (0); // Spare + Instance
+}
+
+uint32_t
+GtpcIes::DeserializeBearerContextHeader (Buffer::Iterator &i, uint16_t &length)
+{
+ uint8_t type = i.ReadU8 ();
+ NS_ASSERT_MSG (type == 93, "Wrong Bearer Context IE type = " << (uint16_t) type);
+ length = i.ReadNtohU16 ();
+ uint8_t instance = i.ReadU8 () & 0x0f;
+ NS_ASSERT_MSG (instance == 0, "Wrong Bearer Context IE instance");
+
+ return serializedSizeBearerContextHeader;
+}
+
+/////////////////////////////////////////////////////////////////////
+
+TypeId
+GtpcCreateSessionRequestMessage::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::GtpcCreateSessionRequestMessage")
+ .SetParent ()
+ .SetGroupName ("Lte")
+ .AddConstructor ();
+ return tid;
+}
+
+GtpcCreateSessionRequestMessage::GtpcCreateSessionRequestMessage ()
+{
+ SetMessageType (GtpcHeader::CreateSessionRequest);
+ SetSequenceNumber (0);
+ m_imsi = 0;
+ m_uliEcgi = 0;
+}
+
+GtpcCreateSessionRequestMessage::~GtpcCreateSessionRequestMessage ()
+{
+}
+
+TypeId
+GtpcCreateSessionRequestMessage::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+
+uint32_t
+GtpcCreateSessionRequestMessage::GetMessageSize (void) const
+{
+ uint32_t serializedSize = serializedSizeImsi + serializedSizeUliEcgi + serializedSizeFteid;
+ for (auto &bc : m_bearerContextsToBeCreated)
+ {
+ serializedSize += serializedSizeBearerContextHeader + serializedSizeEbi
+ + GetSerializedSizeBearerTft (bc.tft->GetPacketFilters ())
+ + serializedSizeFteid + serializedSizeBearerQos;
+ }
+
+ return serializedSize;
+}
+
+uint32_t
+GtpcCreateSessionRequestMessage::GetSerializedSize (void) const
+{
+ return GtpcHeader::GetSerializedSize () + GetMessageSize ();
+}
+
+void
+GtpcCreateSessionRequestMessage::Serialize (Buffer::Iterator start) const
+{
+ Buffer::Iterator i = start;
+
+ GtpcHeader::PreSerialize (i);
+ SerializeImsi (i, m_imsi);
+ SerializeUliEcgi (i, m_uliEcgi);
+ SerializeFteid (i, m_senderCpFteid);
+
+ for (auto &bc : m_bearerContextsToBeCreated)
+ {
+ std::list packetFilters = bc.tft->GetPacketFilters ();
+
+ SerializeBearerContextHeader (i, serializedSizeEbi + GetSerializedSizeBearerTft (packetFilters) + serializedSizeFteid + serializedSizeBearerQos);
+
+ SerializeEbi (i, bc.epsBearerId);
+ SerializeBearerTft (i, packetFilters);
+ SerializeFteid (i, bc.sgwS5uFteid);
+ SerializeBearerQos (i, bc.bearerLevelQos);
+ }
+}
+
+uint32_t
+GtpcCreateSessionRequestMessage::Deserialize (Buffer::Iterator start)
+{
+ Buffer::Iterator i = start;
+ GtpcHeader::PreDeserialize (i);
+
+ DeserializeImsi (i, m_imsi);
+ DeserializeUliEcgi (i, m_uliEcgi);
+ DeserializeFteid (i, m_senderCpFteid);
+
+ m_bearerContextsToBeCreated.clear ();
+ while (i.GetRemainingSize () > 0)
+ {
+ uint16_t length;
+ DeserializeBearerContextHeader (i, length);
+
+ BearerContextToBeCreated bearerContext;
+ DeserializeEbi (i, bearerContext.epsBearerId);
+
+ Ptr epcTft = Create ();
+ DeserializeBearerTft (i, epcTft);
+ bearerContext.tft = epcTft;
+
+ DeserializeFteid (i, bearerContext.sgwS5uFteid);
+ DeserializeBearerQos (i, bearerContext.bearerLevelQos);
+
+ m_bearerContextsToBeCreated.push_back (bearerContext);
+ }
+
+ return GetSerializedSize ();
+}
+
+void
+GtpcCreateSessionRequestMessage::Print (std::ostream &os) const
+{
+ os << " imsi " << m_imsi << " uliEcgi " << m_uliEcgi;
+}
+
+uint64_t
+GtpcCreateSessionRequestMessage::GetImsi () const
+{
+ return m_imsi;
+}
+
+void
+GtpcCreateSessionRequestMessage::SetImsi (uint64_t imsi)
+{
+ m_imsi = imsi;
+}
+
+uint32_t
+GtpcCreateSessionRequestMessage::GetUliEcgi () const
+{
+ return m_uliEcgi;
+}
+
+void
+GtpcCreateSessionRequestMessage::SetUliEcgi (uint32_t uliEcgi)
+{
+ m_uliEcgi = uliEcgi;
+}
+
+GtpcHeader::Fteid_t
+GtpcCreateSessionRequestMessage::GetSenderCpFteid () const
+{
+ return m_senderCpFteid;
+}
+
+void
+GtpcCreateSessionRequestMessage::SetSenderCpFteid (GtpcHeader::Fteid_t fteid)
+{
+ m_senderCpFteid = fteid;
+}
+
+std::list
+GtpcCreateSessionRequestMessage::GetBearerContextsToBeCreated () const
+{
+ return m_bearerContextsToBeCreated;
+}
+
+void
+GtpcCreateSessionRequestMessage::SetBearerContextsToBeCreated (std::list bearerContexts)
+{
+ m_bearerContextsToBeCreated = bearerContexts;
+}
+
+/////////////////////////////////////////////////////////////////////
+
+TypeId
+GtpcCreateSessionResponseMessage::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::GtpcCreateSessionResponseMessage")
+ .SetParent ()
+ .SetGroupName ("Lte")
+ .AddConstructor ();
+ return tid;
+}
+
+GtpcCreateSessionResponseMessage::GtpcCreateSessionResponseMessage ()
+{
+ SetMessageType (GtpcHeader::CreateSessionResponse);
+ SetSequenceNumber (0);
+ m_cause = Cause_t::RESERVED;
+}
+
+GtpcCreateSessionResponseMessage::~GtpcCreateSessionResponseMessage ()
+{
+}
+
+TypeId
+GtpcCreateSessionResponseMessage::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+
+uint32_t
+GtpcCreateSessionResponseMessage::GetMessageSize (void) const
+{
+ uint32_t serializedSize = serializedSizeCause + serializedSizeFteid;
+ for (auto &bc : m_bearerContextsCreated)
+ {
+ serializedSize += serializedSizeBearerContextHeader + serializedSizeEbi
+ + GetSerializedSizeBearerTft (bc.tft->GetPacketFilters ())
+ + serializedSizeFteid + serializedSizeBearerQos;
+ }
+
+ return serializedSize;
+}
+
+uint32_t
+GtpcCreateSessionResponseMessage::GetSerializedSize (void) const
+{
+ return GtpcHeader::GetSerializedSize () + GetMessageSize ();
+}
+
+void
+GtpcCreateSessionResponseMessage::Serialize (Buffer::Iterator start) const
+{
+ Buffer::Iterator i = start;
+
+ GtpcHeader::PreSerialize (i);
+ SerializeCause (i, m_cause);
+ SerializeFteid (i, m_senderCpFteid);
+
+ for (auto &bc : m_bearerContextsCreated)
+ {
+ std::list packetFilters = bc.tft->GetPacketFilters ();
+
+ SerializeBearerContextHeader (i, serializedSizeEbi + GetSerializedSizeBearerTft (packetFilters) + serializedSizeFteid + serializedSizeBearerQos);
+
+ SerializeEbi (i, bc.epsBearerId);
+ SerializeBearerTft (i, packetFilters);
+ SerializeFteid (i, bc.fteid);
+ SerializeBearerQos (i, bc.bearerLevelQos);
+ }
+}
+
+uint32_t
+GtpcCreateSessionResponseMessage::Deserialize (Buffer::Iterator start)
+{
+ Buffer::Iterator i = start;
+ GtpcHeader::PreDeserialize (i);
+
+ DeserializeCause (i, m_cause);
+ DeserializeFteid (i, m_senderCpFteid);
+
+ m_bearerContextsCreated.clear ();
+ while (i.GetRemainingSize () > 0)
+ {
+ BearerContextCreated bearerContext;
+ uint16_t length;
+
+ DeserializeBearerContextHeader (i, length);
+ DeserializeEbi (i, bearerContext.epsBearerId);
+
+ Ptr epcTft = Create ();
+ DeserializeBearerTft (i, epcTft);
+ bearerContext.tft = epcTft;
+
+ DeserializeFteid (i, bearerContext.fteid);
+ DeserializeBearerQos (i, bearerContext.bearerLevelQos);
+
+ m_bearerContextsCreated.push_back (bearerContext);
+ }
+
+ return GetSerializedSize ();
+}
+
+void
+GtpcCreateSessionResponseMessage::Print (std::ostream &os) const
+{
+ os << " cause " << m_cause << " FTEID " << m_senderCpFteid.addr << "," << m_senderCpFteid.teid ;
+}
+
+GtpcCreateSessionResponseMessage::Cause_t
+GtpcCreateSessionResponseMessage::GetCause () const
+{
+ return m_cause;
+}
+
+void
+GtpcCreateSessionResponseMessage::SetCause (GtpcCreateSessionResponseMessage::Cause_t cause)
+{
+ m_cause = cause;
+}
+
+GtpcHeader::Fteid_t
+GtpcCreateSessionResponseMessage::GetSenderCpFteid () const
+{
+ return m_senderCpFteid;
+}
+
+void
+GtpcCreateSessionResponseMessage::SetSenderCpFteid (GtpcHeader::Fteid_t fteid)
+{
+ m_senderCpFteid = fteid;
+}
+
+std::list
+GtpcCreateSessionResponseMessage::GetBearerContextsCreated () const
+{
+ return m_bearerContextsCreated;
+}
+
+void
+GtpcCreateSessionResponseMessage::SetBearerContextsCreated (std::list bearerContexts)
+{
+ m_bearerContextsCreated = bearerContexts;
+}
+
+/////////////////////////////////////////////////////////////////////
+
+TypeId
+GtpcModifyBearerRequestMessage::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::GtpcModifyBearerRequestMessage")
+ .SetParent ()
+ .SetGroupName ("Lte")
+ .AddConstructor ();
+ return tid;
+}
+
+GtpcModifyBearerRequestMessage::GtpcModifyBearerRequestMessage ()
+{
+ SetMessageType (GtpcHeader::ModifyBearerRequest);
+ SetSequenceNumber (0);
+ m_imsi = 0;
+ m_uliEcgi = 0;
+}
+
+GtpcModifyBearerRequestMessage::~GtpcModifyBearerRequestMessage ()
+{
+}
+
+TypeId
+GtpcModifyBearerRequestMessage::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+
+uint32_t
+GtpcModifyBearerRequestMessage::GetMessageSize (void) const
+{
+ uint32_t serializedSize = serializedSizeImsi + serializedSizeUliEcgi
+ + m_bearerContextsToBeModified.size ()
+ * (serializedSizeBearerContextHeader
+ + serializedSizeEbi + serializedSizeFteid);
+ return serializedSize;
+}
+
+uint32_t
+GtpcModifyBearerRequestMessage::GetSerializedSize (void) const
+{
+ return GtpcHeader::GetSerializedSize () + GetMessageSize ();
+}
+
+void
+GtpcModifyBearerRequestMessage::Serialize (Buffer::Iterator start) const
+{
+ Buffer::Iterator i = start;
+
+ GtpcHeader::PreSerialize (i);
+ SerializeImsi (i, m_imsi);
+ SerializeUliEcgi (i, m_uliEcgi);
+
+ for (auto &bc : m_bearerContextsToBeModified)
+ {
+ SerializeBearerContextHeader (i, serializedSizeEbi + serializedSizeFteid);
+
+ SerializeEbi (i, bc.epsBearerId);
+ SerializeFteid (i, bc.fteid);
+ }
+}
+
+uint32_t
+GtpcModifyBearerRequestMessage::Deserialize (Buffer::Iterator start)
+{
+ Buffer::Iterator i = start;
+ GtpcHeader::PreDeserialize (i);
+
+ DeserializeImsi (i, m_imsi);
+ DeserializeUliEcgi (i, m_uliEcgi);
+
+ while (i.GetRemainingSize () > 0)
+ {
+ BearerContextToBeModified bearerContext;
+ uint16_t length;
+
+ DeserializeBearerContextHeader (i, length);
+
+ DeserializeEbi (i, bearerContext.epsBearerId);
+ DeserializeFteid (i, bearerContext.fteid);
+
+ m_bearerContextsToBeModified.push_back (bearerContext);
+ }
+
+ return GetSerializedSize ();
+}
+
+void
+GtpcModifyBearerRequestMessage::Print (std::ostream &os) const
+{
+ os << " imsi " << m_imsi << " uliEcgi " << m_uliEcgi;
+}
+
+uint8_t
+GtpcModifyBearerRequestMessage::GetImsi () const
+{
+ return m_imsi;
+}
+
+void
+GtpcModifyBearerRequestMessage::SetImsi (uint8_t imsi)
+{
+ m_imsi = imsi;
+}
+
+uint32_t
+GtpcModifyBearerRequestMessage::GetUliEcgi () const
+{
+ return m_uliEcgi;
+}
+
+void
+GtpcModifyBearerRequestMessage::SetUliEcgi (uint32_t uliEcgi)
+{
+ m_uliEcgi = uliEcgi;
+}
+
+std::list
+GtpcModifyBearerRequestMessage::GetBearerContextsToBeModified () const
+{
+ return m_bearerContextsToBeModified;
+}
+
+void
+GtpcModifyBearerRequestMessage::SetBearerContextsToBeModified (std::list bearerContexts)
+{
+ m_bearerContextsToBeModified = bearerContexts;
+}
+
+/////////////////////////////////////////////////////////////////////
+
+TypeId
+GtpcModifyBearerResponseMessage::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::GtpcModifyBearerResponseMessage")
+ .SetParent ()
+ .SetGroupName ("Lte")
+ .AddConstructor ();
+ return tid;
+}
+
+GtpcModifyBearerResponseMessage::GtpcModifyBearerResponseMessage ()
+{
+ SetMessageType (GtpcHeader::ModifyBearerResponse);
+ SetSequenceNumber (0);
+ m_cause = Cause_t::RESERVED;
+}
+
+GtpcModifyBearerResponseMessage::~GtpcModifyBearerResponseMessage ()
+{
+}
+
+TypeId
+GtpcModifyBearerResponseMessage::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+
+uint32_t
+GtpcModifyBearerResponseMessage::GetMessageSize (void) const
+{
+ return serializedSizeCause;
+}
+
+uint32_t
+GtpcModifyBearerResponseMessage::GetSerializedSize (void) const
+{
+ return GtpcHeader::GetSerializedSize () + GetMessageSize ();
+}
+
+void
+GtpcModifyBearerResponseMessage::Serialize (Buffer::Iterator start) const
+{
+ Buffer::Iterator i = start;
+
+ GtpcHeader::PreSerialize (i);
+ SerializeCause (i, m_cause);
+}
+
+uint32_t
+GtpcModifyBearerResponseMessage::Deserialize (Buffer::Iterator start)
+{
+ Buffer::Iterator i = start;
+ GtpcHeader::PreDeserialize (i);
+
+ DeserializeCause (i, m_cause);
+
+ return GetSerializedSize ();
+}
+
+void
+GtpcModifyBearerResponseMessage::Print (std::ostream &os) const
+{
+ os << " cause " << (uint16_t)m_cause;
+}
+
+GtpcModifyBearerResponseMessage::Cause_t
+GtpcModifyBearerResponseMessage::GetCause () const
+{
+ return m_cause;
+}
+
+void
+GtpcModifyBearerResponseMessage::SetCause (GtpcModifyBearerResponseMessage::Cause_t cause)
+{
+ m_cause = cause;
+}
+
+/////////////////////////////////////////////////////////////////////
+
+TypeId
+GtpcDeleteBearerCommandMessage::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::GtpcDeleteBearerCommandMessage")
+ .SetParent ()
+ .SetGroupName ("Lte")
+ .AddConstructor ();
+ return tid;
+}
+
+GtpcDeleteBearerCommandMessage::GtpcDeleteBearerCommandMessage ()
+{
+ SetMessageType (GtpcHeader::DeleteBearerCommand);
+ SetSequenceNumber (0);
+}
+
+GtpcDeleteBearerCommandMessage::~GtpcDeleteBearerCommandMessage ()
+{
+}
+
+TypeId
+GtpcDeleteBearerCommandMessage::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+
+uint32_t
+GtpcDeleteBearerCommandMessage::GetMessageSize (void) const
+{
+ uint32_t serializedSize = m_bearerContexts.size ()
+ * (serializedSizeBearerContextHeader + serializedSizeEbi);
+ return serializedSize;
+}
+
+uint32_t
+GtpcDeleteBearerCommandMessage::GetSerializedSize (void) const
+{
+ return GtpcHeader::GetSerializedSize () + GetMessageSize ();
+}
+
+void
+GtpcDeleteBearerCommandMessage::Serialize (Buffer::Iterator start) const
+{
+ Buffer::Iterator i = start;
+
+ GtpcHeader::PreSerialize (i);
+ for (auto &bearerContext : m_bearerContexts)
+ {
+ SerializeBearerContextHeader (i, serializedSizeEbi);
+
+ SerializeEbi (i, bearerContext.m_epsBearerId);
+ }
+}
+
+uint32_t
+GtpcDeleteBearerCommandMessage::Deserialize (Buffer::Iterator start)
+{
+ Buffer::Iterator i = start;
+ GtpcHeader::PreDeserialize (i);
+
+ while (i.GetRemainingSize () > 0)
+ {
+ uint16_t length;
+ DeserializeBearerContextHeader (i, length);
+
+ BearerContext bearerContext;
+ DeserializeEbi (i, bearerContext.m_epsBearerId);
+ m_bearerContexts.push_back (bearerContext);
+ }
+
+ return GetSerializedSize ();
+}
+
+void
+GtpcDeleteBearerCommandMessage::Print (std::ostream &os) const
+{
+ os << " bearerContexts [";
+ for (auto &bearerContext : m_bearerContexts)
+ {
+ os << (uint16_t)bearerContext.m_epsBearerId << " ";
+ }
+ os << "]";
+}
+
+std::list
+GtpcDeleteBearerCommandMessage::GetBearerContexts () const
+{
+ return m_bearerContexts;
+}
+
+void
+GtpcDeleteBearerCommandMessage::SetBearerContexts (std::list bearerContexts)
+{
+ m_bearerContexts = bearerContexts;
+}
+
+/////////////////////////////////////////////////////////////////////
+
+TypeId
+GtpcDeleteBearerRequestMessage::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::GtpcDeleteBearerRequestMessage")
+ .SetParent ()
+ .SetGroupName ("Lte")
+ .AddConstructor ();
+ return tid;
+}
+
+GtpcDeleteBearerRequestMessage::GtpcDeleteBearerRequestMessage ()
+{
+ SetMessageType (GtpcHeader::DeleteBearerRequest);
+ SetSequenceNumber (0);
+}
+
+GtpcDeleteBearerRequestMessage::~GtpcDeleteBearerRequestMessage ()
+{
+}
+
+TypeId
+GtpcDeleteBearerRequestMessage::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+
+uint32_t
+GtpcDeleteBearerRequestMessage::GetMessageSize (void) const
+{
+ uint32_t serializedSize = m_epsBearerIds.size () * serializedSizeEbi;
+ return serializedSize;
+}
+
+uint32_t
+GtpcDeleteBearerRequestMessage::GetSerializedSize (void) const
+{
+ return GtpcHeader::GetSerializedSize () + GetMessageSize ();
+}
+
+void
+GtpcDeleteBearerRequestMessage::Serialize (Buffer::Iterator start) const
+{
+ Buffer::Iterator i = start;
+
+ GtpcHeader::PreSerialize (i);
+ for (auto &epsBearerId : m_epsBearerIds)
+ {
+ SerializeEbi (i, epsBearerId);
+ }
+}
+
+uint32_t
+GtpcDeleteBearerRequestMessage::Deserialize (Buffer::Iterator start)
+{
+ Buffer::Iterator i = start;
+ GtpcHeader::PreDeserialize (i);
+
+ while (i.GetRemainingSize () > 0)
+ {
+ uint8_t epsBearerId;
+ DeserializeEbi (i, epsBearerId);
+ m_epsBearerIds.push_back (epsBearerId);
+ }
+
+ return GetSerializedSize ();
+}
+
+void
+GtpcDeleteBearerRequestMessage::Print (std::ostream &os) const
+{
+ os << " epsBearerIds [";
+ for (auto &epsBearerId : m_epsBearerIds)
+ {
+ os << (uint16_t)epsBearerId << " ";
+ }
+ os << "]";
+}
+
+std::list
+GtpcDeleteBearerRequestMessage::GetEpsBearerIds () const
+{
+ return m_epsBearerIds;
+}
+
+void
+GtpcDeleteBearerRequestMessage::SetEpsBearerIds (std::list epsBearerId)
+{
+ m_epsBearerIds = epsBearerId;
+}
+
+/////////////////////////////////////////////////////////////////////
+
+TypeId
+GtpcDeleteBearerResponseMessage::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::GtpcDeleteBearerResponseMessage")
+ .SetParent ()
+ .SetGroupName ("Lte")
+ .AddConstructor ();
+ return tid;
+}
+
+GtpcDeleteBearerResponseMessage::GtpcDeleteBearerResponseMessage ()
+{
+ SetMessageType (GtpcHeader::DeleteBearerResponse);
+ SetSequenceNumber (0);
+}
+
+GtpcDeleteBearerResponseMessage::~GtpcDeleteBearerResponseMessage ()
+{
+}
+
+TypeId
+GtpcDeleteBearerResponseMessage::GetInstanceTypeId (void) const
+{
+ return GetTypeId ();
+}
+
+uint32_t
+GtpcDeleteBearerResponseMessage::GetMessageSize (void) const
+{
+ uint32_t serializedSize = serializedSizeCause + m_epsBearerIds.size () * serializedSizeEbi;
+ return serializedSize;
+}
+
+uint32_t
+GtpcDeleteBearerResponseMessage::GetSerializedSize (void) const
+{
+ return GtpcHeader::GetSerializedSize () + GetMessageSize ();
+}
+
+void
+GtpcDeleteBearerResponseMessage::Serialize (Buffer::Iterator start) const
+{
+ Buffer::Iterator i = start;
+
+ GtpcHeader::PreSerialize (i);
+ SerializeCause (i, m_cause);
+
+ for (auto &epsBearerId : m_epsBearerIds)
+ {
+ SerializeEbi (i, epsBearerId);
+ }
+}
+
+uint32_t
+GtpcDeleteBearerResponseMessage::Deserialize (Buffer::Iterator start)
+{
+ Buffer::Iterator i = start;
+ GtpcHeader::PreDeserialize (i);
+
+ DeserializeCause (i, m_cause);
+
+ while (i.GetRemainingSize () > 0)
+ {
+ uint8_t epsBearerId;
+ DeserializeEbi (i, epsBearerId);
+ m_epsBearerIds.push_back (epsBearerId);
+ }
+
+ return GetSerializedSize ();
+}
+
+void
+GtpcDeleteBearerResponseMessage::Print (std::ostream &os) const
+{
+ os << " cause " << (uint16_t)m_cause << " epsBearerIds [";
+ for (auto &epsBearerId : m_epsBearerIds)
+ {
+ os << (uint16_t)epsBearerId << " ";
+ }
+ os << "]";
+}
+
+GtpcDeleteBearerResponseMessage::Cause_t
+GtpcDeleteBearerResponseMessage::GetCause () const
+{
+ return m_cause;
+}
+
+void
+GtpcDeleteBearerResponseMessage::SetCause (GtpcDeleteBearerResponseMessage::Cause_t cause)
+{
+ m_cause = cause;
+}
+
+std::list
+GtpcDeleteBearerResponseMessage::GetEpsBearerIds () const
+{
+ return m_epsBearerIds;
+}
+
+void
+GtpcDeleteBearerResponseMessage::SetEpsBearerIds (std::list epsBearerId)
+{
+ m_epsBearerIds = epsBearerId;
+}
+
+} // namespace ns3
diff --git a/src/lte/model/epc-gtpc-header.h b/src/lte/model/epc-gtpc-header.h
new file mode 100644
index 000000000..e1cacf5cb
--- /dev/null
+++ b/src/lte/model/epc-gtpc-header.h
@@ -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
+ */
+
+#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 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 packetFilters) const;
+ uint32_t DeserializeBearerTft (Buffer::Iterator &i, Ptr 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 tft; ///< traffic flow template
+ EpsBearer bearerLevelQos; ///< bearer QOS level
+ };
+
+ std::list GetBearerContextsToBeCreated () const;
+ void SetBearerContextsToBeCreated (std::list bearerContexts);
+
+private:
+ uint64_t m_imsi;
+ uint32_t m_uliEcgi;
+ GtpcHeader::Fteid_t m_senderCpFteid;
+
+ std::list 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 tft; ///< Bearer traffic flow template
+ GtpcHeader::Fteid_t fteid; ///< FTEID
+ EpsBearer bearerLevelQos; ///< Bearer QOS level
+ };
+
+ std::list GetBearerContextsCreated () const;
+ void SetBearerContextsCreated (std::list bearerContexts);
+
+private:
+ Cause_t m_cause;
+ GtpcHeader::Fteid_t m_senderCpFteid;
+
+ std::list 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 GetBearerContextsToBeModified () const;
+ void SetBearerContextsToBeModified (std::list bearerContexts);
+
+private:
+ uint64_t m_imsi;
+ uint32_t m_uliEcgi;
+
+ std::list 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 GetBearerContexts () const;
+ void SetBearerContexts (std::list bearerContexts);
+
+private:
+ std::list 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 GetEpsBearerIds () const;
+ void SetEpsBearerIds (std::list epsBearerIds);
+
+private:
+ std::list 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 GetEpsBearerIds () const;
+ void SetEpsBearerIds (std::list epsBearerIds);
+
+private:
+ Cause_t m_cause;
+ std::list m_epsBearerIds;
+};
+
+} // namespace ns3
+
+#endif // EPC_GTPC_HEADER_H
diff --git a/src/lte/model/epc-mme-application.cc b/src/lte/model/epc-mme-application.cc
new file mode 100644
index 000000000..d205d3e62
--- /dev/null
+++ b/src/lte/model/epc-mme-application.cc
@@ -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
+ */
+
+#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 (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