5G用户面隧道封装与排障:TEID、QFI、SDAP、PDCP链路解析

发布时间:2026/10/28 23:37:29
5G用户面隧道封装与排障:TEID、QFI、SDAP、PDCP链路解析

简介:面向学习5G NR空口协议与下行数据流程的通信从业者及高校学生,这份图形化资料以独立组网基站为例,梳理用户面协议栈中CU-DU高层分离架构下SDAP、PDCP、RLC、MAC与物理层的分布关系。内容沿应用层HTTP请求、TCP/IP封装、链路层处理到物理层传输逐层展开,并结合图示说明TCP与IPv4头部的端口、序列号、窗口大小、校验和、源地址与目标地址等字段作用,便于建立端到端数据封装与转发的整体认识。压缩包仅含1个PDF文件,大小约874KB,适合作为协议栈复习和课堂讲解的辅助材料。目前已有270人学习,可用于快速对照各层头部结构与下行传输步骤,强化对5G NR用户面流程的理解。

1. 一个 HTTP GET 在 5G 里被套了五层壳:5G NR 下行数据流的真实形态

终端点一下网页,你以为空口上跑的是“网页内容”,实际跑出来的却是一层层头部套出来的字节流。同一个 TCP 包,在核心网侧被贴着“每 PDU Session 一条”的隧道标签,到了基站内部又换成“每 DRB 一条”的另一套标签,中间还要额外塞进两个容器才能说清自己属于哪个 QoS Flow。更反直觉的是:隧道标识 TEID 从头到尾都不知道 QoS Flow 是谁。

搞懂这条链路的价值在于排查。空口速率不达标、大包丢小包通、语音断续而下载正常,这些现象最后几乎都会落到某个头部字段的取值上。这篇内容按“包怎么被一层层加上标签、标签为什么这么设计、哪些地方最容易翻车”的顺序拆开讲,看完你应该能对着一次抓包,指出问题出在哪一层。

2. 从 HTTP 到 IP:20 字节头部里哪些字段真的会被下游用到

先站在应用服务器这一端。用户发出 HTTP GET,服务器回响应,浏览器之下是 TCP,TCP 之下是 IP。这一段看起来跟 5G 无关,但后面所有 QoS 决策的输入,都来自这两个头部里的字段。换句话说:5G 网络没有“读懂”你的业务,它只是读了 TCP/IP 头。

2.1 TCP 头部:序列号、窗口、校验和各自解决什么问题

标准 TCP 头 20 字节,可选字段会让它更长。逐字段看,真正影响下行链路的只有几个:

源端口和目的端口各 16 比特,用来标识上层应用。HTTP 默认目的端口 80,HTTPS 是 443。这两个值是后面五元组匹配的关键输入。

序列号 32 比特,接收端靠它重排序、检测丢包。确认号 32 比特,反向告诉发送端“我已经收到哪一段”。这两个字段合起来构成了 TCP 的可靠传输基础——注意,是 TCP 在保证可靠,不是 5G。5G 的 RLC 有 ARQ、PDCP 有重排序,但它们服务的是“空口这一段”,端到端的可靠性仍然是 TCP 自己的事。这一点在排查“到底是空口丢包还是服务器重传”时非常关键。

数据偏移 4 比特,定义头部长度,因为选项字段可变。窗口大小 16 比特,告诉对端“我还愿意接收多少字节”,这是 TCP 流控的核心,也是为什么高时延链路上必须放大窗口才有吞吐。

校验和 16 比特,覆盖头部和载荷。这里有个常被忽略的细节:TCP 校验和计算时会引入一个伪头部,包含源 IP、目的 IP、协议号和 TCP 长度。也就是说 TCP 校验和隐式地校验了 IP 地址的正确性——包被错误 NAT 或错误路由到另一端时,校验和会失败而不是静默接受。

紧急指针 16 比特,标记需要高优先级处理的数据。实际部署中用得极少,但字段一直在。

头部里还有 9 个标志位(NS/CWR/ECE/URG/ACK/PSH/RST/SYN/FIN),其中 ECE 和 CWR 与 ECN 拥塞通知配合,这条线索会延伸到下一节的 IP 头。

2.2 IP 头部:DSCP 与 ECN 是唯一能“带话”给网络的字段

IPv4 标准头也是 20 字节。版本字段值为 4,头部长度字段给出实际头长,总长度给出整包大小。

真正参与 5G QoS 决策的是 DSCP 和 ECN。DSCP 占 6 比特,用于给包打优先级标记;ECN 占 2 比特,用于指示拥塞,让路由器在不丢包的前提下通知端点降速。这两个字段是三层设备唯一能“看见并利用”的业务意图表达。

