ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

QINQ配置避坑指南:从TPID不匹配到隔离失效的实战排错

QINQ配置避坑指南:从TPID不匹配到隔离失效的实战排错

1. 从一个真实的翻车现场说起:为什么QINQ不是"配一下就行"

刚接手园区网改造那会儿,我天真地以为QINQ就是个"外层套内层"的简单活儿。结果第一次上线就翻车了——客户那边反馈说财务部门和研发部门突然能互相访问了,而这两个部门在规划里是必须隔离的。排查了整整一个下午,最后发现问题出在QINQ的TPID值没对齐:核心交换机用的是默认的0x8100,而接入层某台设备被我改成了0x88A8,两层标签在转发过程中被设备"误解"了,外层标签直接被剥掉,隔离策略形同虚设。

这件事让我彻底明白一个道理:QINQ(802.1Q-in-802.1Q,也叫Stacked VLAN或Double VLAN)看起来只是"多打一层标签",但它牵扯到TPID协商、MTU调整、端口类型匹配、外层VLAN规划、广播域边界等一系列连锁问题。任何一个环节没对齐,轻则业务不通,重则隔离失效、环路风暴。

这篇文章适合三类人看:一是刚接触运营商级以太网或园区多租户场景的网工,二是需要给客户做VLAN扩展但被4094个VLAN ID卡住的技术支持,三是想搞清楚QINQ底层转发逻辑、不想只会敲命令的进阶读者。我会从"为什么需要QINQ"讲起,把TPID、端口角色、标签压栈/弹栈的完整链路拆开,再给出一套可以直接抄作业的配置模板和排错清单。全文基于我这些年做过的几个多租户园区和城域接入项目整理,涉及具体设备的地方我会用通用命令格式,不同厂商的差异我会单独标注。

先给一个最直观的理解:普通VLAN就像给包裹贴一张快递单,QINQ就是在这个包裹外面再套一个大箱子,箱子上再贴一张单子。内层单子(C-Tag,Customer Tag)是用户自己的VLAN信息,外层单子(S-Tag,Service Tag)是运营商或核心网用来区分不同客户/不同区域的。核心网只认外层单子,用户的内层单子对它透明——这就是QINQ最核心的价值:让核心网用少量S-VLAN承载海量C-VLAN,突破4094的数量天花板。

2. QINQ的标签结构:TPID、优先级、VLAN ID到底怎么排布

2.1 一个以太帧被"套两层"之后长什么样

要配好QINQ,必须先能在大脑里"看见"帧结构。普通802.1Q帧是在源MAC之后插入4字节的Tag,结构是TPID(2字节)+ Priority(3bit)+ CFI/DEI(1bit)+ VLAN ID(12bit)。QINQ就是在这个Tag前面再插一个4字节的外层Tag,形成"外层Tag + 内层Tag + 原始载荷"的结构。

用文字画出来大概是这样:

| 目的MAC | 源MAC | 外层TPID | 外层PCP | 外层DEI | 外层VID | 内层TPID | 内层PCP | 内层DEI | 内层VID | 类型/长度 | 载荷 |

这里有几个关键点容易被忽略:

  • 外层TPID默认是0x8100,但很多运营商场景要求用0x88A8(这是802.1ad标准定义的S-Tag TPID)。如果两端设备TPID不一致,设备可能无法识别外层标签,直接当普通帧处理。
  • 外层VLAN ID(S-VID)是核心网转发依据,通常由运营商或核心层规划,范围一般避开用户常用段。
  • 内层VLAN ID(C-VID)是用户自己的,对核心网透明,可以重复使用。
  • PCP(Priority Code Point)在外层和内层都有,QoS策略到底看哪一层,取决于设备配置,这个后面会专门讲。

2.2 TPID不匹配:最隐蔽也最致命的坑

我前面提到的翻车现场,根因就是TPID。不同厂商对TPID的处理策略不一样:有的设备收到TPID不匹配的帧直接丢弃,有的会尝试解析,有的会当普通帧转发。更麻烦的是,有些设备默认只认0x8100,你配了0x88A8它也不报错,但实际转发时行为诡异。

我的经验是:在规划阶段就把TPID当成一个必须书面确认的参数,写进对接文档里。核心层、汇聚层、接入层三层的TPID必须统一,或者至少保证"打标签的设备"和"剥标签的设备"TPID一致。如果中间有第三方设备透传,还要确认它是否会把TPID改掉。

