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