协议字段标识载荷类型,TCP 对应数值 6,UDP 是 17。这个数字会被后面的 SDF 模板当作匹配条件之一。

标识、标志、分片偏移三个字段服务于分片。一旦包超过链路 MTU 就必须分片,而分片在隧道封装场景下会变得非常麻烦——外层加了几十字节头,内层原本刚好卡在 MTU 边界上的包立刻超限。这是后面避坑章节里会专门说的一条。

生存时间 TTL 每经过一个路由器减一,用来防环。头部校验和只覆盖 IP 头本身,不覆盖载荷,所以每跳都要重算,这也是 IPv6 取消该字段的原因之一。

把这两层看完就能得出一个结论:应用层往下传的“业务语义”被压缩成了几个数字——端口、协议号、IP 地址、DSCP。5G 核心网能做的所有精细化处理,都建立在这几个数字之上。

2.3 SDF 模板与五元组匹配:UPF 如何把包塞进正确的 QoS Flow

包离开服务器,穿过 IP 网络,到达 5G 核心网的入口——用户面功能 UPF。UPF 要回答两个问题:这个包属于哪个 PDU Session?属于该会话下的哪个 QoS Flow?

做这件事的机制叫包检查加 SDF 模板匹配。UPF 提取头部字段,与一组业务数据流模板逐一比对。模板的典型形态是一个五元组组合:{源 IP 地址、目的 IP 地址、源端口号、目的端口号、协议号}。命中哪条模板,就落到对应的 PDU Session 和 QoS Flow。

这批模板不是 UPF 自己生成的,而是会话管理功能 SMF 在 PDU Session 建立阶段下发的。常见的实现思路是:SMF 通过控制面接口把包检测规则和对应的转发动作一起推给 UPF,UPF 只做匹配和执行,不做策略判断。策略与控制分离,这是整个核心网架构的基本分工。

这里有个容易误解的点:QoS Flow 不是“一种业务一条”,而是“一组具有相同转发处理要求的流”。同一个 PDU Session 下可以有多条 QoS Flow,每条有自己的 5QI、保证速率、调度优先级。一个浏览器开的多个 TCP 连接,很可能全部落在同一条 QoS Flow 里,因为它们的五元组匹配到了同一条模板。

匹配完成后,UPF 需要把包送向基站。这一步就要引入隧道了,而隧道的粒度选择,恰恰是整条链路上最容易被想当然的地方。

3. GTP-U 隧道:TEID 为什么只认 PDU Session,不认 QoS Flow

从 UPF 到基站要跨传输网,用的是 GTP-U 隧道。原始材料里有一句话值得反复读:GTP-U 隧道是每 PDU Session 一条,这意味着 GTP-U 头里的隧道端点标识 TEID 只能标识 PDU Session,不能标识 QoS Flow。

这不是实现缺陷,而是刻意的分层结果。

3.1 GTP-U 头部逐字段拆解

GTP-U 头有几个必选字段和一组可选字段。版本占 3 比特,PT 标识协议类型,S 位表示是否带序列号,PN 位表示是否带 N-PDU 号,E 位表示是否存在扩展头。消息类型一个字节,承载用户数据时是 G-PDU。长度字段给出隧道头之后的内容长度。

核心是 TEID,32 比特。它由隧道接收端分配,发送端在回程方向上使用同一个值。一条 NG-U 隧道对应一个 PDU Session,TEID 因此成为“这个包属于哪个会话”的唯一索引。基站收到包,读 TEID,查表得到 PDU Session,就这么直接。

问题随之而来:一个 PDU Session 下可能有多条 QoS Flow,TEID 无法区分。于是标准引入了一个扩展头——PDU Session Container,专门用来补上这个信息。基础 GTP-U 头 8 字节,加上扩展头后整体长度增加,具体取决于是否携带序列号等可选字段。

结构上大致是这样:基础头之后是可选的序列号、N-PDU 号、下一个扩展头类型,然后是扩展头长度和扩展头内容,即 PDU Session Container。

3.2 PDU Session Container:QFI、PDU Type、PPI、RQI 四个字段各自的作用

这个容器只有几个字节,但信息密度很高。

PDU 类型字段取值为 0 表示下行包,取值为 1 表示上行包。方向标识在这里而不是在 GTP-U 基础头里,是因为扩展头内容由上层协议定义。

QFI 是 QoS Flow 标识,6 比特,取值范围内标识该包所属的 QoS Flow。这就是 TEID 缺失的那块拼图:TEID 定位会话,QFI 定位流。