提示:部分厂商的QINQ端口可以配置tpid参数,命令类似qinq tpid 88a8。配置后务必用抓包工具验证实际发出的帧TPID是否正确,不要只看配置回显。

2.3 MTU:被两层标签"撑大"的帧

普通以太帧MTU是1500字节,加一层VLAN Tag变成1504,加两层变成1508。如果链路上有设备MTU卡在1500,这些"超长帧"就会被丢弃。表现是:小包ping通,大包不通,或者TCP能建连但传文件卡死。

这个问题在QINQ场景里特别常见,因为很多默认配置的接口MTU就是1500。解决办法是把QINQ路径上所有接口的MTU调大,一般建议至少设到1518或1522,留出余量。命令通常是mtu 1522或jumbo-frame相关配置,具体看厂商。

我踩过的坑是:只调了核心层,忘了接入层。结果用户侧小流量正常,一跑备份任务就断。后来养成习惯,QINQ上线前先用大包ping做端到端验证,命令类似ping -s 1500 -M do(Linux)或设备自带的带包长ping功能。

3. 端口角色与标签处理:Access、Trunk、Hybrid在QINQ里怎么选

3.1 四种端口角色在QINQ场景下的分工

普通VLAN里我们熟悉Access、Trunk、Hybrid三种端口。到了QINQ,还要引入"QINQ隧道端口"和"QINQ上联端口"的概念。不同厂商叫法不同,但逻辑是一致的:

端口角色位置对标签的处理典型配置
用户接入端口靠近用户侧给未标记帧打内层C-TagAccess或QINQ access
QINQ隧道端口接入设备上联给已带C-Tag的帧再打外层S-Tagqinq enable+ 外层VLAN
QINQ上联/核心端口核心设备识别并剥离外层S-TagTrunk允许S-VLAN
透传端口中间设备不处理双层标签,直接转发需确认MTU和TPID

这里最容易出错的是用户接入端口。如果用户设备自己会发带Tag的帧(比如用户侧有支持802.1Q的交换机),那接入端口就不能再打C-Tag,否则会变成三层标签。这时候要么把用户端口配成"信任已有Tag",要么让用户侧改成untagged。

3.2 灵活QINQ vs 基本QINQ:什么时候该用哪个

基本QINQ(也叫普通QINQ)的逻辑很简单:一个端口进来的所有帧,不管内层VLAN是多少,统一打同一个外层S-VLAN。适合"一个客户一个S-VLAN"的简单场景。

灵活QINQ(Selective QINQ)则可以根据内层VLAN ID、优先级等条件,映射到不同的外层S-VLAN。比如客户有VLAN 10、20、30,你可以配置成VLAN 10→S-VLAN 100,VLAN 20→S-VLAN 200,VLAN 30→S-VLAN 300。适合"一个客户多个业务需要不同外层标识"的场景。

选型建议:

  • 如果客户数量少、每个客户业务单一,用基本QINQ,配置简单,排错容易。
  • 如果客户数量多、或者需要按业务类型做外层区分,用灵活QINQ,但配置复杂度上升,要维护映射表。
  • 如果客户自己也要做VLAN隔离,且希望核心网只看到外层,基本QINQ就够了。

我个人的偏好是:能用基本QINQ解决的就别上灵活QINQ。灵活QINQ的映射表一旦写错,排查起来非常痛苦,因为你要同时核对内层、外层、映射规则三层逻辑。

3.3 一个完整的标签压栈/弹栈链路

假设用户A的PC发出一个untagged帧,要经过接入交换机、汇聚交换机、核心交换机,最终到达用户B。整个过程是这样的:

  1. 接入交换机用户端口:收到untagged帧,打上内层C-Tag(比如VID 10),变成单层Tag帧。
  2. 接入交换机QINQ隧道端口:收到单层Tag帧,再打上外层S-Tag(比如VID 1000),变成双层Tag帧。
  3. 汇聚/核心设备:只识别外层S-Tag 1000,根据S-VLAN转发,内层VID 10对它透明。
  4. 对端接入交换机QINQ隧道端口:剥离外层S-Tag 1000,恢复成单层Tag帧。
  5. 对端用户端口:剥离内层C-Tag 10,发出untagged帧给用户B。

这个链路里,每一跳的端口角色和标签处理必须严格对应。如果中间某台设备把双层帧当单层处理,外层标签就会被误读成内层,转发就乱了。

4. 配置实战:一套可以直接抄的QINQ模板

4.1 规划阶段要定下来的五件事

