A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
epc-pgw-application.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Manuel Requena <manuel.requena@cttc.es>
7 * (based on epc-sgw-pgw-application.cc)
8 */
9
10#include "epc-pgw-application.h"
11
12#include "epc-gtpu-header.h"
13
14#include "ns3/abort.h"
15#include "ns3/inet-socket-address.h"
16#include "ns3/ipv4-l3-protocol.h"
17#include "ns3/ipv4.h"
18#include "ns3/ipv6-header.h"
19#include "ns3/ipv6-l3-protocol.h"
20#include "ns3/ipv6.h"
21#include "ns3/log.h"
22#include "ns3/mac48-address.h"
23
24namespace ns3
25{
26
27NS_LOG_COMPONENT_DEFINE("EpcPgwApplication");
28
29/////////////////////////
30// UeInfo
31/////////////////////////
32
37
38void
40{
41 NS_LOG_FUNCTION(this << (uint16_t)bearerId << teid << tft);
42 m_teidByBearerIdMap[bearerId] = teid;
43 return m_tftClassifier.Add(tft, teid);
44}
45
46void
48{
49 NS_LOG_FUNCTION(this << (uint16_t)bearerId);
50 auto it = m_teidByBearerIdMap.find(bearerId);
51 if (it != m_teidByBearerIdMap.end())
52 {
53 m_tftClassifier.Delete(it->second); // delete tft
54 m_teidByBearerIdMap.erase(bearerId);
55 }
56}
57
60{
61 NS_LOG_FUNCTION(this << p);
62 // we hardcode DOWNLINK direction since the PGW is expected to
63 // classify only downlink packets (uplink packets will go to the
64 // internet without any classification).
65 return m_tftClassifier.Classify(p, EpcTft::DOWNLINK, protocolNumber);
66}
67
70{
71 return m_sgwAddr;
72}
73
74void
76{
77 m_sgwAddr = sgwAddr;
78}
79
82{
83 return m_ueAddr;
84}
85
86void
88{
89 m_ueAddr = ueAddr;
90}
91
94{
95 return m_ueAddr6;
96}
97
98void
100{
101 m_ueAddr6 = ueAddr;
102}
103
104/////////////////////////
105// EpcPgwApplication
106/////////////////////////
107
108TypeId
110{
111 static TypeId tid =
112 TypeId("ns3::EpcPgwApplication")
113 .SetParent<Object>()
114 .SetGroupName("Lte")
115 .AddTraceSource("RxFromTun",
116 "Receive data packets from internet in Tunnel NetDevice",
118 "ns3::EpcPgwApplication::RxTracedCallback")
119 .AddTraceSource("RxFromS1u",
120 "Receive data packets from S5 Socket",
122 "ns3::EpcPgwApplication::RxTracedCallback");
123 return tid;
124}
125
126void
135
137 Ipv4Address s5Addr,
138 const Ptr<Socket> s5uSocket,
139 const Ptr<Socket> s5cSocket)
140 : m_pgwS5Addr(s5Addr),
141 m_s5uSocket(s5uSocket),
142 m_s5cSocket(s5cSocket),
143 m_tunDevice(tunDevice),
144 m_gtpuUdpPort(2152), // fixed by the standard
145 m_gtpcUdpPort(2123) // fixed by the standard
146{
147 NS_LOG_FUNCTION(this << tunDevice << s5Addr << s5uSocket << s5cSocket);
150}
151
156
157bool
159 const Address& source,
160 const Address& dest,
161 uint16_t protocolNumber)
162{
163 NS_LOG_FUNCTION(this << source << dest << protocolNumber << packet << packet->GetSize());
164 m_rxTunPktTrace(packet->Copy());
165
166 // get IP address of UE
167 if (protocolNumber == Ipv4L3Protocol::PROT_NUMBER)
168 {
169 Ipv4Header ipv4Header;
170 packet->PeekHeader(ipv4Header);
171 Ipv4Address ueAddr = ipv4Header.GetDestination();
172 NS_LOG_LOGIC("packet addressed to UE " << ueAddr);
173
174 // find corresponding UeInfo address
175 auto it = m_ueInfoByAddrMap.find(ueAddr);
176 if (it == m_ueInfoByAddrMap.end())
177 {
178 NS_LOG_WARN("unknown UE address " << ueAddr);
179 }
180 else
181 {
182 Ipv4Address sgwAddr = it->second->GetSgwAddr();
183 uint32_t teid = it->second->Classify(packet, protocolNumber);
184 if (teid == 0)
185 {
186 NS_LOG_WARN("no matching bearer for this packet");
187 }
188 else
189 {
190 SendToS5uSocket(packet, sgwAddr, teid);
191 }
192 }
193 }
194 else if (protocolNumber == Ipv6L3Protocol::PROT_NUMBER)
195 {
196 Ipv6Header ipv6Header;
197 packet->PeekHeader(ipv6Header);
198 Ipv6Address ueAddr = ipv6Header.GetDestination();
199 NS_LOG_LOGIC("packet addressed to UE " << ueAddr);
200
201 // find corresponding UeInfo address
202 auto it = m_ueInfoByAddrMap6.find(ueAddr);
203 if (it == m_ueInfoByAddrMap6.end())
204 {
205 NS_LOG_WARN("unknown UE address " << ueAddr);
206 }
207 else
208 {
209 Ipv4Address sgwAddr = it->second->GetSgwAddr();
210 uint32_t teid = it->second->Classify(packet, protocolNumber);
211 if (teid == 0)
212 {
213 NS_LOG_WARN("no matching bearer for this packet");
214 }
215 else
216 {
217 SendToS5uSocket(packet, sgwAddr, teid);
218 }
219 }
220 }
221 else
222 {
223 NS_ABORT_MSG("Unknown IP type");
224 }
225
226 // there is no reason why we should notify the TUN
227 // VirtualNetDevice that he failed to send the packet: if we receive
228 // any bogus packet, it will just be silently discarded.
229 const bool succeeded = true;
230 return succeeded;
231}
232
233void
235{
236 NS_LOG_FUNCTION(this << socket);
237 NS_ASSERT(socket == m_s5uSocket);
238 Ptr<Packet> packet = socket->Recv();
239 m_rxS5PktTrace(packet->Copy());
240
241 GtpuHeader gtpu;
242 packet->RemoveHeader(gtpu);
243 uint32_t teid = gtpu.GetTeid();
244
245 SendToTunDevice(packet, teid);
246}
247
248void
250{
251 NS_LOG_FUNCTION(this << socket);
252 NS_ASSERT(socket == m_s5cSocket);
253 Ptr<Packet> packet = socket->Recv();
254 GtpcHeader header;
255 packet->PeekHeader(header);
256 uint16_t msgType = header.GetMessageType();
257
258 switch (msgType)
259 {
262 break;
263
266 break;
267
270 break;
271
274 break;
275
276 default:
277 NS_FATAL_ERROR("GTP-C message not supported");
278 break;
279 }
280}
281
282void
284{
285 NS_LOG_FUNCTION(this);
286
288 packet->RemoveHeader(msg);
289 uint64_t imsi = msg.GetImsi();
290 uint16_t cellId = msg.GetUliEcgi();
291 NS_LOG_DEBUG("cellId " << cellId << " IMSI " << imsi);
292
293 auto ueit = m_ueInfoByImsiMap.find(imsi);
294 NS_ASSERT_MSG(ueit != m_ueInfoByImsiMap.end(), "unknown IMSI " << imsi);
295 ueit->second->SetSgwAddr(m_sgwS5Addr);
296
297 GtpcHeader::Fteid_t sgwS5cFteid = msg.GetSenderCpFteid();
298 NS_ASSERT_MSG(sgwS5cFteid.interfaceType == GtpcHeader::S5_SGW_GTPC, "Wrong interface type");
299
301 msgOut.SetTeid(sgwS5cFteid.teid);
303
304 GtpcHeader::Fteid_t pgwS5cFteid;
306 pgwS5cFteid.teid = sgwS5cFteid.teid;
307 pgwS5cFteid.addr = m_pgwS5Addr;
308 msgOut.SetSenderCpFteid(pgwS5cFteid);
309
310 std::list<GtpcCreateSessionRequestMessage::BearerContextToBeCreated> bearerContexts =
312 NS_LOG_DEBUG("BearerContextsToBeCreated size = " << bearerContexts.size());
313
314 std::list<GtpcCreateSessionResponseMessage::BearerContextCreated> bearerContextsCreated;
315 for (auto& bearerContext : bearerContexts)
316 {
317 uint32_t teid = bearerContext.sgwS5uFteid.teid;
318 NS_LOG_DEBUG("bearerId " << (uint16_t)bearerContext.epsBearerId << " SGW "
319 << bearerContext.sgwS5uFteid.addr << " TEID " << teid);
320
321 ueit->second->AddBearer(bearerContext.epsBearerId, teid, bearerContext.tft);
322
325 bearerContextOut.fteid.teid = teid;
326 bearerContextOut.fteid.addr = m_pgwS5Addr;
327 bearerContextOut.epsBearerId = bearerContext.epsBearerId;
328 bearerContextOut.bearerLevelQos = bearerContext.bearerLevelQos;
329 bearerContextOut.tft = bearerContext.tft;
330 bearerContextsCreated.push_back(bearerContextOut);
331 }
332
333 NS_LOG_DEBUG("BearerContextsCreated size = " << bearerContextsCreated.size());
334 msgOut.SetBearerContextsCreated(bearerContextsCreated);
335 msgOut.SetTeid(sgwS5cFteid.teid);
336 msgOut.ComputeMessageLength();
337
338 Ptr<Packet> packetOut = Create<Packet>();
339 packetOut->AddHeader(msgOut);
340 NS_LOG_DEBUG("Send CreateSessionResponse to SGW " << sgwS5cFteid.addr);
341 m_s5cSocket->SendTo(packetOut, 0, InetSocketAddress(sgwS5cFteid.addr, m_gtpcUdpPort));
342}
343
344void
346{
347 NS_LOG_FUNCTION(this);
348
350 packet->RemoveHeader(msg);
351 uint64_t imsi = msg.GetImsi();
352 uint16_t cellId = msg.GetUliEcgi();
353 NS_LOG_DEBUG("cellId " << cellId << " IMSI " << imsi);
354
355 auto ueit = m_ueInfoByImsiMap.find(imsi);
356 NS_ASSERT_MSG(ueit != m_ueInfoByImsiMap.end(), "unknown IMSI " << imsi);
357 ueit->second->SetSgwAddr(m_sgwS5Addr);
358
359 std::list<GtpcModifyBearerRequestMessage::BearerContextToBeModified> bearerContexts =
361 NS_LOG_DEBUG("BearerContextsToBeModified size = " << bearerContexts.size());
362
363 for (auto& bearerContext : bearerContexts)
364 {
365 Ipv4Address sgwAddr = bearerContext.fteid.addr;
366 uint32_t teid = bearerContext.fteid.teid;
367 NS_LOG_DEBUG("bearerId " << (uint16_t)bearerContext.epsBearerId << " SGW " << sgwAddr
368 << " TEID " << teid);
369 }
370
373 msgOut.SetTeid(imsi);
374 msgOut.ComputeMessageLength();
375
376 Ptr<Packet> packetOut = Create<Packet>();
377 packetOut->AddHeader(msgOut);
378 NS_LOG_DEBUG("Send ModifyBearerResponse to SGW " << m_sgwS5Addr);
380}
381
382void
384{
385 NS_LOG_FUNCTION(this);
386
388 packet->RemoveHeader(msg);
389
390 std::list<uint8_t> epsBearerIds;
391 for (auto& bearerContext : msg.GetBearerContexts())
392 {
393 NS_LOG_DEBUG("ebid " << (uint16_t)bearerContext.m_epsBearerId);
394 epsBearerIds.push_back(bearerContext.m_epsBearerId);
395 }
396
398 msgOut.SetEpsBearerIds(epsBearerIds);
399 msgOut.SetTeid(msg.GetTeid());
400 msgOut.ComputeMessageLength();
401
402 Ptr<Packet> packetOut = Create<Packet>();
403 packetOut->AddHeader(msgOut);
404 NS_LOG_DEBUG("Send DeleteBearerRequest to SGW " << m_sgwS5Addr);
406}
407
408void
410{
411 NS_LOG_FUNCTION(this);
412
414 packet->RemoveHeader(msg);
415
416 uint64_t imsi = msg.GetTeid();
417 auto ueit = m_ueInfoByImsiMap.find(imsi);
418 NS_ASSERT_MSG(ueit != m_ueInfoByImsiMap.end(), "unknown IMSI " << imsi);
419
420 for (auto& epsBearerId : msg.GetEpsBearerIds())
421 {
422 // Remove de-activated bearer contexts from PGW side
423 NS_LOG_INFO("PGW removing bearer " << (uint16_t)epsBearerId << " of IMSI " << imsi);
424 ueit->second->RemoveBearer(epsBearerId);
425 }
426}
427
428void
430{
431 NS_LOG_FUNCTION(this << packet << teid);
432 NS_LOG_LOGIC("packet size: " << packet->GetSize() << " bytes");
433
434 uint8_t ipType;
435 packet->CopyData(&ipType, 1);
436 ipType = (ipType >> 4) & 0x0f;
437
438 uint16_t protocol = 0;
439 if (ipType == 0x04)
440 {
441 protocol = 0x0800;
442 }
443 else if (ipType == 0x06)
444 {
445 protocol = 0x86DD;
446 }
447 else
448 {
449 NS_ABORT_MSG("Unknown IP type");
450 }
451
452 m_tunDevice->Receive(packet,
453 protocol,
454 m_tunDevice->GetAddress(),
455 m_tunDevice->GetAddress(),
457}
458
459void
461{
462 NS_LOG_FUNCTION(this << packet << sgwAddr << teid);
463
464 GtpuHeader gtpu;
465 gtpu.SetTeid(teid);
466 // From 3GPP TS 29.281 v10.0.0 Section 5.1
467 // Length of the payload + the non obligatory GTP-U header
468 gtpu.SetLength(packet->GetSize() + gtpu.GetSerializedSize() - 8);
469 packet->AddHeader(gtpu);
470 uint32_t flags = 0;
471 m_s5uSocket->SendTo(packet, flags, InetSocketAddress(sgwAddr, m_gtpuUdpPort));
472}
473
474void
476{
477 NS_LOG_FUNCTION(this << sgwS5Addr);
478 m_sgwS5Addr = sgwS5Addr;
479}
480
481void
483{
484 NS_LOG_FUNCTION(this << imsi);
485 Ptr<UeInfo> ueInfo = Create<UeInfo>();
486 m_ueInfoByImsiMap[imsi] = ueInfo;
487}
488
489void
491{
492 NS_LOG_FUNCTION(this << imsi << ueAddr);
493 auto ueit = m_ueInfoByImsiMap.find(imsi);
494 NS_ASSERT_MSG(ueit != m_ueInfoByImsiMap.end(), "unknown IMSI" << imsi);
495 ueit->second->SetUeAddr(ueAddr);
496 m_ueInfoByAddrMap[ueAddr] = ueit->second;
497}
498
499void
501{
502 NS_LOG_FUNCTION(this << imsi << ueAddr);
503 auto ueit = m_ueInfoByImsiMap.find(imsi);
504 NS_ASSERT_MSG(ueit != m_ueInfoByImsiMap.end(), "unknown IMSI " << imsi);
505 m_ueInfoByAddrMap6[ueAddr] = ueit->second;
506 ueit->second->SetUeAddr6(ueAddr);
507}
508
509} // namespace ns3
a polymophic address class
Definition address.h:90
Ipv6Address GetUeAddr6()
Get the IPv6 address of the UE.
uint32_t Classify(Ptr< Packet > p, uint16_t protocolNumber)
Classify the packet according to TFTs of this UE.
void SetUeAddr(Ipv4Address addr)
Set the IPv4 address of the UE.
Ipv4Address GetSgwAddr()
Get the address of the SGW to which the UE is connected.
void RemoveBearer(uint8_t bearerId)
Delete context of bearer for this UE on PGW side.
Ipv4Address GetUeAddr()
Get the IPv4 address of the UE.
void SetUeAddr6(Ipv6Address addr)
Set the IPv6 address of the UE.
void SetSgwAddr(Ipv4Address addr)
Set the address of the eNB to which the UE is connected.
void AddBearer(uint8_t bearerId, uint32_t teid, Ptr< EpcTft > tft)
Add a bearer for this UE on PGW side.
EpcPgwApplication(const Ptr< VirtualNetDevice > tunDevice, Ipv4Address s5Addr, const Ptr< Socket > s5uSocket, const Ptr< Socket > s5cSocket)
Constructor that binds the tap device to the callback methods.
void SendToS5uSocket(Ptr< Packet > packet, Ipv4Address sgwS5uAddress, uint32_t teid)
Send a data packet to the SGW via the S5-U interface.
void SetUeAddress6(uint64_t imsi, Ipv6Address ueAddr)
set the address of a previously added UE
void SendToTunDevice(Ptr< Packet > packet, uint32_t teid)
Send a data packet to the internet via the SGi interface of the PGW.
void AddSgw(Ipv4Address sgwS5Addr)
Let the PGW be aware of a new SGW.
TracedCallback< Ptr< Packet > > m_rxTunPktTrace
Callback to trace received data packets at Tun NetDevice from internet.
TracedCallback< Ptr< Packet > > m_rxS5PktTrace
Callback to trace received data packets from S5 socket.
std::map< Ipv6Address, Ptr< UeInfo > > m_ueInfoByAddrMap6
UeInfo stored by UE IPv6 address.
void RecvFromS5uSocket(Ptr< Socket > socket)
Method to be assigned to the receiver callback of the S5-U socket.
void DoRecvDeleteBearerResponse(Ptr< Packet > packet)
Process Delete Bearer Response message.
void RecvFromS5cSocket(Ptr< Socket > socket)
Method to be assigned to the receiver callback of the S5-C socket.
void DoRecvDeleteBearerCommand(Ptr< Packet > packet)
Process Delete Bearer Command message.
void AddUe(uint64_t imsi)
Let the PGW be aware of a new UE.
Ptr< Socket > m_s5uSocket
UDP socket to send/receive GTP-U packets to/from the S5 interface.
void DoDispose() override
Destructor implementation.
uint16_t m_gtpuUdpPort
UDP port to be used for GTP-U.
bool RecvFromTunDevice(Ptr< Packet > packet, const Address &source, const Address &dest, uint16_t protocolNumber)
Method to be assigned to the callback of the SGi TUN VirtualNetDevice.
std::map< uint64_t, Ptr< UeInfo > > m_ueInfoByImsiMap
UeInfo stored by IMSI.
Ipv4Address m_pgwS5Addr
PGW address of the S5 interface.
Ipv4Address m_sgwS5Addr
SGW address of the S5 interface.
~EpcPgwApplication() override
Destructor.
Ptr< VirtualNetDevice > m_tunDevice
TUN VirtualNetDevice used for tunneling/detunneling IP packets from/to the internet over GTP-U/UDP/IP...
void DoRecvModifyBearerRequest(Ptr< Packet > packet)
Process Modify Bearer Request message.
void DoRecvCreateSessionRequest(Ptr< Packet > packet)
Process Create Session Request message.
uint16_t m_gtpcUdpPort
UDP port to be used for GTPv2-C.
static TypeId GetTypeId()
Get the type ID.
Ptr< Socket > m_s5cSocket
UDP socket to send/receive GTPv2-C packets to/from the S5 interface.
std::map< Ipv4Address, Ptr< UeInfo > > m_ueInfoByAddrMap
UeInfo stored by UE IPv4 address.
void SetUeAddress(uint64_t imsi, Ipv4Address ueAddr)
Set the address of a previously added UE.
GTP-C Create Session Request Message.
uint64_t GetImsi() const
Get the IMSI.
GtpcHeader::Fteid_t GetSenderCpFteid() const
Get the Sender CpFteid.
uint32_t GetUliEcgi() const
Get the UliEcgi.
std::list< BearerContextToBeCreated > GetBearerContextsToBeCreated() const
Get the Bearer Contexts.
GTP-C Create Session Response Message.
void SetCause(Cause_t cause)
Set the Cause.
void SetBearerContextsCreated(std::list< BearerContextCreated > bearerContexts)
Set the Bearer Contexts.
void SetSenderCpFteid(GtpcHeader::Fteid_t fteid)
Set the Sender CpFteid.
GTP-C Delete Bearer Command Message.
std::list< BearerContext > GetBearerContexts() const
Get the Bearer contexts.
GTP-C Delete Bearer Request Message.
void SetEpsBearerIds(std::list< uint8_t > epsBearerIds)
Set the Bearers IDs.
GTP-C Delete Bearer Response Message.
std::list< uint8_t > GetEpsBearerIds() const
Get 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.
uint64_t GetImsi() const
Get the IMSI.
uint32_t GetUliEcgi() const
Get the UliEcgi.
std::list< BearerContextToBeModified > GetBearerContextsToBeModified() const
Get the Bearer Contexts.
GTP-C Modify Bearer Response Message.
void SetCause(Cause_t cause)
Set the Cause.
Implementation of the GPRS Tunnelling Protocol header according to GTPv1-U Release 10 as per 3Gpp TS ...
void SetTeid(uint32_t teid)
Set TEID function.
uint32_t GetSerializedSize() const override
uint32_t GetTeid() const
Get a tunnel endpoint identificator (TEID)
void SetLength(uint16_t length)
Set the length in octets of the payload.
an Inet address class
Ipv4 addresses are stored in host order in this class.
Packet header for IPv4.
Definition ipv4-header.h:23
Ipv4Address GetDestination() const
static constexpr uint16_t PROT_NUMBER
Protocol number.
Describes an IPv6 address.
Packet header for IPv6.
Definition ipv6-header.h:24
Ipv6Address GetDestination() const
Get the "Destination address" field.
static constexpr uint16_t PROT_NUMBER
The protocol number for IPv6 (0x86DD).
@ PACKET_HOST
Packet addressed to us.
Definition net-device.h:290
A base class which provides memory management and object aggregation.
Definition object.h:78
Smart pointer class similar to boost::intrusive_ptr.
void SetRecvCallback(Callback< void, Ptr< Socket > > receivedData)
Notify application when new data is available to be read.
Definition socket.cc:117
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:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#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:75
Callback< R, Args... > MakeNullCallback()
Definition callback.h:727
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition log.h:250
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
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:684
Ptr< EpcTft > tft
Bearer traffic flow template.
Ipv4Address addr
IPv4 address.
InterfaceType_t interfaceType
Interface type.