
简介这份文档面向移动通信网络优化与测试工程师聚焦LTE切换流程中的S1数据转发机制帮助读者理解并验证切换期间用户面数据的连续性保障方法。内容围绕数据流向变化、TEID与Sequence Number的作用、目标eNodeB资源接纳与HANDOVER REQUEST ACKNOWLEDGE消息参数展开并重点梳理End Marker发送时机、源小区与目标小区数据传送地址及转发地址的切换检查点配合切换全流程信令概述便于对照抓包定位问题。资源包共1个docx文件约769KB以文字与信令流程说明为主适合作为测试小结或排错参考。已有306人学习下载可供从事切换测试、用户面转发验证的读者快速建立检查思路并结合网络拥塞、延迟与错误处理场景补充验证。1. S1 数据转发切换时那条“最后一包”为什么能决定用户面生死一次 LTE 切换里最容易被忽略、又最容易翻车的不是信令而是用户面那几毫秒的数据流向。很多人以为切换就是“源小区断、目标小区接”实际上中间存在一段双通道并存的窗口下行数据一边还在从服务网关往源基站送一边已经开始往目标基站灌。如果这段窗口处理不好用户看到的就是视频卡一下、下载断一截甚至 TCP 直接进拥塞控制。S1 data forwarding 要解决的核心问题只有一个在切换执行期间把源侧还没送出去、以及还在路上飞的数据一包不丢地交到目标侧手里。而这条链路的收尾信号就是那个看起来平平无奇的 End Marker 包。搞懂它就搞懂了切换用户面为什么能“无缝”。2. 数据流向的三段式为什么切换中要绕回服务网关2.1 切换前、切换中、切换后的路径变化把 S1 数据转发拆开看用户面路径其实经历了三个明确阶段。切换前下行数据走的是服务网关到源基站的 S1 承载源基站再通过空口发给终端这时候目标基站完全不在数据路径上。切换执行开始后路径变成服务网关先把数据送到源基站源基站再通过转发隧道送到目标基站目标基站缓冲起来等终端接入。切换成功后服务网关直接把数据送到目标基站源基站彻底退出。这个“绕一下”的设计不是多余。切换命令下发到终端真正接入目标小区之间存在一段终端与源小区已断开、与目标小区尚未同步的空窗期。如果服务网关此时直接切到目标基站目标基站拿不到终端上下文数据只能丢如果继续只发源基站源基站空口已断数据同样发不出去。所以必须有一个中间态源基站把收到的数据通过 X2 或 S1 转发隧道交给目标基站暂存等终端一接入就立刻补发。这就是 data forwarding 存在的根本理由。2.2 转发隧道与传送隧道的区别这里有个特别容易混淆的点目标基站会分配两类地址一类是数据传送地址一类是数据转发地址。传送地址是切换完成后服务网关直接向目标基站发用户面数据的 GTP 隧道端点转发地址是切换过程中源基站把数据转给目标基站用的隧道端点。两者在 GTP-U 层是两个不同的 TEID对应不同的隧道上下文。从测试记录里能看得很清楚源小区数据传送地址是 0x01001008切换准备阶段源侧转发地址是 0x0000115b目标侧转发地址是 0x01000a09切换完成后目标小区数据传送地址是 0x01000a08。四个地址对应四个不同的隧道端点任何一个配错数据就会进错管道。常见的实现思路是基站在 HANDOVER REQUEST ACKNOWLEDGE 里把目标侧传送地址和转发地址一起带给源侧源侧据此建立转发隧道同时保留原传送隧道直到 End Marker 到达。2.3 End Marker 的角色不是数据是句号End Marker 包本身不携带任何用户数据它的 GTP-U 载荷为空只带一个标记。服务网关在把下行路径从源基站切到目标基站之前先向源基站发一个 End Marker意思是“这是我通过这条旧隧道发的最后一个包了”。源基站收到后把它转发给目标基站然后就可以停掉自己的转发任务。目标基站收到 End Marker也就知道源侧不会再送数据过来了可以安心把缓冲队列按序交给终端。这个机制解决的是一个顺序问题如果没有 End Marker目标基站无法判断源侧转发什么时候结束可能过早释放转发上下文导致尾部数据丢失也可能一直等下去造成资源悬挂。用一个空包做显式终止符比靠定时器猜要可靠得多。我一般会把它理解成用户面的“半关闭”信号和 TCP 的 FIN 在语义上是一个思路。3. TEID 与 Sequence NumberGTP 隧道里谁负责找路、谁负责排队3.1 TEID 是隧道的门牌号GTP-U 头里的 TEID 是 Tunnel Endpoint Identifier接收侧靠它把包分发给正确的承载上下文。一个基站上可能同时存在几十上百个 GTP 隧道每个隧道的 TEID 在本地唯一标识一个端点。S1 接口上上行和下行各有一个 TEID由接收侧分配、发送侧使用。切换过程中之所以要重新分配目标侧 TEID就是因为隧道端点从源基站换到了目标基站旧 TEID 在新节点上没有意义。测试里核对 TEID 是排查转发问题的第一手段。如果源侧转发用的目标 TEID 和目标侧实际分配的转发 TEID 对不上包会被目标基站直接丢弃表现就是切换后目标侧收不到任何转发数据但信令流程一切正常。这种问题只看信令日志是看不出来的必须抓用户面包比对 GTP 头。3.2 Sequence Number 保证不乱序GTP-U 的 sequence number 是可选的但在切换转发场景里通常会启用。原因很直接转发路径和直传路径可能短暂并存目标基站会同时收到来自源侧转发的包和切换后服务网关直发的包如果没有序号无法判断先后。序号让接收侧可以按序递交把转发来的尾部数据和直传的新数据拼接起来。下面这段伪代码展示了一个典型的接收侧处理逻辑重点在 End Marker 和序号的配合def handle_gtpu_packet(pkt, tunnel_ctx): # 按 TEID 找到对应承载上下文 if pkt.teid ! tunnel_ctx.expected_teid: drop(pkt) # TEID 不匹配直接丢弃 return if pkt.is_end_marker: # 收到终止符标记转发路径结束 tunnel_ctx.forwarding_done True tunnel_ctx.reorder_buffer.flush() # 把缓冲的尾部数据按序交出 release_forwarding_tunnel(tunnel_ctx) return # 普通数据包按序号插入重排缓冲 tunnel_ctx.reorder_buffer.insert(pkt.seq, pkt.payload) deliver_in_order(tunnel_ctx.reorder_buffer)这段逻辑里TEID 校验放在最前面因为它是分发的前提End Marker 分支不碰数据缓冲的插入逻辑只触发 flush 和隧道释放普通包走重排缓冲。参数上expected_teid 来自切换准备阶段协商的结果reorder_buffer 的深度决定了能容忍多大的乱序窗口。实际实现里还要处理序号回绕和重复包但骨架就是这三步。3.3 转发地址和传送地址在包头的体现抓包时区分一个包走的是转发隧道还是传送隧道看的就是目的 TEID 和目的 IP。切换准备完成后、HANDOVER NOTIFY 之前源基站发出的用户面包目的地址应该是目标侧转发地址HANDOVER NOTIFY 之后服务网关发出的包目的地址应该是目标侧传送地址。如果在这个时间边界上看到目的地址没切换或者切换早了就说明路径更新逻辑有问题。测试记录里把 0x01000a09 和 0x01000a08 分开标注正是为了在抓包里一眼看出当前处于哪个阶段。4. 切换信令与承载接纳目标侧地址是怎么传到源侧的4.1 从 HANDOVER REQUEST 到 ACKNOWLEDGE 的参数传递整个切换准备阶段的核心是目标基站把“我这边准备好了地址是这些”告诉源基站。流程上源基站先发 HANDOVER REQUIRED 给 MMEMME 再发 HANDOVER REQUEST 给目标基站。目标基站做完接纳控制如果资源满足、小区允许接入就回 HANDOVER REQUEST ACKNOWLEDGE。这个 ACK 里带的关键参数包括目标侧分配的 eNB UE S1AP ID以及每个接纳成功的 EPS 承载对应的目标侧数据传送地址和转发地址。源基站收到 HANDOVER COMMAND由 MME 转发后从里面解析出这些地址才知道往哪儿转发。这里的设计动机是把地址分配权交给接收侧目标基站最清楚自己哪个小区、哪个隧道端点可用由它分配再回传比源侧猜要可靠。代价是准备阶段多了一次往返但换来了地址的唯一性和一致性。4.2 接纳控制失败时会发生什么如果目标基站资源不足它不会回 ACKNOWLEDGE而是回 HANDOVER PREPARATION FAILURE。源基站收到后不会下发切换命令终端继续留在源小区。这时候不会发生任何数据转发因为转发隧道根本没建立。测试时要区分“切换准备失败”和“切换执行失败”前者是目标侧没接纳用户面完全没动后者是命令已下发但终端接入失败可能已经有一部分数据被转发过去需要回滚。4.3 状态转移与资源释放的时序切换执行后期源基站发 eNB STATUS TRANSFERMME 转成 MME STATUS TRANSFER 给目标基站把 PDCP 状态传过去保证未确认的数据能续传。目标基站收到终端发来的 RRC CONNECTION RECONFIGURATION COMPLETE 后发 HANDOVER NOTIFY 给 MME宣告终端已成功接入。MME 随后通知服务网关更新下行路径服务网关开始向目标侧传送地址发数据同时向源侧发 End Marker。最后 MME 发 UE CONTEXT RELEASE 给源基站源基站释放资源。这个时序里HANDOVER NOTIFY 是路径切换的触发点End Marker 是旧路径的终止点UE CONTEXT RELEASE 是源侧资源回收点。三个点顺序不能乱如果 End Marker 在路径更新前就到源侧源侧可能提前停转发导致尾部数据丢如果资源释放早于 End Marker转发隧道被拆同样丢包。5. 避坑与排查转发测试里最容易翻车的几个点5.1 现象切换后目标侧收不到任何转发数据信令全绿原因通常是源侧使用的目标转发 TEID 和目标侧实际分配的不一致。信令日志里 ACKNOWLEDGE 带的地址是一个值源侧配置或解析成了另一个值包发出去被目标侧按 TEID 不匹配丢弃。解决方法是同时抓 S1 信令和用户面包把 ACKNOWLEDGE 里的 TEID 和实际发出包的 GTP 头逐一对齐重点看是否有字节序或字段偏移解析错误。5.2 现象切换完成后终端收到重复包或乱序包原因是转发路径和直传路径并存期间序号重排没做好或者 End Marker 到达前缓冲就被 flush 了。表现是应用层看到重复 TCP 段或序列跳变。排查时看目标侧重排缓冲的深度配置和 flush 触发条件确认 End Marker 处理分支没有提前释放缓冲。解决思路是让 flush 严格由 End Marker 或明确的路径切换事件触发不靠定时器兜底。5.3 现象源侧转发隧道一直不释放资源悬挂原因是 End Marker 丢了或者没被识别。GTP-U 的 End Marker 是带特定标记的空包如果中间设备或解析逻辑把它当普通空包丢弃源侧就永远等不到终止信号。排查时在源侧入口抓包确认是否收到 End Marker再看解析代码是否检查了对应标志位。解决方法是加一个兜底定时器但定时器只做告警不做正常释放正常路径仍以 End Marker 为准。5.4 现象切换准备成功但执行阶段数据大量丢失常见于转发地址和传送地址配反。源侧把数据发到了目标侧传送地址而不是转发地址目标侧在终端接入前没有对应上下文包全丢。核对方法是按时间线看目的地址HANDOVER NOTIFY 之前必须是转发地址之后才是传送地址。测试记录里把两类地址分开标注就是为了这种边界排查。提示排查转发问题永远信令和用户面一起抓只看信令会漏掉 TEID 和地址层面的错配只看用户面又不知道当前处于哪个信令阶段。6. 设计取舍为什么用显式 End Marker 而不是靠定时器End Marker 这个机制本质上是用一个带内信号替代带外超时判断。定时器方案实现简单但参数极难调设短了尾部数据还在路上就把转发上下文拆了丢包设长了每次切换都多占一份资源高负载下累积起来很可观。更麻烦的是定时器无法区分“对端真的发完了”和“网络暂时拥塞”在拥塞场景下必然误判。显式 End Marker 把终止判断交给发送侧接收侧只需要被动响应语义明确、时序确定代价只是多一个空包的开销。这个取舍背后是一个更普遍的原则跨节点的状态同步能用显式信号就别用隐式超时。超时是猜测信号是事实。当然显式信号也有代价就是信号本身可能丢所以工程实现里通常保留一个远大于正常时延的兜底定时器只用于异常告警和最终回收不参与正常流程。我一般会把这个兜底值设成正常转发时延的十几倍确保它永远不会在正常场景下触发。验证这套机制是否工作正常最直接的办法是在实验室里构造三种场景正常切换看 End Marker 是否按序到达并触发释放人为丢弃 End Marker 看兜底是否生效且不误伤在转发期间注入乱序包看重排缓冲是否正确拼接。三种场景都过基本可以认为转发路径的实现是可信的。从那以后我每次做切换相关的用户面验证都会先把这四个地址和 End Marker 的时序在抓包里标出来再谈性能。希望帮到你。本文还有配套的精品资源点击获取