在敲任何命令之前,先把这五件事定下来,能省掉后面80%的返工:

  1. S-VLAN范围:核心网用哪些VLAN ID做外层,避开用户可能用到的段。建议单独划一段,比如2000-3000。
  2. TPID值:全链路统一,默认0x8100还是0x88A8,书面确认。
  3. MTU值:全链路统一调大,建议1522以上。
  4. 端口角色表:哪个端口是用户口、哪个是隧道口、哪个是上联口,画个表。
  5. C-VLAN到S-VLAN映射:如果用灵活QINQ,映射关系提前列好。

4.2 接入交换机配置示例

以下命令是通用格式,不同厂商关键字可能不同,但逻辑一致:

# 创建外层S-VLAN vlan 1000 description QINQ_SVLAN_CustomerA # 配置用户接入端口 interface GigabitEthernet0/1 switchport mode access switchport access vlan 10 description User_Port # 配置QINQ隧道端口(上联) interface GigabitEthernet0/24 switchport mode trunk qinq enable qinq svlan 1000 switchport trunk allowed vlan 10 description QINQ_Tunnel_Port mtu 1522

关键点说明:

  • qinq enable是开启QINQ功能的总开关,不同厂商可能叫qinq、dot1q-tunnel等。
  • qinq svlan 1000指定外层S-VLAN,有的设备是在端口下配,有的在全局配。
  • switchport trunk allowed vlan 10是允许内层C-VLAN 10通过,注意这里允许的是内层VLAN。
  • mtu 1522是给双层标签留余量。

4.3 核心交换机配置示例

核心设备主要负责识别和转发外层S-VLAN:

# 创建外层S-VLAN vlan 1000 description QINQ_SVLAN_CustomerA # 上联端口(连接接入交换机) interface GigabitEthernet0/1 switchport mode trunk switchport trunk allowed vlan 1000 mtu 1522 description To_Access_Switch # 下联端口(连接其他核心或出口) interface GigabitEthernet0/2 switchport mode trunk switchport trunk allowed vlan 1000 mtu 1522 description To_Core_Uplink

核心设备通常不需要开qinq enable,它只需要把外层S-VLAN当普通VLAN转发即可。但前提是它认识外层TPID,如果TPID是0x88A8,有些设备需要额外配置才能识别。

4.4 灵活QINQ的映射配置

如果要做C-VLAN到S-VLAN的灵活映射,配置会复杂一些:

interface GigabitEthernet0/24 qinq enable qinq mapping vlan 10 svlan 1000 qinq mapping vlan 20 svlan 2000 qinq mapping vlan 30 svlan 3000 mtu 1522

这段配置的意思是:内层VLAN 10的帧打外层1000,内层VLAN 20的打外层2000,以此类推。映射表一定要和规划文档逐条核对,我见过因为映射写反导致整个客户业务跑到另一个S-VLAN里的案例。

4.5 验证命令与预期结果

配完之后别急着交付,按这个清单验证:

验证项命令示例预期结果
端口QINQ状态show qinq interface隧道端口显示enable
S-VLAN学习show mac address-table vlan 1000能看到用户MAC
大包连通性ping -s 1500不丢包
标签抓包镜像端口抓包外层TPID正确
隔离验证跨S-VLAN ping不通

注意:抓包验证是最可靠的手段。配置回显只能说明"命令生效了",不能说明"帧真的按预期打了标签"。我习惯在隧道端口做镜像,用抓包工具确认外层TPID、S-VID、内层C-VID三个字段都对。

5. 排错实录:QINQ不通时我按这个顺序查

5.1 第一层:物理与链路状态

先看端口up没up、有没有CRC错误、光衰是否正常。这听起来很基础,但我遇到过好几次"QINQ配了半天不通",最后发现是光纤跳线松了。排错要从最底层开始,不要一上来就怀疑配置。

5.2 第二层:TPID与MTU一致性

如果物理层正常,下一步查TPID和MTU。方法:

  • 在隧道端口抓包,看外层TPID是0x8100还是0x88A8。
  • 对比两端设备的TPID配置。
  • 用带包长的ping测试MTU,从1400开始逐步加大,找到丢包的临界点。

我整理过一个快速判断表:

现象可能原因排查动作
小包通大包不通MTU不足调大路径MTU
完全不通报错TPID不匹配抓包对比TPID
时通时不通环路或MAC漂移查MAC表和STP
能通但隔离失效外层标签被剥查端口角色

