首页 / 资讯中心 / 文章详情

3GPP LTE RLC协议深度解析:状态机、窗口机制与避坑指南

3GPP LTE RLC协议深度解析:状态机、窗口机制与避坑指南 ★ FEATURED ARTICLE
简介3GPP LTE RLC中文协议是TD-LTE数字蜂窝移动通信网Uu接口系列技术要求的第7部分由中国通信标准化协会组织制定面向LTE协议开发、网络优化及测试工程师提供了RLC协议中文规范的重要参考。这份技术报告对RLC协议的功能、架构与工作机制进行了详细规定涵盖E-UTRA RLC子层结构、实体划分、数据传输机制、错误检测与纠正机制并对协议数据单元格式及异常数据处理作出了明确说明。资源为单个doc格式文档压缩包大小约1.74MB内容完整保留了技术报告原文结构从范围、规范性引用文件、术语定义到协议详细规范逐章展开便于按章节查阅与学习。报告还包含RLC协议实现架构、测试方法与测试用例等相关规定为实际组网应用、协议栈开发调试及一致性测试提供了重要指导。已有489人学习该资源适合需要研读TD-LTE Uu接口技术规范、从事LTE协议栈研发或通信标准学习的技术人员使用。1. 3GPP LTE RLC中文协议协议栈里最容易被低估的一层却卡住了大半新人刚接触LTE协议栈的人多半从RRC或PDCP开始翻等真正动手调RLC重传时才发现这一层的问题全是状态变量和窗口机制带来的。所谓3GPP LTE RLC中文协议指的就是把3GPP TS 36.322这套英文规范吃透、整理成能对着实现的中文资料。RLC在PDCP和MAC之间做分段、级联、重传和按序递交SRB和DRB都绕不开它读懂这一层是调试上行丢包、下行乱序、吞吐掉零的前提。这篇笔记按实现者的视角把规范位置、三种模式选型、状态机推进、PDU比特级拆解和常见翻车点一次讲透。2. 先定位规范源头RLC在36.322里的角色、版本差异与三种模式选型2.1 为什么RLC值得单独啃一遍很多从业者习惯把LTE协议栈画成一张分层图然后默认RLC只不过是MAC和PDCP之间的搬运工。这个理解在早期版本里勉强成立到了LTE-A和后续R10/R11引入eNB间载波聚合、多流传输后RLC的重排序和重传逻辑直接决定用户体验。3GPP把RLC的完整规范放在TS 36.322和36.321MAC、36.323PDCP、36.331RRC并列。如果你去翻36.322正文会发现它通篇在定义三类东西状态变量、控制PDU格式、以及状态迁移条件。RLC的职能拆开看有三件一是把上层PDCP的SDU按MAC调度的传输块大小做动态分段和级联二是在AM模式下用状态报告触发对端重传三是在接收侧做重复检测、乱序重排和按序递交。这三件事直接影响TCP窗口、语音时延和切换成功率。一个典型场景是下行速率明明调度到了100Mbps测速却只有40M排查到最后往往是RLC的t-Reordering配得过大或过小导致接收窗频繁阻塞。2.2 UM/AM/TM三种模式分别在什么场景下被启用36.322定义了三种传输模式选型依据是上层业务对时延、误码率、按序性的容忍度。TM透明模式最轻量不添加任何RLC头直接透传一般用于随机接入过程中的SRB0消息比如RRC Connection Request。它不做分段也就要求MAC调度的TB大小刚好容纳整个SDU所以只适合控制面早期消息和广播场景。UM非确认模式加了RLC头包含SN序号和分段信息接收侧能检测丢包并重排但不发状态报告、不重传。语音VoIP业务和某些实时视频走UM丢了就丢了重传反而引入抖动。UM要注意的是SN长度可配5bit、6bit或10bit小区边缘用户调度周期长时SN太短会绕回需要靠配置兜底。AM确认模式是最复杂的模式发送侧维护重传缓存接收侧维护接收窗和状态报告支持ARQ重传、poll轮询、t-Reordering重排序。所有DRB数据无线承载默认走AM因为TCP业务不允许丢包。AM下又分UM承载能映射到AM承载吗不行逻辑信道到RLC模式的映射在RRC建立时定死中途不能切换。2.3 不同版本规范下的行为差异对照做协议栈的都知道同一个RLC实体在不同3GPP版本下行为和字段定义有小幅演进。R8基础版本定义了AM/UM/TM、AMD PDU和状态PDU基本格式R9/R10引入了载波聚合RLC层本身变化不大但分段时需要考虑MAC分集调度的多个进程R11之后对eNB间双连接有增强RLC在Split Bearer场景下需要支持发送侧SDU在Master和Secondary路径上分配SN这对轮询和状态报告的触发逻辑提出了新约束。实际开发中芯片平台和网络侧EnodeB厂商华为、爱立信、中兴对某些字段的容忍度不同。比如AMD PDU的P字段Poll bit在规范里只是置1表示请求状态报告但有些基站固件对连续poll的间隔有隐含限制。做互操作测试时不要迷信R8基线务必要确认目标网络跑的是R9还是R11尤其是载波聚合场景下的重分段和SN分配策略。版本RLC主要变化对实现的影响R8RLC分离到36.322独立规范基线AM PDU基本格式R9/R10载波聚合引入MAC多进程调度分段状态需对应多个HARQ进程R11/R12Split Bearer支持eNB间双连接发送侧SN分配需跨路径协调R13增强CA最多32载波RLC主要涉及重排序时效t-Reordering参数需随载波数调整3. 把AM收发状态机拆成白话状态变量、窗口与重传触发条件RLC AM的难不在PDU格式在状态机。规范里用了一堆缩写——VR(R)、VR(MR)、VR(X)、VR(MS)、VR(H)、VT(A)、VT(S)——看起来像黑匣子其实每个变量对应一个窗口边界。3.1 发送侧状态变量与窗口推进逻辑发送侧最重要的两个变量是VT(S)和VT(A)。VT(S)是下一个新传PDU要分配的SNVT(A)是已经被对端确认过的最大SN可以理解为重传缓存的最低有效位。每次发送新AMD PDU时给该PDU打上当前VT(S)然后VT(S)自增收到对端状态报告里的ACK_SN时把VT(A)推进到ACK_SNVT(A)到VT(S)之间就是还没被确认的窗口。窗口大小受协议规定限制。AM的SN是10位部分场景12位最大窗口不能超过SN空间一半否则会出现确认帧无法区分新旧序列的问题。实现时常见做法是在发送侧维护poll计时器和poll计数器当连续发送的PDU数量达到pollPDU或字节数达到pollByte时在下一个AMD PDU上置P字段为1请求对端回状态报告。发送侧容易出错的地方在于状态PDU里只带ACK_SN和NACK_SN列表NACK粒度可以是SN级别也可以是SO段级别。如果用的是SO段级别NACK重传时只重发未确认的SO段而不是整个PDU。这部分逻辑在36.322的5.2.1里写得很细但落到代码时很容易把重传整个PDU和重传SO段混在一个分支里。python # 发送侧AMD PDU生成的关键状态推进伪码 vt_s last_sn 1 # 下一个新传SN vt_a highest_acked_sn # 对端确认的最大SN # 发送一个AMD PDU def send_amd_pdu(sdu_segment, vt_s): pdu build_amd_header(snvt_s, poll_bitshould_poll()) pdu.payload sdu_segment retx_buffer[vt_s] pdu # 进重传缓存 vt_s 1 return pdu这段伪码对应的是发送侧最小流程。vt_s在每个新传时递增重传缓存以SN为索引保存PDU收到状态报告后再把对应条目清掉。关键字是retx_buffer如果高层新数据到达你却把缓存写成覆盖式那AM的重传就名存实亡了。3.2 接收侧状态变量与t-Reordering定时器的联动接收侧一眼看过去有VR(R)、VR(MR)、VR(X)、VR(MS)好几个变量实际上只需要抓住三个核心VR(R)是下一个期望按序递交的SNVR(MR)是接收窗的上界等于VR(R)加窗口大小VR(X)是在t-Reordering启动时记录的那个缺失SN。当收到一个SN大于等于VR(R)的PDU时先丢进重排缓存再检查它是否等于VR(R)。如果大于VR(R)说明中间有缺失PDU此时启动t-Reordering记录VR(X)为当前缺失值在t-Reordering超时前后续到的乱序PDU都停在缓存里不递交超时后如果缺的那个还没来就把VR(R)之前能连续递交的PDU全部上报给PDCP再对缺失部分触发状态报告请求对端重传。t-Reordering的取值是接收侧吞吐抖动的关键。设小了乱序还没等齐就先把缺口报出去对端立刻重传造成不必要的空口资源浪费设大了真的丢包时要干等超时TCP层感知到RTO超时开始慢启动吞吐悬崖式下跌。业内常见配置是20ms到40ms之间但高速场景下有经验的工程师会按调度周期和HARQ反馈的来回时延去推算而不是直接用默认值。3.3 关键参数表pollPDU、pollByte对吞吐和时延的影响pollPDU和pollByte是AM发送侧最常调的协议参数它们在RRC配置里由eNB下发给UE。pollPDU表示每发多少个AMD PDU就置一次P字段pollByte表示累计发多少字节就置一次P字段。两者是或关系任一条件满足就触发poll。参数设置方向影响pollPDU 1每个PDU都poll反馈最及时但空口上行消息开销大pollPDU 8每8个PDU poll一次平衡反馈时延和开销常用pollByte 0禁用字节维度触发小包场景可能长时间无pollt-Reordering15ms~40ms决定乱序容忍度和丢包感知速度MAX_RETX_THRESHOLD网络侧配置超过后触发RLF需谨慎设实际调优时我一般先看空口环境。信道质量好、误块率低时pollPDU可以放大到16或32减少上行反馈开销信道差时反而要调小poll间隔让对端尽快感知缺失并重传。pollByte在纯语音小包场景意义不大视频大包场景要改成和分段大小匹配的数值。4. 从英文规范到中文实现笔记整理一份自己能复现的协议要点对着36.322原文啃RLC最大的阻力不是英文而是叙述顺序。规范先讲抽象模型再讲字段格式最后才讲状态迁移和实现者的思路正好相反。常见做法是先抓分段、级联、填充三个动作再做比特级拆解最后固化成自己的中文笔记。4.1 先抓协议正文里的三个动分段、级联、填充RLC对SDU做的事可以概括成三个动词。分段发生在SDU大小超过当前MAC可用的TB大小时把SDU切段每段挂上RLC头级联发生在多个SDU都小于剩余空间时把几个小SDU装进同一个RLC PDU填充发生在分段加级联后还剩少量字节时用Padding字节补齐。理解这三个动作才能看懂MAC的调度反馈。MAC的DCI grant给多少字节RLC就按这个字节数裁剪PDU。所以RLC实现里都有一个Segment Buffer记录当前正在分段的SDU在上下文中位的位置。常见翻车点是在AM模式下重分段re-segment)时忘了保存原始SN导致网络侧按段号找不到归属的父PDU。4.2 把每一条字段定义转成比特级注释——用AM PDU解析示例AMD PDU头至少包含D/C字段1bit、RF字段1bit、P字段1bit、SI字段2bit、SN字段10bit。如果是重分段RF1后面还要跟LSF字段1bit和SO字段15bit。这些字段的位宽和顺序在36.322第6.2.1.3节有表格实现时最容易错的是bit序——3GPP的图是高位在前和常用CPU的小端序正好相反暴力读raw bits会全部错位。# AMD PDU头解析10bit SN非重分段 def parse_amd_header(raw_byte0, raw_byte1): dc (raw_byte0 7) 0x01 rf (raw_byte0 6) 0x01 p (raw_byte0 5) 0x01 si (raw_byte0 3) 0x03 sn ((raw_byte0 0x07) 7) | (raw_byte1 0x7F) return dc, rf, p, si, sn代码里的关键在读位顺序rf在最前面sn跨两个字节。注释里我已经标明这是10bit SN所以低7位取第二字节的0x7F。如果业务配置的是12bit SN这个函数的掩码和移位要全部重算——这是改协议版本时最常见的翻车点。4.3 维护一份中文协议自己该怎么组织——哪些必抄、哪些可省把36.322整理成能用的中文资料不需要逐字翻译。我一般会拆成四张表状态变量表VT(A)/VT(S)/VR(R)/VR(MR)等、PDU字段对照表AMD/UMD/STATUS/饥饿状态、状态迁移表每种事件引发的动作和参数速查表网络侧RRC下发的RLC配置项。表格里标注规范原文章节号留一列写实现备注记录踩过坑的位序、边界条件。状态迁移表才是最值钱的部分。规范里的状态机图是给设计者看的实现者更需要的是事件到动作的映射收到ACK、收到NACK、t-Reordering超时、poll计时器到期每一个事件对应哪些变量要更新、哪些PDU要发出去。把这张表做出来中文协议就脱离翻译文档的层面成为自己能维护的实现手册了。5. 避坑RLC实现中绕不开的五个真实问题做RLC调试有些问题是规范里写了但你不会留意的有些是规范没写全靠血泪验证的。下面按现象、原因、解决的顺序记录五条高频踩坑经验。一、状态报告丢失后发送侧窗口卡死。现象是下行速率突然降为0稍后自行恢复。原因是AM发送侧发了poll但状态PDU在网络中丢失发送侧不知道哪些PDU被确认不敢推进窗口、也不敢发新PDU。解决方法是发送侧必须启动poll重传定时器t-PollRetransmit在定时器超时且仍未收到状态PDU时重新发起poll。这个定时器在RRC配置里有不少实现默认值偏大建议按RTT的两倍去设。二、SN绕回时用大小比较判断窗口导致一切错乱。现象是长时间高速业务后出现大面积重传和重复递交。原因是RLC SN只有10bit或12bit达到1024或4096后绕回0如果你用sn window_boundary做判断绕回后就完全失效。解决方法是严格按规范用(sn - VR(R)) mod 2^bitwidth做窗口内判断且只允许窗口最大为SN空间的一半绕回时配合HFN超帧号来区分前后代。三、t-Reordering配错导致VoIP通话断续。现象是RTP包在语音解码时有周期性丢字但空口统计BLER很低。原因是VoIP走UM模式UM也配了t-Reordering乱序包在缓冲里等待超时超时前即使后到的包也无法递交。解决方法是VoIP场景把t-Reordering设到一个调度周期以内或者直接配置为0让乱序包立即递交依靠解码器的抖动缓冲去消化乱序。四、重分段后NACK的SO字段与父PDU对应错位。现象是上行重传大幅增加且目标基站反馈CRC错误。原因是AMD PDU被MAC分多次调度后接收侧在状态报告里用SOSegment Offset指向缺失段如果发送侧处理重分段时错误地把SDU内偏移当成PDU内偏移重传的段就对不上。解决方法是重分段时用SO 原始PDU中数据段的起始字节偏移并且在驱动里把父PDU的SN、原始大小和SO存成三元组。五、RLC和MAC的HARQ双重重传。现象是重传率达到10%以上但有效吞吐没有明显下降。很多人以为RLC和HARQ重传的是同一个数据包其实MAC重传的是HARQ进程里同一个传输块RLC重传的是逻辑信道上的PDU两者是不同层。问题是当HARQ重传把数据块推给RLC时RLC如果已经收到对端NACK就会重复发同一个PDU导致接收侧重复检测PDU反复触发。解决方法是确认HARQ反馈与RLC状态反馈的时间差配置HARQ最大重传次数略大于RLC的poll间隔让RLC在HARQ还在抢救时不至于过早重传。6. 验证手段与进阶技巧用一个最小仿真把轮转计数器和窗口推进跑通RLC的调试不适合只靠空口实测因为空口变量太多很难把SN绕回和窗口推进的边界复现出来。我一般会用一段本地仿真代码把发送侧和接收侧的状态机跑一遍专门验证绕回和边界条件再把结论带回实网测试。6.1 用python模拟SN 12bit轮转和窗口滑动SN_BITS 12 WINDOW_SIZE 512 # 最大不超过2^(SN_BITS-1) vr_r 0 vr_mr (vr_r WINDOW_SIZE) % (1 SN_BITS) def in_receive_window(sn, vr_r, vr_mr, bits12): n 1 bits if vr_r vr_mr: return vr_r sn vr_mr # 绕回场景 return sn vr_r or sn vr_mr # 模拟SN从4090开始收到4094窗口正常 for sn in [4090, 4091, 4092]: assert in_receive_window(sn, vr_r, vr_mr) # 模拟SN绕回到2判断是否在窗口内 assert in_receive_window(2, vr_r, vr_mr) # 窗口后半部分在窗内这段代码的逻辑关键是vr_r vr_mr时不用取模比较绕回时才需要分开判断。实际开发中如果直接照搬上面的简单判断会漏掉vr_r等于vr_mr的边界——规范里窗口大小永远不会等于SN空间一半所以不会出现相等。参数注释里建议把WINDOW_SIZE写进配置方便模拟不同的基站配置。6.2 参数边界验证什么时候t-Reordering会引发吞吐瞬时掉零另一个值得仿真的是t-Reordering对吞吐的瞬时冲击。把乱序包到达时间设为正态分布t-Reordering设成不同值可以看到包在缓存中滞留的时长和缺口重传的时延是此消彼长的关系。实网上如果调度周期是2ms、HARQ RTT约8mst-Reordering设到20ms是安全区间低于10ms会频繁触发不必要的重传高于50ms则会让TCP把RTO放大到200ms级别。我个人的习惯是每次修改完RRC的RLC参数后先用这段仿真跑一遍边界再上车实测。这样能在进实验室前过滤掉纯逻辑错误到实网上只关注空口固有的随机性。协议规范里没有调试口诀这种东西但你把这些边界条件做成自己的清单之后RLC就不再是玄学。实网验证时也别只盯着吞吐记得看终端上报的PDCP层SDU丢弃率——RLC的乱序重传一旦失控PDCP层的丢弃计数器会先于吞吐指标报警。这算是我的个人教训希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站