PPP 字段指示头部里是否携带寻呼策略指示。PPI 是寻呼策略指示本身,UPF 可以把它传给基站,用来影响寻呼流程的优先级。这个字段的场景很具体:当 UE 处于 RRC 非活跃态,下行包到达会触发寻呼,如果这个包优先级高,网络希望寻呼也快一点。PPI 就是把这个意图从核心网传到无线侧的通道。

RQI 是反射式 QoS 指示,用来告诉接收方是否要对该 QoS Flow 应用反射式 QoS。这个字段的价值在 SDAP 那一层才能完全体现,先记住它是个开关。

用一段解析代码把这段结构固定下来,会更直观:

def parse_gtpu_ext_header(raw: bytes): """解析 GTP-U 扩展头中的 PDU Session Container(示意实现)""" # raw[0]: 扩展头长度,单位 4 字节,值为 1 表示共 4 字节 ext_len = raw[0] * 4 # raw[1]: 高 4 位为 PDU Type,低 4 位为 QFI 高位部分 pdu_type = (raw[1] & 0xF0) >> 4 # 0=下行, 1=上行 qfi = raw[1] & 0x3F # QoS Flow Identifier, 6 bit # raw[2]: PPP / PPI / RQI 位域 ppp = (raw[2] & 0x80) >> 7 # 是否携带寻呼策略指示 ppi = (raw[2] & 0x78) >> 3 # 寻呼策略指示, 4 bit rqi = (raw[2] & 0x04) >> 2 # 反射式 QoS 指示 return { "ext_len": ext_len, "pdu_type": "DL" if pdu_type == 0 else "UL", "qfi": qfi, "ppp": ppp, "ppi": ppi, "rqi": rqi, }

代码里的位偏移是关键:QFI 占第 2 字节的低 6 位,PDU Type 占高 4 位中的低 1 位。不同版本标准的位域定义可能有细微差异,实际解析要以对应规范为准,但“TEID 定会话、QFI 定流”这个分工不会变。参数上,ext_len 决定了要往后跳多少字节才能找到下一个扩展头,做多层扩展解析时必须靠它逐级跳。

3.3 双层 IP 头:内层给终端,外层给传输网

GTP-U 跑在 UDP 之上,UDP 再跑在 IP 之上。UDP 端口 2152 是 GTP-U 的注册端口,源和目的端口都用它来标识上层应用。UDP 头只有 8 字节:源端口、目的端口、长度、校验和。

于是这个包就有了两层 IP 头。内层 IP 是终端和服务器之间的端到端地址,外层 IP 是 UPF 和基站这两个隧道端点之间的传输地址。到达隧道对端时,外层这一整套(外层 IP、UDP、GTP-U)会被剥掉,只剩下内层 IP 和载荷交给基站处理。

这两层头部的 DSCP 是独立的。外层 DSCP 用于传输网内部的转发优先级,内层 DSCP 是用户业务的原始标记。两者可以一致也可以不一致,取决于运营策略。排障时混淆这两者,会得出完全错误的结论——这一点后面单独列一条。

4. CU 内部的两级映射:SDAP 选 DRB,PDCP 管安全

包到了基站,但基站内部还分 CU 和 DU。CU 承载 SDAP 和 PDCP,DU 承载 RLC、MAC 和物理层。这个高层分割架构决定了包要在基站内部再走一次隧道。先看 CU 里发生了什么。

4.1 SDAP:QoS Flow 到 DRB 的映射,以及那个“可选”的头部

CU 先解 GTP-U,读 TEID 定位 PDU Session,读 PDU Session Container 里的 QFI 定位 QoS Flow。接下来交给 SDAP 层,它的唯一职责是把 QoS Flow 映射到数据无线承载 DRB。

这里存在一个天然的层级差异:QoS Flow 是核心网的概念,由 SMF 决定,粒度细、数量多;DRB 是无线侧的概念,由基站调度决定,粒度粗、数量少。一个 DRB 可以承载多条 QoS Flow,只要它们的调度需求足够接近。这个映射关系的意义在于:核心网可以定义几十条 QoS Flow,无线侧不必为此建几十条承载,调度复杂度可控。

SDAP 头是可配置的。不配置时,SDAP 直接透传,不添加任何字节——这对吞吐有利,因为每个包都省掉几个字节,乘以每秒几十万包就是实打实的带宽。配置时,头部会带上 QFI 和反射式 QoS 指示。