5.3 第三层:端口角色与VLAN允许列表

确认隧道端口是否真的开了QINQ,上联端口是否允许了正确的S-VLAN。这里有个常见错误:在Trunk端口上只允许了内层C-VLAN,忘了允许外层S-VLAN。结果就是外层标签到了上联口被丢弃。

5.4 第四层:映射表与转发路径

如果是灵活QINQ,逐条核对映射表。如果是多台设备级联,确认每一跳的端口角色都对。我习惯画一张转发路径图,把每个节点的"入标签→出标签"标出来,一眼就能看出哪里断了。

5.5 一个真实的排查案例

某次客户反馈"QINQ配好后,A楼能通B楼,但A楼通C楼不通"。我按上面的顺序查:

  1. 物理层正常。
  2. 抓包发现A楼发出的帧外层TPID是0x88A8,但C楼侧设备只认0x8100。
  3. 查配置发现C楼侧设备是另一批次的型号,默认TPID不同。
  4. 把C楼侧设备TPID改成0x88A8,问题解决。

这个案例说明:同一网络里混用不同批次、不同型号的设备时,TPID默认值可能不一致,必须逐台确认。

6. 几个容易被忽略的进阶细节

6.1 QoS优先级到底看外层还是内层

QINQ场景下,外层和内层都有PCP字段。设备在做QoS调度时,到底信任哪一层,取决于配置。有的设备默认信任外层,有的可以配置成信任内层。如果客户希望自己的优先级标记被尊重,就要配置成信任内层PCP;如果核心网要统一调度,就信任外层。

我的建议是:在核心网侧统一信任外层PCP,由接入设备根据内层PCP映射到外层PCP。这样核心网策略简单,用户侧也有一定的自主权。

6.2 广播域与环路防护

QINQ虽然扩展了VLAN数量,但广播域的本质没变。一个S-VLAN就是一个广播域,如果同一个S-VLAN下有环路,照样会风暴。所以STP、环路检测这些机制该开还得开。另外,不同客户的S-VLAN必须隔离,不能因为图省事把多个客户映射到同一个S-VLAN。

6.3 和VLAN Translation的区别

有人会把QINQ和VLAN Translation(VLAN映射/转换)搞混。简单说:QINQ是"加一层",帧变成双层标签;VLAN Translation是"换一个",帧还是单层标签,只是VID被替换了。两者解决的问题不同:QINQ解决VLAN数量扩展,Translation解决VLAN ID冲突。实际项目里两者可以配合使用。

6.4 设备兼容性清单

不同厂商对QINQ的支持程度差异很大。有的设备只支持基本QINQ,不支持灵活QINQ;有的设备TPID可配,有的固定;有的设备在QINQ端口上不支持某些ACL。选型阶段一定要拿到设备的QINQ特性清单,逐项确认。我吃过亏:项目中期才发现某款接入交换机不支持灵活QINQ,只能临时改方案。

7. 我在QINQ项目里攒下的几条硬经验

第一条,规划文档比配置命令重要。S-VLAN范围、TPID、MTU、端口角色、映射表,这五样东西必须在开工前白纸黑字定下来,所有参与方签字确认。我见过太多因为"口头说了一下"导致后期扯皮的情况。

第二条,抓包是唯一真相。配置回显、日志、计数器都只能作为参考,真正判断帧对不对,必须抓包看TPID、S-VID、C-VID三个字段。我现在的习惯是,QINQ上线前必抓包,抓完存档,后面出问题可以对比。

第三条,MTU要留余量。不要只调到1508,建议1522甚至更大。因为实际网络中可能还有MPLS、GRE等额外封装,余量留足能省很多事。

第四条,隔离验证要单独做。不要只测"能通",还要测"不该通的确实不通"。跨S-VLAN的ping测试、跨客户的访问测试,都要做一遍。隔离失效是QINQ最严重的问题,一旦出事就是安全事件。

第五条,变更窗口留足时间。QINQ涉及多层设备联动,一旦某台设备配置回滚,可能影响整条链路。我一般会把变更窗口留到业务低峰期,并且准备好回滚脚本。

最后分享一个我常用的小技巧:在隧道端口配置一个描述性的description,把客户名、S-VLAN、C-VLAN范围都写进去。比如description QINQ_CustomerA_SVLAN1000_CVLAN10-30。这样后面任何人看配置都能快速理解,排错时不用翻文档。这个习惯帮我省了无数次"这是哪个客户的端口"的困惑。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进