RAN LIFECYCLE
上图描述了每个数据包在其生命周期中要遍历的对象。供参考,图2和图3也提供了一幅地图,以更好地跟踪RAN的每个参与者(即gNB和UE)处理的数据包。本教程将逐步介绍每个步骤,并从这些数据包进入RAN的入口点开始-即EpcEnbApplication。
图二 gNB’s downlink packet processing pipeline
图三 : UE’s downlink packet processing pipeline
EpcEnbApplication
EpcEnbApplication安装在gNB上。它负责接收通过EPC模型隧道传输的数据包,并将其发送到NrGnbNetDevice。从概念上讲,这只是一个应用层的中继功能。通过启用EpcEnbApplication日志组件,可以运行cttc-nr-demo场景,该组件还可以配置为以INFO级别打印消息,并在消息前加上模拟时间、感兴趣的节点ID和打印该消息的例程。通过以下命令,可以达到这样的效果。
NS_LOG="EpcEnbApplication=info|prefix_all" ./ns3 run 'cttc-nr-demo' > log.out 2>&1
可以在第一个数据包上观察到这种中继功能,如下所示:
+0.400000282s 0 EpcEnbApplication:RecvFromS1uSocket(): [INFO ] Received packet from␣
,→S1-U interface.
+0.400000282s 0 EpcEnbApplication:RecvFromS1uSocket(): [INFO ] Received packet from␣
,→S1-U interface with GTP TEID: 2
+0.400000282s 0 EpcEnbApplication:SendToLteSocket(): [INFO ] Add EpsBearerTag with␣
,→RNTI 2 and bearer ID 2
+0.400000282s 0 EpcEnbApplication:SendToLteSocket(): [INFO ] Forward packet from eNB
,→'s S1-U to LTE stack.
+0.400000282s 0 EpcEnbApplication:SendToLteSocket(): [INFO ] Forward packet from eNB
,→'s S1-U to LTE stack via IPv4 socket.
文件src/lte/model/epc-enb-application.cc包含了源代码。
EpcEnbApplication通过EpsBearerTag添加了特定小区的UE ID(RNTI)和BID作为标签,这在后续章节中极大地简化了数据包处理。该应用程序可以根据接收到的数据包结构中GTP-U头部的TEID找到正确的RNTI和BID。这个过程可以在EpcEnbApplication::RecvFromS1uSocket()源代码中找到:
GtpuHeader gtpu;
packet->RemoveHeader(gtpu);
uint32_t teid = gtpu.GetTeid();
std::map<uint32_t, EpsFlowId_t>::iterator it = m_teidRbidMap.find(teid);
if (it == m_teidRbidMap.end())
{
NS_LOG_WARN("UE context at cell id " << m_cellId << " not found, discarding packet
,→");
m_rxDropS1uSocketPktTrace(packet->Copy());
}
else
{
m_rxS1uSocketPktTrace(packet->Copy());
SendToLteSocket(packet, it->second.m_rnti, it->second.m_bid);
}
注意,hashmap <uint32_t,EpsFlowId_t>将一个由uint32_t处理的TEID与由EpsFlowId_t数据结构分组的RNTI和BID进行了关联。
数据包及其修改可以用下图表示,其中红色标记表示删除的部分,绿色标记表示添加的部分。
还有一个字节标签用于跟踪数据包的流量统计,这与流量监视器绑定,并与场景打印的最终结果相关。
经过修改的新数据包最终被发送到EpcEnbApplication::SendToLteSocket(),该函数根据数据包的L3类型区分要发送的数据包,此处为IPv4类型。
最后,可以使用以下跟踪信息来追踪该应用程序的传入和传出数据包:
RxFromEnb: Receive data packets from LTE Enb Net Device
RxFromS1u: Receive data packets from S1-U Net Device
RxFromS1uDrop: Drop data packets from S1-U Net Device
TxToEnd: Transmit data packets to LTE eNB Net Device
TxToS1u: Transmit data packets to S1-U Net Device
#1
数据包延迟
数据包在EnbEpcApplication中不能产生延迟。
#2丢包
如果GTP-U TEID与gNB-UE链路的RNTI和BID之间没有关联,数据包可能会被丢弃。
NrGnbNetDevice
在EpcEnbApplication发送数据包后,它立即在NrGnbNetDevice::DoSend()方法中接收。我们可以通过日志观察到这一点:
NS_LOG="NrGnbNetDevice=info|prefix_all" ./ns3 run 'cttc-nr-demo' > log.out 2>&1
+0.400000282s 0 NrGnbNetDevice:DoSend(): [INFO ] Forward received packet to RRC Layer
该方法的源代码位于contrib/nr/model/nr-gnb-net-device.cc文件中。值得一提的是,注意我们在源代码目录src/lte/(用于之前的EpcEnbApplication)和contrib/nr/(用于这个对象)之间的切换;这对于当前nr模块的上层来说是正确的,这些上层重用了最初为LTE实现的部分组件。
源代码揭示了可以通过NrNetDevice/Tx跟踪数据包。
NrGnbNetDevice不处理数据包,而是将其转发到RRC层。
#1
数据包延迟
数据包在EnbEpcApplication中不能产生延迟。
#2丢包
数据包不会被丢弃。
LteEnbRrc
gNB的RRC层由LteEnbRrc及其伙伴UeManager处理,它们都可以在lte/model/lte-enb-rrc.cc中找到。 当来自上层的数据包被处理时,会使用LteEnbRrc::SendData()函数,而要发送到UE的数据包则由UeManager::SendPacket()函数来处理。实际上,如果使用以下命令启动模拟
NS_LOG="LteEnbRrc=info|prefix_all" ./ns3 run cttc-nr-demo &> out.log
下面的日志信息会被生成
+0.400000282s 0 LteEnbRrc:SendData(): [INFO ] Received packet
+0.400000282s 0 LteEnbRrc:SendPacket(): [INFO ] Send packet to PDCP layer
通过查看源代码,RRC层首先提取RNTI,该RNTI由EpsBearerTag数据结构处理。由于RNTI,可以检索相应的UeManager实例,该实例通过FSM跟踪gNB-UE链路状态。 搜索由LteEnbRrc完成,它使用一个哈希映射,将每个RNTI链接到感兴趣的UeManager的指针。找到之后,使用引用的数据包的bid调用匹配的SendData()方法。
EpsBearerTag tag;
bool found = packet->RemovePacketTag(tag);
NS_ASSERT_MSG(found, "no EpsBearerTag found in packet to be sent");
Ptr<UeManager> ueManager = GetUeManager(tag.GetRnti());
ueManager->SendData(tag.GetBid(), packet);
SendData()方法可以通过以下代码摘录快速理解:
switch (m_state)
{
case INITIAL_RANDOM_ACCESS:
case CONNECTION_SETUP:
NS_LOG_WARN("not connected, discarding packet");
m_packetDropTrace(p, bid);
return;
case CONNECTED_NORMALLY:
case CONNECTION_RECONFIGURATION:
case CONNECTION_REESTABLISHMENT:
case HANDOVER_PREPARATION:
case HANDOVER_PATH_SWITCH: {
NS_LOG_LOGIC("queueing data on PDCP for transmission over the air");
SendPacket(bid, p);
}
break;
// ...
}
让我们忽略与切换相关的状态,因为在NR模块中还没有实现X2-U接口。
如果UE准备从gNB角度接收数据包,即它在connected_normal中,SendPacket()方法调用以继续传输:
LtePdcpSapProvider::TransmitPdcpSduParameters params;
params.pdcpSdu = p;
params.rnti = m_rnti;
params.lcid = Bid2Lcid(bid);
uint8_t drbid = Bid2Drbid(bid);
// Transmit PDCP sdu only if DRB ID found in drbMap
std::map<uint8_t, Ptr<LteDataRadioBearerInfo>>::iterator it = m_drbMap.find(drbid);
if (it != m_drbMap.end())
{
Ptr<LteDataRadioBearerInfo> bearerInfo = GetDataRadioBearerInfo(drbid);
if (bearerInfo)
{
NS_LOG_INFO("Send packet to PDCP layer");
LtePdcpSapProvider* pdcpSapProvider = bearerInfo->m_pdcp->
,→GetLtePdcpSapProvider();
pdcpSapProvider->TransmitPdcpSdu(params);
}
}
sap:子层与子层之间使用服务接入点(Service Access Points, SAP)作为端到端通信的接口
在这里,通过创建一个具有补充信息的PDCP SDU结构来处理数据包,该信息被称为LtePdcpSapProvider::TransmitPdcpSduParameters。 这些参数包括RNTI以及依赖于BID的另外两个参数,如LCID,在这个例子中是4,以及DRBID,它是2。如果仍然存在,后者用于检索与DRBID相关的LteDataRadioBearerInfo. 最后,SDU将通过TransmitPdcpSdu()函数传递给激活的LtePdcpSapProvider。有了这个过程,就可以理解数据包是如何被修改的。如果通过启用LteEnbRrc日志组件运行相同的模拟,我们可以获得以下消息日志
+0.400000282s 0 LteEnbRrc:SendData(): [INFO ] Received packet
+0.400000282s 0 LteEnbRrc:SendPacket(): [INFO ] Send packet to PDCP layer
如可以注意到的那样,数据包标签会被移除,因为RNTI和BID会被传递给LtePdcpSapProvider::TransmitPdcpSduParameters实例。字节标签和数据包结构保持不变。
#Packet latency
数据包在LteEnbRrc中不能产生延迟。
#Packet drops
在某些情况下,UE可能仍然在RACH上请求资源,例如INITIAL_RANDOM_ACCESS,或者仍然有待处理的设置,例如CONNECTION_SETUP。在这种情况下,该数据包将无法被传输。因此,它被放置在UeManager/Drop跟踪源中并被丢弃。