A Discrete-Event Network Simulator
API
epc-mme-application.cc
Go to the documentation of this file.
1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2017-2018 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Manuel Requena <manuel.requena@cttc.es>
19  */
20 
21 #include "ns3/log.h"
22 #include "ns3/epc-gtpc-header.h"
23 #include "ns3/epc-mme-application.h"
24 
25 namespace ns3 {
26 
27 NS_LOG_COMPONENT_DEFINE ("EpcMmeApplication");
28 
29 NS_OBJECT_ENSURE_REGISTERED (EpcMmeApplication);
30 
32  : m_gtpcUdpPort (2123) //fixed by the standard
33 {
34  NS_LOG_FUNCTION (this);
36 }
38 {
39  NS_LOG_FUNCTION (this);
40 }
41 
42 void
44 {
45  NS_LOG_FUNCTION (this);
46  delete m_s1apSapMme;
47 }
48 
49 TypeId
51 {
52  static TypeId tid = TypeId ("ns3::EpcMmeApplication")
53  .SetParent<Object> ()
54  .SetGroupName ("Lte")
55  .AddConstructor<EpcMmeApplication> ();
56  return tid;
57 }
58 
61 {
62  return m_s1apSapMme;
63 }
64 
65 void
66 EpcMmeApplication::AddSgw (Ipv4Address sgwS11Addr, Ipv4Address mmeS11Addr, Ptr<Socket> mmeS11Socket)
67 {
68  NS_LOG_FUNCTION (this << sgwS11Addr << mmeS11Addr << mmeS11Socket);
69  m_sgwS11Addr = sgwS11Addr;
70  m_mmeS11Addr = mmeS11Addr;
71  m_s11Socket = mmeS11Socket;
73 }
74 
75 void
76 EpcMmeApplication::AddEnb (uint16_t gci, Ipv4Address enbS1uAddr, EpcS1apSapEnb* enbS1apSap)
77 {
78  NS_LOG_FUNCTION (this << gci << enbS1uAddr << enbS1apSap);
79  Ptr<EnbInfo> enbInfo = Create<EnbInfo> ();
80  enbInfo->gci = gci;
81  enbInfo->s1uAddr = enbS1uAddr;
82  enbInfo->s1apSapEnb = enbS1apSap;
83  m_enbInfoMap[gci] = enbInfo;
84 }
85 
86 void
87 EpcMmeApplication::AddUe (uint64_t imsi)
88 {
89  NS_LOG_FUNCTION (this << imsi);
90  Ptr<UeInfo> ueInfo = Create<UeInfo> ();
91  ueInfo->imsi = imsi;
92  ueInfo->mmeUeS1Id = imsi;
93  ueInfo->bearerCounter = 0;
94  m_ueInfoMap[imsi] = ueInfo;
95 }
96 
97 uint8_t
99 {
100  NS_LOG_FUNCTION (this << imsi);
101  std::map<uint64_t, Ptr<UeInfo> >::iterator it = m_ueInfoMap.find (imsi);
102  NS_ASSERT_MSG (it != m_ueInfoMap.end (), "could not find any UE with IMSI " << imsi);
103  NS_ASSERT_MSG (it->second->bearerCounter < 11, "too many bearers already! " << it->second->bearerCounter);
104  BearerInfo bearerInfo;
105  bearerInfo.bearerId = ++(it->second->bearerCounter);
106  bearerInfo.tft = tft;
107  bearerInfo.bearer = bearer;
108  it->second->bearersToBeActivated.push_back (bearerInfo);
109  return bearerInfo.bearerId;
110 }
111 
112 
113 // S1-AP SAP MME forwarded methods
114 
115 void
116 EpcMmeApplication::DoInitialUeMessage (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, uint64_t imsi, uint16_t gci)
117 {
118  NS_LOG_FUNCTION (this << mmeUeS1Id << enbUeS1Id << imsi << gci);
119  std::map<uint64_t, Ptr<UeInfo> >::iterator it = m_ueInfoMap.find (imsi);
120  NS_ASSERT_MSG (it != m_ueInfoMap.end (), "could not find any UE with IMSI " << imsi);
121  it->second->cellId = gci;
122 
124  msg.SetImsi (imsi);
125  msg.SetUliEcgi (gci);
126 
127  GtpcHeader::Fteid_t mmeS11Fteid;
129  mmeS11Fteid.teid = imsi;
130  mmeS11Fteid.addr = m_mmeS11Addr;
131  msg.SetSenderCpFteid (mmeS11Fteid); // S11 MME GTP-C F-TEID
132 
133  std::list<GtpcCreateSessionRequestMessage::BearerContextToBeCreated> bearerContexts;
134  for (std::list<BearerInfo>::iterator bit = it->second->bearersToBeActivated.begin ();
135  bit != it->second->bearersToBeActivated.end ();
136  ++bit)
137  {
139  bearerContext.epsBearerId = bit->bearerId;
140  bearerContext.tft = bit->tft;
141  bearerContext.bearerLevelQos = bit->bearer;
142  bearerContexts.push_back (bearerContext);
143  }
144  NS_LOG_DEBUG ("BearerContextToBeCreated size = " << bearerContexts.size ());
145  msg.SetBearerContextsToBeCreated (bearerContexts);
146 
147  msg.SetTeid (0);
148  msg.ComputeMessageLength ();
149 
150  Ptr<Packet> packet = Create <Packet> ();
151  packet->AddHeader (msg);
152  NS_LOG_DEBUG ("Send CreateSessionRequest to SGW " << m_sgwS11Addr);
154 }
155 
156 void
157 EpcMmeApplication::DoInitialContextSetupResponse (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<EpcS1apSapMme::ErabSetupItem> erabSetupList)
158 {
159  NS_LOG_FUNCTION (this << mmeUeS1Id << enbUeS1Id);
160  NS_FATAL_ERROR ("unimplemented");
161 }
162 
163 void
164 EpcMmeApplication::DoPathSwitchRequest (uint64_t enbUeS1Id, uint64_t mmeUeS1Id, uint16_t gci, std::list<EpcS1apSapMme::ErabSwitchedInDownlinkItem> erabToBeSwitchedInDownlinkList)
165 {
166  NS_LOG_FUNCTION (this << mmeUeS1Id << enbUeS1Id << gci);
167  uint64_t imsi = mmeUeS1Id;
168  std::map<uint64_t, Ptr<UeInfo> >::iterator it = m_ueInfoMap.find (imsi);
169  NS_ASSERT_MSG (it != m_ueInfoMap.end (), "could not find any UE with IMSI " << imsi);
170  NS_LOG_INFO ("IMSI " << imsi << " old eNB: " << it->second->cellId << ", new eNB: " << gci);
171  it->second->cellId = gci;
172  it->second->enbUeS1Id = enbUeS1Id;
173 
175  msg.SetImsi (imsi);
176  msg.SetUliEcgi (gci);
177 
178  std::list<GtpcModifyBearerRequestMessage::BearerContextToBeModified> bearerContexts;
179  for (auto &erab : erabToBeSwitchedInDownlinkList)
180  {
181  NS_LOG_DEBUG ("erabId " << erab.erabId <<
182  " eNB " << erab.enbTransportLayerAddress <<
183  " TEID " << erab.enbTeid);
184 
186  bearerContext.epsBearerId = erab.erabId;
188  bearerContext.fteid.addr = erab.enbTransportLayerAddress;
189  bearerContext.fteid.teid = erab.enbTeid;
190  bearerContexts.push_back (bearerContext);
191  }
192  msg.SetBearerContextsToBeModified (bearerContexts);
193  msg.SetTeid (imsi);
194  msg.ComputeMessageLength ();
195 
196  Ptr<Packet> packet = Create <Packet> ();
197  packet->AddHeader (msg);
198  NS_LOG_DEBUG ("Send ModifyBearerRequest to SGW " << m_sgwS11Addr);
200 }
201 
202 void
203 EpcMmeApplication::DoErabReleaseIndication (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<EpcS1apSapMme::ErabToBeReleasedIndication> erabToBeReleaseIndication)
204 {
205  NS_LOG_FUNCTION (this << mmeUeS1Id << enbUeS1Id);
206  uint64_t imsi = mmeUeS1Id;
207  std::map<uint64_t, Ptr<UeInfo> >::iterator it = m_ueInfoMap.find (imsi);
208  NS_ASSERT_MSG (it != m_ueInfoMap.end (), "could not find any UE with IMSI " << imsi);
209 
211  std::list<GtpcDeleteBearerCommandMessage::BearerContext> bearerContexts;
212  for (auto &erab : erabToBeReleaseIndication)
213  {
214  NS_LOG_DEBUG ("erabId " << (uint16_t)erab.erabId);
216  bearerContext.m_epsBearerId = erab.erabId;
217  bearerContexts.push_back (bearerContext);
218  }
219  msg.SetBearerContexts (bearerContexts);
220  msg.SetTeid (imsi);
221  msg.ComputeMessageLength ();
222 
223  Ptr<Packet> packet = Create <Packet> ();
224  packet->AddHeader (msg);
225  NS_LOG_DEBUG ("Send DeleteBearerCommand to SGW " << m_sgwS11Addr);
227 }
228 
229 void
230 EpcMmeApplication::RemoveBearer (Ptr<UeInfo> ueInfo, uint8_t epsBearerId)
231 {
232  NS_LOG_FUNCTION (this << epsBearerId);
233  std::list<BearerInfo>::iterator bit = ueInfo->bearersToBeActivated.begin ();
234  while (bit != ueInfo->bearersToBeActivated.end ())
235  {
236  if (bit->bearerId == epsBearerId)
237  {
238  ueInfo->bearersToBeActivated.erase (bit);
239  ueInfo->bearerCounter = ueInfo->bearerCounter - 1;
240  break;
241  }
242  ++bit;
243  }
244 }
245 
246 
247 void
249 {
250  NS_LOG_FUNCTION (this << socket);
251  NS_ASSERT (socket == m_s11Socket);
252  Ptr<Packet> packet = socket->Recv ();
253  GtpcHeader header;
254  packet->PeekHeader (header);
255  uint16_t msgType = header.GetMessageType ();
256 
257  switch (msgType)
258  {
260  DoRecvCreateSessionResponse (header, packet);
261  break;
262 
264  DoRecvModifyBearerResponse (header, packet);
265  break;
266 
268  DoRecvDeleteBearerRequest (header, packet);
269  break;
270 
271  default:
272  NS_FATAL_ERROR ("GTP-C message not supported");
273  break;
274  }
275 }
276 
277 void
279 {
280  NS_LOG_FUNCTION (this << header);
281  uint64_t imsi = header.GetTeid ();
282  NS_LOG_DEBUG ("TEID/IMSI " << imsi);
283  std::map<uint64_t, Ptr<UeInfo> >::iterator it = m_ueInfoMap.find (imsi);
284  NS_ASSERT_MSG (it != m_ueInfoMap.end (), "could not find any UE with IMSI " << imsi);
285  uint16_t cellId = it->second->cellId;
286  uint16_t enbUeS1Id = it->second->enbUeS1Id;
287  uint64_t mmeUeS1Id = it->second->mmeUeS1Id;
288  NS_LOG_DEBUG ("cellId " << cellId << " mmeUeS1Id " << mmeUeS1Id << " enbUeS1Id " << enbUeS1Id);
289  std::map<uint16_t, Ptr<EnbInfo> >::iterator jt = m_enbInfoMap.find (cellId);
290  NS_ASSERT_MSG (jt != m_enbInfoMap.end (), "could not find any eNB with CellId " << cellId);
291 
293  packet->RemoveHeader (msg);
294 
295  std::list<EpcS1apSapEnb::ErabToBeSetupItem> erabToBeSetupList;
296  std::list<GtpcCreateSessionResponseMessage::BearerContextCreated> bearerContexts =
297  msg.GetBearerContextsCreated ();
298  NS_LOG_DEBUG ("BearerContextsCreated size = " << bearerContexts.size ());
299  for (auto &bearerContext : bearerContexts)
300  {
302  erab.erabId = bearerContext.epsBearerId;
303  erab.erabLevelQosParameters = bearerContext.bearerLevelQos;
304  erab.transportLayerAddress = bearerContext.fteid.addr; // SGW S1U address
305  erab.sgwTeid = bearerContext.fteid.teid;
306  NS_LOG_DEBUG ("SGW " << erab.transportLayerAddress << " TEID " << erab.sgwTeid);
307  erabToBeSetupList.push_back (erab);
308  }
309 
310  NS_LOG_DEBUG ("Send InitialContextSetupRequest to eNB " << jt->second->s1apSapEnb);
311  jt->second->s1apSapEnb->InitialContextSetupRequest (mmeUeS1Id, enbUeS1Id, erabToBeSetupList);
312 }
313 
314 void
316 {
317  NS_LOG_FUNCTION (this << header);
319  packet->RemoveHeader (msg);
321 
322  uint64_t imsi = header.GetTeid ();
323  NS_LOG_DEBUG ("TEID/IMSI " << imsi);
324  std::map<uint64_t, Ptr<UeInfo> >::iterator it = m_ueInfoMap.find (imsi);
325  NS_ASSERT_MSG (it != m_ueInfoMap.end (), "could not find any UE with IMSI " << imsi);
326  uint16_t cellId = it->second->cellId;
327  uint16_t enbUeS1Id = it->second->enbUeS1Id;
328  uint64_t mmeUeS1Id = it->second->mmeUeS1Id;
329  NS_LOG_DEBUG ("cellId " << cellId << " mmeUeS1Id " << mmeUeS1Id << " enbUeS1Id " << enbUeS1Id);
330  std::list<EpcS1apSapEnb::ErabSwitchedInUplinkItem> erabToBeSwitchedInUplinkList; // unused for now
331  std::map<uint16_t, Ptr<EnbInfo> >::iterator jt = m_enbInfoMap.find (cellId);
332  NS_ASSERT_MSG (jt != m_enbInfoMap.end (), "could not find any eNB with CellId " << cellId);
333 
334  NS_LOG_DEBUG ("Send PathSwitchRequestAcknowledge to eNB " << jt->second->s1apSapEnb);
335  jt->second->s1apSapEnb->PathSwitchRequestAcknowledge (enbUeS1Id, mmeUeS1Id, cellId, erabToBeSwitchedInUplinkList);
336 }
337 
338 void
340 {
341  NS_LOG_FUNCTION (this << header);
342  uint64_t imsi = header.GetTeid ();
343  NS_LOG_DEBUG ("TEID/IMSI " << imsi);
344  std::map<uint64_t, Ptr<UeInfo> >::iterator it = m_ueInfoMap.find (imsi);
345  NS_ASSERT_MSG (it != m_ueInfoMap.end (), "could not find any UE with IMSI " << imsi);
346 
348  packet->RemoveHeader (msg);
349 
351 
352  std::list<uint8_t> epsBearerIds;
353  for (auto &ebid : msg.GetEpsBearerIds ())
354  {
355  epsBearerIds.push_back (ebid);
356  /*
357  * This condition is added to not remove bearer info at MME
358  * when UE gets disconnected since the bearers are only added
359  * at beginning of simulation at MME and if it is removed the
360  * bearers cannot be activated again unless scheduled for
361  * addition of the bearer during simulation
362  *
363  */
364  if (it->second->cellId == 0)
365  {
366  RemoveBearer (it->second, ebid); //schedules function to erase, context of de-activated bearer
367  }
368  }
369  msgOut.SetEpsBearerIds (epsBearerIds);
370  msgOut.SetTeid (imsi);
371  msgOut.ComputeMessageLength ();
372 
373  Ptr<Packet> packetOut = Create <Packet> ();
374  packetOut->AddHeader (msgOut);
375  NS_LOG_DEBUG ("Send DeleteBearerResponse to SGW " << m_sgwS11Addr);
377 }
378 
379 } // namespace ns3
uint32_t RemoveHeader(Header &header)
Deserialize and remove the header from the internal buffer.
Definition: packet.cc:280
void RemoveBearer(Ptr< UeInfo > ueInfo, uint8_t epsBearerId)
This Function erases all contexts of bearer from MME side.
Hold info on an EPS bearer to be activated.
an Inet address class
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
EpcS1apSapEnb * s1apSapEnb
EpcS1apSapEnb.
MME side of the S1-AP Service Access Point (SAP), provides the MME methods to be called when an S1-AP...
Definition: epc-s1ap-sap.h:53
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
Ipv4Address m_mmeS11Addr
IPv4 address of the MME S11 interface.
NS_ASSERT_MSG(false, "Ipv4AddressGenerator::MaskToIndex(): Impossible")
void DoRecvDeleteBearerRequest(GtpcHeader &header, Ptr< Packet > packet)
Process GTP-C Delete Bearer Request message.
void SetBearerContextsToBeCreated(std::list< BearerContextToBeCreated > bearerContexts)
std::map< uint64_t, Ptr< UeInfo > > m_ueInfoMap
UeInfo stored by IMSI.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:204
void RecvFromS11Socket(Ptr< Socket > socket)
Reads the S11 messages from a socket.
void DoErabReleaseIndication(uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list< EpcS1apSapMme::ErabToBeReleasedIndication > erabToBeReleaseIndication)
Process ERAB Release Indication received from an eNB.
uint16_t m_gtpcUdpPort
UDP port for GTP-C protocol. Fixed by the standard to port 2123.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:280
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:162
void ComputeMessageLength(void)
Ipv4Address s1uAddr
IP address of the S1-U interface.
void AddEnb(uint16_t ecgi, Ipv4Address enbS1UAddr, EpcS1apSapEnb *enbS1apSap)
Add a new eNB to the MME.
EpsBearer bearer
bearer QOS characteristics
EpcMmeApplication()
Constructor.
void DoInitialUeMessage(uint64_t mmeUeS1Id, uint16_t enbUeS1Id, uint64_t imsi, uint16_t ecgi)
Process the S1 Initial UE Message received from an eNB.
void DoInitialContextSetupResponse(uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list< EpcS1apSapMme::ErabSetupItem > erabSetupList)
Process the S1 Initial Context Setup Response received from an eNB.
Ptr< Socket > m_s11Socket
Socket to send/receive messages in the S11 interface.
void SetSenderCpFteid(GtpcHeader::Fteid_t fteid)
eNB side of the S1-AP Service Access Point (SAP), provides the eNB methods to be called when an S1-AP...
Definition: epc-s1ap-sap.h:141
void SetEpsBearerIds(std::list< uint8_t > epsBearerIds)
void DoRecvCreateSessionResponse(GtpcHeader &header, Ptr< Packet > packet)
Process GTP-C Create Session Response message.
EpcS1apSapMme * GetS1apSapMme()
uint32_t PeekHeader(Header &header) const
Deserialize but does not remove the header from the internal buffer.
Definition: packet.cc:290
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1489
void SetRecvCallback(Callback< void, Ptr< Socket > >)
Notify application when new data is available to be read.
Definition: socket.cc:128
uint16_t bearerCounter
bearer counter
std::map< uint16_t, Ptr< EnbInfo > > m_enbInfoMap
EnbInfo stored by EGCI.
static TypeId GetTypeId(void)
Get the type ID.
void AddUe(uint64_t imsi)
Add a new UE to the MME.
InterfaceType_t interfaceType
Ipv4Address transportLayerAddress
transport layer address
Definition: epc-s1ap-sap.h:151
Every class exported by the ns3 library is enclosed in the ns3 namespace.
void DoPathSwitchRequest(uint64_t enbUeS1Id, uint64_t mmeUeS1Id, uint16_t cgi, std::list< EpcS1apSapMme::ErabSwitchedInDownlinkItem > erabToBeSwitchedInDownlinkList)
Process the S1 Path Switch Request received from an eNB.
virtual void DoDispose()
Destructor implementation.
virtual Ptr< Packet > Recv(uint32_t maxSize, uint32_t flags)=0
Read data from the socket.
virtual ~EpcMmeApplication()
Destructor.
void DoRecvModifyBearerResponse(GtpcHeader &header, Ptr< Packet > packet)
Process GTP-C Modify Bearer Response message.
EpsBearer erabLevelQosParameters
Level QOS parameters.
Definition: epc-s1ap-sap.h:150
Ipv4Address m_sgwS11Addr
IPv4 address of the SGW S11 interface.
std::list< BearerInfo > bearersToBeActivated
list of bearers to be activated
uint8_t AddBearer(uint64_t imsi, Ptr< EpcTft > tft, EpsBearer bearer)
Add an EPS bearer to the list of bearers to be activated for this UE.
This class contains the specification of EPS Bearers.
Definition: eps-bearer.h:91
uint8_t GetMessageType() const
Get message type.
EpcS1apSapMme * m_s1apSapMme
EpcS1apSapMme.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:40
This application implements the Mobility Management Entity (MME) according to the 3GPP TS 23...
void SetTeid(uint32_t teid)
Set TEID.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:272
virtual int SendTo(Ptr< Packet > p, uint32_t flags, const Address &toAddress)=0
Send data to a specified peer.
Template for the implementation of the EpcS1apSapMme as a member of an owner class of type C to which...
Definition: epc-s1ap-sap.h:203
A base class which provides memory management and object aggregation.
Definition: object.h:87
Header of the GTPv2-C protocol.
uint32_t GetTeid() const
Get TEID.
ErabToBeSetupItem structure.
Definition: epc-s1ap-sap.h:147
a unique identifier for an interface.
Definition: type-id.h:58
void AddSgw(Ipv4Address sgwS11Addr, Ipv4Address mmeS11Addr, Ptr< Socket > mmeS11Socket)
Add a new SGW to the MME.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:915
void SetBearerContextsToBeModified(std::list< BearerContextToBeModified > bearerContexts)
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
Ptr< EpcTft > tft
traffic flow template