5G-LENA nr-v3.3-120-gdac69c56
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
nr-epc-gnb-application.cc
1// Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
2//
3// SPDX-License-Identifier: GPL-2.0-only
4//
5// Author: Jaume Nin <jnin@cttc.cat>
6// Nicola Baldo <nbaldo@cttc.cat>
7
8#include "nr-epc-gnb-application.h"
9
10#include "nr-epc-gtpu-header.h"
11#include "nr-eps-bearer-tag.h"
12
13#include "ns3/inet-socket-address.h"
14#include "ns3/ipv4.h"
15#include "ns3/log.h"
16#include "ns3/mac48-address.h"
17#include "ns3/uinteger.h"
18
19namespace ns3
20{
21
22NS_LOG_COMPONENT_DEFINE("NrEpcGnbApplication");
23
24NrEpcGnbApplication::EpsFlowId_t::EpsFlowId_t()
25{
26}
27
28NrEpcGnbApplication::EpsFlowId_t::EpsFlowId_t(const uint16_t a, const uint8_t b)
29 : m_rnti(a),
30 m_bid(b)
31{
32}
33
34bool
36{
37 return ((a.m_rnti == b.m_rnti) && (a.m_bid == b.m_bid));
38}
39
40bool
42{
43 return ((a.m_rnti < b.m_rnti) || ((a.m_rnti == b.m_rnti) && (a.m_bid < b.m_bid)));
44}
45
46TypeId
48{
49 static TypeId tid =
50 TypeId("ns3::NrEpcGnbApplication")
51 .SetParent<Object>()
52 .SetGroupName("Nr")
53 .AddTraceSource("RxFromGnb",
54 "Receive data packets from NR Gnb Net Device",
55 MakeTraceSourceAccessor(&NrEpcGnbApplication::m_rxNrSocketPktTrace),
56 "ns3::NrEpcGnbApplication::RxTracedCallback")
57 .AddTraceSource("RxFromS1u",
58 "Receive data packets from S1-U Net Device",
59 MakeTraceSourceAccessor(&NrEpcGnbApplication::m_rxS1uSocketPktTrace),
60 "ns3::NrEpcGnbApplication::RxTracedCallback");
61 return tid;
62}
63
64void
65NrEpcGnbApplication::DoDispose()
66{
67 NS_LOG_FUNCTION(this);
68 m_nrSocket = nullptr;
69 m_nrSocket6 = nullptr;
70 m_s1uSocket = nullptr;
71 delete m_s1SapProvider;
72 delete m_s1apSapGnb;
73}
74
76 Ptr<Socket> nrSocket6,
77 uint16_t cellId)
78 : m_nrSocket(nrSocket),
79 m_nrSocket6(nrSocket6),
80 m_gtpuUdpPort(2152), // fixed by the standard
81 m_s1SapUser(nullptr),
82 m_s1apSapMme(nullptr),
83 m_cellId(cellId)
84{
85 NS_LOG_FUNCTION(this << nrSocket << nrSocket6 << cellId);
86
87 m_nrSocket->SetRecvCallback(MakeCallback(&NrEpcGnbApplication::RecvFromNrSocket, this));
88 m_nrSocket6->SetRecvCallback(MakeCallback(&NrEpcGnbApplication::RecvFromNrSocket, this));
89 m_s1SapProvider = new NrMemberEpcGnbS1SapProvider<NrEpcGnbApplication>(this);
90 m_s1apSapGnb = new NrMemberEpcS1apSapGnb<NrEpcGnbApplication>(this);
91}
92
93void
95 Ipv4Address gnbAddress,
96 Ipv4Address sgwAddress)
97{
98 NS_LOG_FUNCTION(this << s1uSocket << gnbAddress << sgwAddress);
99
100 m_s1uSocket = s1uSocket;
101 m_s1uSocket->SetRecvCallback(MakeCallback(&NrEpcGnbApplication::RecvFromS1uSocket, this));
102 m_gnbS1uAddress = gnbAddress;
103 m_sgwS1uAddress = sgwAddress;
104}
105
107{
108 NS_LOG_FUNCTION(this);
109}
110
111void
113{
114 m_s1SapUser = s;
115}
116
119{
120 return m_s1SapProvider;
121}
122
123void
125{
126 m_s1apSapMme = s;
127}
128
131{
132 return m_s1apSapGnb;
133}
134
135void
136NrEpcGnbApplication::DoInitialUeMessage(uint64_t imsi, uint16_t rnti)
137{
138 NS_LOG_FUNCTION(this);
139 // side effect: create entry if not exist
140 m_imsiRntiMap[imsi] = rnti;
141 m_s1apSapMme->InitialUeMessage(imsi, rnti, imsi, m_cellId);
142}
143
144void
145NrEpcGnbApplication::DoPathSwitchRequest(NrEpcGnbS1SapProvider::PathSwitchRequestParameters params)
146{
147 NS_LOG_FUNCTION(this);
148 uint16_t gnbUeS1Id = params.rnti;
149 uint64_t mmeUeS1Id = params.mmeUeS1Id;
150 uint64_t imsi = mmeUeS1Id;
151 // side effect: create entry if not exist
152 m_imsiRntiMap[imsi] = params.rnti;
153
154 uint16_t gci = params.cellId;
155 std::list<NrEpcS1apSapMme::ErabSwitchedInDownlinkItem> erabToBeSwitchedInDownlinkList;
156 for (auto bit = params.bearersToBeSwitched.begin(); bit != params.bearersToBeSwitched.end();
157 ++bit)
158 {
159 EpsFlowId_t flowId;
160 flowId.m_rnti = params.rnti;
161 flowId.m_bid = bit->epsBearerId;
162 uint32_t teid = bit->teid;
163
164 EpsFlowId_t rbid(params.rnti, bit->epsBearerId);
165 // side effect: create entries if not exist
166 m_rbidTeidMap[params.rnti][bit->epsBearerId] = teid;
167 m_teidRbidMap[teid] = rbid;
168
169 NrEpcS1apSapMme::ErabSwitchedInDownlinkItem erab;
170 erab.erabId = bit->epsBearerId;
171 erab.gnbTransportLayerAddress = m_gnbS1uAddress;
172 erab.gnbTeid = bit->teid;
173
174 erabToBeSwitchedInDownlinkList.push_back(erab);
175 }
176 m_s1apSapMme->PathSwitchRequest(gnbUeS1Id, mmeUeS1Id, gci, erabToBeSwitchedInDownlinkList);
177}
178
179void
180NrEpcGnbApplication::DoUeContextRelease(uint16_t rnti)
181{
182 NS_LOG_FUNCTION(this << rnti);
183 auto rntiIt = m_rbidTeidMap.find(rnti);
184 if (rntiIt != m_rbidTeidMap.end())
185 {
186 for (auto bidIt = rntiIt->second.begin(); bidIt != rntiIt->second.end(); ++bidIt)
187 {
188 uint32_t teid = bidIt->second;
189 m_teidRbidMap.erase(teid);
190 NS_LOG_INFO("TEID: " << teid << " erased");
191 }
192 m_rbidTeidMap.erase(rntiIt);
193 NS_LOG_INFO("RNTI: " << rntiIt->first << " erased");
194 }
195}
196
197void
198NrEpcGnbApplication::DoInitialContextSetupRequest(
199 uint64_t mmeUeS1Id,
200 uint16_t gnbUeS1Id,
201 std::list<NrEpcS1apSapGnb::ErabToBeSetupItem> erabToBeSetupList)
202{
203 NS_LOG_FUNCTION(this);
204
205 uint64_t imsi = mmeUeS1Id;
206 auto imsiIt = m_imsiRntiMap.find(imsi);
207 NS_ASSERT_MSG(imsiIt != m_imsiRntiMap.end(), "unknown IMSI");
208 uint16_t rnti = imsiIt->second;
209
210 for (auto erabIt = erabToBeSetupList.begin(); erabIt != erabToBeSetupList.end(); ++erabIt)
211 {
212 // request the RRC to setup a radio bearer
213 NrEpcGnbS1SapUser::DataRadioBearerSetupRequestParameters params;
214 params.rnti = rnti;
215 params.bearer = erabIt->erabLevelQosParameters;
216 params.bearerId = erabIt->erabId;
217 params.gtpTeid = erabIt->sgwTeid;
218 m_s1SapUser->DataRadioBearerSetupRequest(params);
219
220 EpsFlowId_t rbid(rnti, erabIt->erabId);
221 // side effect: create entries if not exist
222 m_rbidTeidMap[rnti][erabIt->erabId] = params.gtpTeid;
223 m_teidRbidMap[params.gtpTeid] = rbid;
224 }
225
226 // Send Initial Context Setup Request to RRC
227 NrEpcGnbS1SapUser::InitialContextSetupRequestParameters params;
228 params.rnti = rnti;
229 m_s1SapUser->InitialContextSetupRequest(params);
230}
231
232void
233NrEpcGnbApplication::DoPathSwitchRequestAcknowledge(
234 uint64_t gnbUeS1Id,
235 uint64_t mmeUeS1Id,
236 uint16_t gci,
237 std::list<NrEpcS1apSapGnb::ErabSwitchedInUplinkItem> erabToBeSwitchedInUplinkList)
238{
239 NS_LOG_FUNCTION(this);
240
241 uint64_t imsi = mmeUeS1Id;
242 auto imsiIt = m_imsiRntiMap.find(imsi);
243 NS_ASSERT_MSG(imsiIt != m_imsiRntiMap.end(), "unknown IMSI");
244 uint16_t rnti = imsiIt->second;
245 NrEpcGnbS1SapUser::PathSwitchRequestAcknowledgeParameters params;
246 params.rnti = rnti;
247 m_s1SapUser->PathSwitchRequestAcknowledge(params);
248}
249
250void
252{
253 NS_LOG_FUNCTION(this);
254 if (m_nrSocket6)
255 {
256 NS_ASSERT(socket == m_nrSocket || socket == m_nrSocket6);
257 }
258 else
259 {
260 NS_ASSERT(socket == m_nrSocket);
261 }
262 Ptr<Packet> packet = socket->Recv();
263
264 NrEpsBearerTag tag;
265 bool found = packet->RemovePacketTag(tag);
266 NS_ASSERT(found);
267 uint16_t rnti = tag.GetRnti();
268 uint8_t bid = tag.GetBid();
269 NS_LOG_INFO("Received packet with RNTI: " << rnti << ", BID: " << +bid);
270 auto rntiIt = m_rbidTeidMap.find(rnti);
271 if (rntiIt == m_rbidTeidMap.end())
272 {
273 NS_LOG_WARN("UE context not found, discarding packet");
274 }
275 else
276 {
277 auto bidIt = rntiIt->second.find(bid);
278 NS_ASSERT(bidIt != rntiIt->second.end());
279 uint32_t teid = bidIt->second;
280 m_rxNrSocketPktTrace(packet->Copy());
281 SendToS1uSocket(packet, teid);
282 }
283}
284
285void
287{
288 NS_LOG_FUNCTION(this << socket);
289 NS_ASSERT(socket == m_s1uSocket);
290 Ptr<Packet> packet = socket->Recv();
291 NrGtpuHeader gtpu;
292 packet->RemoveHeader(gtpu);
293 uint32_t teid = gtpu.GetTeid();
294 NS_LOG_INFO("Received packet from S1-U interface with GTP TEID: " << teid);
295 auto it = m_teidRbidMap.find(teid);
296 if (it == m_teidRbidMap.end())
297 {
298 NS_LOG_WARN("UE context at cell id " << m_cellId << " not found, discarding packet");
299 }
300 else
301 {
302 m_rxS1uSocketPktTrace(packet->Copy());
303 SendToNrSocket(packet, it->second.m_rnti, it->second.m_bid);
304 }
305}
306
307void
308NrEpcGnbApplication::SendToNrSocket(Ptr<Packet> packet, uint16_t rnti, uint8_t bid)
309{
310 NS_LOG_FUNCTION(this << packet << rnti << bid << packet->GetSize());
311 NrEpsBearerTag tag(rnti, bid);
312 packet->AddPacketTag(tag);
313 NS_LOG_INFO("Add NrEpsBearerTag with RNTI " << rnti << " and bearer ID " << +bid);
314 uint8_t ipType;
315
316 packet->CopyData(&ipType, 1);
317 ipType = (ipType >> 4) & 0x0f;
318
319 int sentBytes;
320 if (ipType == 0x04)
321 {
322 NS_LOG_INFO("Forward packet from gNB's S1-U to NR stack via IPv4 socket.");
323 sentBytes = m_nrSocket->Send(packet);
324 }
325 else if (ipType == 0x06)
326 {
327 NS_LOG_INFO("Forward packet from gNB's S1-U to NR stack via IPv6 socket.");
328 sentBytes = m_nrSocket6->Send(packet);
329 }
330 else
331 {
332 NS_ABORT_MSG("NrEpcGnbApplication::SendToNrSocket - Unknown IP type...");
333 }
334
335 NS_ASSERT(sentBytes > 0);
336}
337
338void
339NrEpcGnbApplication::SendToS1uSocket(Ptr<Packet> packet, uint32_t teid)
340{
341 NS_LOG_FUNCTION(this << packet << teid << packet->GetSize());
342 NrGtpuHeader gtpu;
343 gtpu.SetTeid(teid);
344 // From 3GPP TS 29.281 v10.0.0 Section 5.1
345 // Length of the payload + the non obligatory GTP-U header
346 gtpu.SetLength(packet->GetSize() + gtpu.GetSerializedSize() - 8);
347 packet->AddHeader(gtpu);
348 uint32_t flags = 0;
349 NS_LOG_INFO("Forward packet from gNB's NR to S1-U stack with TEID: " << teid);
350 m_s1uSocket->SendTo(packet, flags, InetSocketAddress(m_sgwS1uAddress, m_gtpuUdpPort));
351}
352
353void
354NrEpcGnbApplication::DoReleaseIndication(uint64_t imsi, uint16_t rnti, uint8_t bearerId)
355{
356 NS_LOG_FUNCTION(this << bearerId);
357 std::list<NrEpcS1apSapMme::ErabToBeReleasedIndication> erabToBeReleaseIndication;
358 NrEpcS1apSapMme::ErabToBeReleasedIndication erab;
359 erab.erabId = bearerId;
360 erabToBeReleaseIndication.push_back(erab);
361 // From 3GPP TS 23401-950 Section 5.4.4.2, gNB sends EPS bearer Identity in Bearer Release
362 // Indication message to MME
363 m_s1apSapMme->ErabReleaseIndication(imsi, rnti, erabToBeReleaseIndication);
364}
365
366} // namespace ns3
void AddS1Interface(Ptr< Socket > s1uSocket, Ipv4Address gnbS1uAddress, Ipv4Address sgwS1uAddress)
friend class NrMemberEpcGnbS1SapProvider< NrEpcGnbApplication >
allow NrMemberEpcGnbS1SapProvider<NrEpcGnbApplication> class friend access
void SetS1apSapMme(NrEpcS1apSapMme *s)
friend class NrMemberEpcS1apSapGnb< NrEpcGnbApplication >
allow NrMemberEpcS1apSapGnb<NrEpcGnbApplication> class friend access
void RecvFromS1uSocket(Ptr< Socket > socket)
static TypeId GetTypeId()
Get the type ID.
void RecvFromNrSocket(Ptr< Socket > socket)
void SetS1SapUser(NrEpcGnbS1SapUser *s)
NrEpcGnbApplication(Ptr< Socket > nrSocket, Ptr< Socket > nrSocket6, uint16_t cellId)
NrEpcGnbS1SapProvider * GetS1SapProvider()
virtual void InitialContextSetupRequest(InitialContextSetupRequestParameters params)=0
virtual void PathSwitchRequestAcknowledge(PathSwitchRequestAcknowledgeParameters params)=0
virtual void DataRadioBearerSetupRequest(DataRadioBearerSetupRequestParameters params)=0
virtual void ErabReleaseIndication(uint64_t mmeUeS1Id, uint16_t gnbUeS1Id, std::list< ErabToBeReleasedIndication > erabToBeReleaseIndication)=0
As per 3GPP TS 36.413 version 9.8.0 section 8.2.3.2.2, the gNB indicates bearer release by sending an...
virtual void PathSwitchRequest(uint64_t gnbUeS1Id, uint64_t mmeUeS1Id, uint16_t gci, std::list< ErabSwitchedInDownlinkItem > erabToBeSwitchedInDownlinkList)=0
virtual void InitialUeMessage(uint64_t mmeUeS1Id, uint16_t gnbUeS1Id, uint64_t stmsi, uint16_t ecgi)=0
uint16_t GetRnti() const
uint32_t GetTeid() const
uint8_t m_bid
Bid, the EPS Bearer Identifier.