反射式 QoS 的机制值得单独说清。下行包经过 SDAP 时,如果头部携带 QFI 且 RQI 置位,终端收到后就能记住“这个 QoS Flow 的包是通过这条 DRB 下来的”。之后终端在上行方向发送同一 QoS Flow 的数据时,可以直接沿用这个映射,不需要网络再下发一次显式配置。这是一种用数据面信令替代控制面信令的做法,省掉了一轮 RRC 重配。

代价是:SDAP 头一旦不配,反射式 QoS 就失去了载体,上行映射只能靠显式 RRC 配置。这也是常见故障来源之一。

4.2 PDCP:先算完整性再加密,顺序反了整个链路都会崩

PDCP 提供三件事:完整性保护、加密、以及头部信息(主要是序列号)。

完整性保护的实现方式是计算一个认证码,附加在包上作为 MAC-I 字段,接收端用它验证包确实来自合法发送方、且未被篡改。加密是在认证码算完之后,对载荷做比特级扰乱,没有密钥就无法还原。

顺序不能反,原因很直接:认证码的计算输入必须是明文。如果先加密再算认证码,接收端拿到的是密文,算出来的值和发送端不一致,校验必然失败。常见的实现思路是:以 COUNT(由超帧号和 PDCP 序列号拼成)加上承载标识和方向位构造输入,跑一次完整性算法得到 MAC-I,然后把 MAC-I 连同载荷一起加密。接收端反向操作,先解密、再校验。

PDCP 序列号用于接收端重排序。空口有 HARQ 重传,包可能乱序到达,序列号让接收端能把它们重新排好再往上交。序列号长度可配,长短各有取舍:长序列号在大带宽、高时延场景下不容易回绕,但头部开销大;短序列号省字节,但回绕更快。

头压缩是 PDCP 的另一个可选功能,通常用在语音场景而不是数据下载。语音包头部占比极高(一个几十字节的包,头部可能占一半以上),压缩收益明显;数据包载荷大,压缩收益有限,反而增加处理开销。

4.3 一个包在 CU 里被改了什么

把这一段串起来看:进入 CU 时,包是 GTP-U 封装的内层 IP 包;SDAP 决定它走哪条 DRB,可能加一个几字节的头;PDCP 计算认证码、加密载荷、加上序列号。出去的时候,它已经是一个 PDCP PDU,准备跨 F1 接口送往 DU。

注意这里发生了一次语义转换:进来时它的身份是“某 PDU Session 下的某 QoS Flow”,出去时它的身份是“某条 DRB 上的一个 PDCP PDU”。标识体系换了,隧道粒度也必须跟着换。

5. F1 接口的隧道粒度变了:几条最容易翻车的排查记录

CU 把 PDCP PDU 送到 DU,要跨 F1 接口。这一步的隧道粒度从“每 PDU Session 一条”变成“每 DRB 一条”。原因不难推:包在 CU 里已经被映射到 DRB 了,DU 需要的是“这条承载的数据”,而不是“这个会话的数据”。一条 PDU Session 可能对应多条 DRB,用会话粒度的隧道送下去,DU 还得再做一次拆分,等于把 CU 的活儿重做一遍。

5.1 NR RAN Container:F1 接口换了容器,也换了一套反馈机制

隧道粒度变了,GTP-U 头里的扩展头也要跟着换。NG-U 接口上用的是 PDU Session Container,F1 接口上用的是 NR RAN Container,内容由新空口用户面协议规定。

这个容器承载的不只是标识信息,还有下行数据传输状态反馈一类的控制信息。常见的实现思路是:DU 通过这个容器周期性告诉 CU“我这边缓冲区还剩多少、已经成功发出多少、建议你再送多少”,CU 据此调整下发速率。这就是流控闭环——CU 不知道空口瞬时状况,DU 知道,所以反馈必须由 DU 发起。

这个设计也解释了 CU-DU 分割的取舍。分割的好处是集中单元可以池化、调度更全局、站点部署更灵活;代价是基站内部多了一跳传输,多了一层隧道,多了一套反馈协议。如果 F1 传输网质量不行,这一跳会成为瓶颈,而且故障现象和空口问题非常像,容易误判。

5.2 五条踩坑记录:现象、原因、解决

下面这些是实际排查中反复出现的类型,每条按现象、原因、解决三段说。

第一条,用 TEID 去区分 QoS Flow,发现同一条隧道里不同优先级的包被一起处理。现象是抓包看到多个 QFI 的包共用同一个 TEID,误以为是设备实现有问题。原因是 TEID 的分配粒度就是 PDU Session,一条会话下的所有 QoS Flow 共享同一个 TEID。解决办法是解析扩展头里的 PDU Session Container,取 QFI 字段做区分,抓包工具的显示过滤也要相应调整。

第二条,只看外层 IP 的 DSCP 判断业务优先级。现象是明明给语音标了高优先级,传输网里却没体现出差异。原因是外层 DSCP 服务的是传输网转发,内层 DSCP 才是用户业务的标记,两者是独立配置的。解决是先剥掉隧道再读内层 IP 头,或者确认传输网侧是否做了 DSCP 映射。

第三条,SDAP 头没配,反射式 QoS 悄无声息地失效。现象是下行正常、上行映射错乱,或者上行包被塞进了不合适的 DRB。原因是 SDAP 头可选,不配的时候终端拿不到 QFI 信息,无法推导上行映射。解决办法是检查无线侧配置里 SDAP 头相关的开关是否打开,以及 RQI 是否在下行包里正确置位。

第四条,完整性保护校验失败导致大量丢包,误判为加密算法不兼容。现象是某些承载上的包全部被丢弃,计数器上完整性失败一路涨。原因是实现里把加密和完整性计算的顺序做反了,或者 COUNT 的构造有偏差(超帧号没有正确维护)。解决办法是对照规范核对处理顺序:先算认证码、再加密,接收端先解密、再校验,同时确认超帧号的翻转逻辑。

第五条,大包丢、小包通,ping 得通但下载卡死。现象很有迷惑性:小尺寸探测包一切正常,一跑大文件就停滞。原因是隧道封装额外占用了传输层字节,外层 IP 加 UDP 加 GTP-U 加扩展头,累计三四十字节以上,内层原本贴着 MTU 边界的包直接超限。如果路径 MTU 发现机制又被中间设备阻断,分片就彻底失效。解决办法是核算隧道总开销、调小内层 MTU,或在边界设备上做 MSS 钳制,让 TCP 自己把段大小降下来。

提示:第五条是最容易被误判成“空口质量差”的一类。判断方法很简单——看丢包是否与包长强相关。强相关就往 MTU 方向查,弱相关再往无线侧查。

6. 为什么要把 QoS Flow 和 DRB 分成两层:一次设计取舍的复盘

把整条链路拉直来看,最值得琢磨的不是某个字段怎么填,而是为什么要有两套标识体系。

QoS Flow 是核心网的语言,它描述“这组数据需要什么服务”:时延预算、丢包率、保证速率。这个描述是端到端的、与无线技术无关的。DRB 是无线侧的语言,它描述“这组数据挂在哪条承载上”:用的是哪个逻辑信道、什么调度优先级、什么 RLC 模式。这个描述是接入技术相关的、与核心网无关。

两者分开,换来的是解耦。核心网改一条 QoS 策略,不需要动无线配置;无线侧换一种调度算法,不需要通知核心网。终端切换小区时,QoS Flow 不变,DRB 可以重建——如果两者合成一个概念,这种迁移会变得极其笨重。

代价也很明确:每一层都要有自己的标识容器。NG-U 上用 PDU Session Container 装 QFI,F1 上用 NR RAN Container 装承载相关信息,两个容器的格式、长度、解析方式都不一样。做抓包分析的人必须记住当前这段链路用的是哪个容器,搞错了就解析出一堆垃圾数据。

维度NG-U 接口F1 接口
隧道粒度每 PDU Session每 DRB
扩展头容器PDU Session ContainerNR RAN Container
关键标识TEID 定位会话,QFI 定位流TEID 定位承载
反馈机制无(依赖核心网策略)下行传输状态反馈,用于流控
典型排障入口剥外层 IP,读 QFI剥外层 IP,核对承载与反馈

验证这套机制是否按预期工作的办法,其实不复杂:在核心网侧和基站侧各抓一次包,比对同一个包在两次抓包中的隧道标识、QFI、序列号、以及内层 IP 的 DSCP。如果 QFI 一致而 TEID 变了,说明映射正常、隧道重建;如果 QFI 都变了,问题在 UPF 的模板匹配;如果内层 DSCP 变了,说明中间有设备做了重标记。

我印象最深的一次,是花了半天时间追一个“随机丢包”,最后发现是完整性校验的 COUNT 维护有偏差,超帧号翻转时没同步。从那以后我每次看下行链路的问题,都强制自己按“先确认隧道粒度、再确认容器类型、最后确认安全顺序”这个顺序走一遍,不再凭现象直接猜层。

这份材料把整条链路画成了连续的图示,从 TCP 头一路排到 F1 接口的隧道结构,字段级的对照关系齐全,适合放在手边当查表用。需要对照抓包逐层核对的时候,翻它的图比翻规范快得多,获取方式在资源页里。

希望帮到你。

本文还有配套的精品资源,点击获取