很多人学完IGMP还是懵的——他查得到“互联网组管理协议”的全称,但真到配组成员、看表项、抓报文的时候,脑子里没有一张图。我第一次真正搞懂IGMP,是某次帮一个视频直播项目排障:多个终端同时收不到组播流,路由器的组播路由表里明明有(*, 239.x.x.x),但用户侧就是没画面。最后一路查下来,问题居然出在主机发出IGMP报告之后,二层交换机没开组播侦听,把组播流量当广播泛洪处理。从那天起我就明白,IGMP这种“又简单又容易翻车”的协议,光看理论是不够的,必须亲手做一遍实验。这篇文章就沿着“基础原理 + 实验验证”两条线走:先搞清楚IGMP在组播体系里的定位,再把v1/v2/v3的机制差异掰开揉碎,最后用模拟器把组成员加入、查询、离开、源过滤、二三层联动全跑一遍,顺便把常见故障的排查思路整理成一条链路。适合刚接触组播的网络工程师、运维同学,以及准备认证考试的朋友。
1. 组播的最后一公里:IGMP要解决的到底是什么问题
1.1 组播分发链路中的“最后一问”
组播的整个体系里有一个核心矛盾:组播源根本不知道谁在看数据。单播是源端明确知道接收端地址,一对一发送;广播则是一对所有人,不管你想不想要都塞给你。组播的思路是“按需分发”——源只要往一个组播地址发数据,数据就会沿着网络复制到所有想要接收的成员那里。但这里有个关键前提:“网络”必须知道谁想接收。
这个“谁想接收”的信息,在路由器之间的传递靠PIM这类组播路由协议完成,而在主机和直连路由器之间的这一段,靠的就是IGMP。
IGMP的全称是Internet Group Management Protocol,互联网组管理协议。它运行的场景很具体:一台主机想加入某个组播组,于是向直连路由器宣告“请把发往这个组的数据在链路上转发给我”;路由器收到后,在自己的接口上维护一张组成员表;当主机不再想接收时,也得通过IGMP告诉路由器“不看了,把流量掐了”。IGMP就是主机和路由器之间维护组成员关系的控制协议。
把它放在整个组播体系里看,地位非常清楚:PIM负责在路由器之间建立组播转发路径,IGMP负责在最后一条链路上收集组成员意愿,两者配合,组播流才能从源到达用户。如果用生活类比解释,组播源是出版社,路由器是邮局,IGMP就是订户填的订阅单——出版社不知道订户在哪,邮局靠订阅单决定把杂志递给谁,订阅单过期或者订户退订,邮局就得停送。
1.2 IGMP协议的定位与报文全貌
IGMP报文直接封装在IP报文里,协议号是2,不像TCP或UDP那样有端口号。它运行在主机和与其直连的路由器之间,报文默认TTL为1,也就是只能在本地链路传播,不会跨路由器转发。这个设计有明确意图:组成员关系本质上只是“本网段内有哪些人要收组播”这件事,不需要传很远。
IGMP的报文类型从v1到v3经历了明显扩展。v1只有两种:成员关系查询和成员关系报告。v2增加了一种离开报文,同时给查询报文加上了最大响应时间字段。v3把报告报文做得更复杂,引入了组记录和源列表,能表达“我要收这个组,但只收这些源发来的数据”。了解了这些报文,后面的实验才能看懂抓包结果。
路由器上每个接口都可以独立开启IGMP,而组成员表项维护的是“组地址 + 入接口”的对应关系。一个接口上可能同时存在多个组成员,路由器只关心这个接口下面有没有人需要某个组,不关心具体是哪个主机——这也是IGMP设计上的一个特点,为的是让路由器维护成本尽量低。
2. IGMP三个版本怎么选:从v1的凑合到v3的精确
2.1 IGMPv1:只有查询和报告的时代
IGMPv1是最早的版本,由RFC 1112定义。它只有两种报文:普遍组查询(General Query)和成员报告(Membership Report)。
查询报文由路由器周期性发送,目的地址是224.0.0.1,也就是“本网段所有主机”。主机收到查询后,如果自己加入了某个组,就回一个报告报文,目的地址是组播组地址本身。比如主机加入了239.0.0.1这个组,报告报文就发往239.0.0.1,源地址是主机自己的IP。路由器据此在接口上建立组成员表。
v1最大的问题在于离开机制。主机想退组时,协议里根本没有“离开”消息,只能靠路由器“等”——默认情况下组成员表要等大约两分钟超时才会删除。如果这个组一直在跑视频流量,那退出的成员还会继续收到两分钟的组播数据,体验很差,也浪费带宽。而且v1不区分具体组,路由器发一次普遍查询,只能用超时机制逐个淘汰不再响应的组。对小型实验网还能忍,生产环境基本没人用v1。
2.2 IGMPv2:把离开这件事快速处理掉
IGMPv2是RFC 2236定义的标准版本,现在绝大多数网络设备默认支持的就是v2。它在v1基础上增加了两个关键能力。
第一个是最大响应时间字段。路由器发普遍查询时,可以在报文里告诉主机“你在多长时间内给我回报告”,默认是10秒。主机在0到最大响应时间之间随机选一个延迟再回报告,避免所有主机同时回包造成拥塞。更关键的是,这个字段让路由器的老化判断有了依据——如果连续多次查询都有主机响应,表项就一直保持。
第二个是离开机制。IGMPv2新增了离开报文(Leave Group),目的地址是224.0.0.2,也就是“本网段所有组播路由器”。当主机发送离开报文后,路由器会针对该组发送特定组查询(Group-Specific Query),目的地址填这个组的组播地址,再等一段时间。如果这段时间内没有主机回报告,路由器就可以删除组成员表项,并把“不再有成员”的信息通知给上游。整个过程相比v1的两分钟超时快得多,实际链路上通常一两秒就能完成组播“断流”。
我在实验里测过,从主机发Leave到路由器删除组成员表,再到这台路由器向上游发剪枝消息,默认参数下基本在两秒内完成。这正是v2能成为生产环境默认版本的底气。
2.3 IGMPv3:源过滤能力与SSM的基石
IGMPv3由RFC 3376定义,解决了更精细的需求:主机不仅要说“我要收239.0.0.1这个组”,还要说“这个组里我只收192.0.2.10这台源机器的数据”,甚至“我只不收哪几个源的数据”。
v3的报告报文结构和v1/v2完全不一样,不再是一个简单的组地址字段,而是携带一条或多条组记录(Group Record)。每条组记录里包含记录类型、组地址、源列表。记录类型就有六种:MODE_IS_INCLUDE、MODE_IS_EXCLUDE、CHANGE_TO_INCLUDE_MODE、CHANGE_TO_EXCLUDE_MODE、ALLOW_NEW_SOURCES、BLOCK_OLD_SOURCES。INCLUDE表示“我只收这些源”,EXCLUDE表示“除了这些源我都收”。
v3还有一个明显变化:报告报文的目的地址不是组播组地址,而是224.0.0.22(所有IGMP路由器),意味着所有组播路由器都会收到这份报告。同时主机需要把当前完整状态发给路由器,而不是像v2那样只发一个组地址,这也是为了让路由器准确追踪源过滤状态。
正是v3的源过滤能力,让SSM(Source-Specific Multicast,特定源组播)成为可能。SSM场景下,接收者必须显式指定要接收的组播源,PIM路由才能针对精确的(S,G)表项建立转发路径。没有IGMPv3,SSM无从谈起。
2.4 三个版本的选型建议
选型这件事,我直接给结论:新网络优先用v3,因为兼容性最好,v3路由器能识别v2主机,也能识别v1主机;有SSM需求就必然用v3;老旧终端如果只支持v2,接口版本显式调成v2最省事;v1不要使用,除非你有二三十年前的老设备。
有一点要注意,IGMP版本是路由器接口级别的配置,不是全网统一。实际组网里经常出现一台路由器接口配v3,下面接的主机却只有一个老旧的v2协议栈。这种情况v3路由器会自动降级兼容,但代价是主机得不到源过滤能力,接口上部分v3功能会退回v2行为。这种“兼容但降级”的细节,在实验里能看到很清楚。
3. 用模拟器搭一个最小实验环境:拓扑、配置与抓包思路
3.1 实验拓扑与设备角色
我习惯用图形化网络模拟器来做这类实验,选它主要是方便:拓扑搭建快,命令风格贴近真实设备,还能直接把抓包点搭在链路上。实验拓扑不需要复杂,三台路由器加两台PC正好。
组播源接在左侧路由器上,组播接收者接在右侧路由器上,中间一台路由器做转发。为了验证组成员关系,我给每条链路配了不同的网段:源侧用10.0.1.0/24,中间互连用10.0.2.0/24和10.0.3.0/24,接收者侧用192.168.1.0/24。接收者PC的地址固定成192.168.1.100,组播源用一台PC或直接用路由器接口作为发送源都可以,我这次在源侧模拟一台主机。
角色划分上,接收者侧路由器是IGMP实验的主角,它直连接收者,负责接收和处理IGMP报文;中间路由器的任务是维护组播路由表;源侧路由器负责接收组播数据并沿组播路由树转发。为了让组播能真的通起来,我还在全网跑了一个基础单播路由协议,保证任意两台设备之间单播互通——PIM依赖单播路由表做逆向路径检查,这一步不能省。
3.2 基础配置流程:三层可达、组播使能与IGMP开启
先把接口地址配上,然后配置单播路由协议。这一步完成后,三台路由器之间应该能互相ping通,接收者PC也能ping通源侧的地址。单播不通的话,后面的组播实验大概率起不来,所以我会先做一轮连通性测试再往下走。
接着在每台路由器上开启组播路由能力。这个全局开关的作用是允许设备维护组播路由表并运行PIM。然后我在所有参与组播转发的接口上开启PIM并用稀疏模式,因为我模拟的组播环境更接近真实生产网络。如果实验只想验证IGMP表项,其实PIM不是必需的,但为了让组播流真正从源转发到接收者,PIM必须配好。稀疏模式里需要指定一个汇聚点,我把中间路由器的环回口地址作为静态RP,全网设备指向它。配置例子大致长这样:
interface Loopback0 ip address 2.2.2.2 255.255.255.255 interface GigabitEthernet0/0/0 ip address 10.0.2.1 255.255.255.0 pim sparse-mode ip multicast rpf select static ip pim rp-address 2.2.2.2接收者侧路由器还要多一步:在连接接收者的接口上开启IGMP,并显式指定版本。实验里我会先用v2跑一遍完整流程,再切v3看差异:
interface GigabitEthernet0/0/2 ip address 192.168.1.1 255.255.255.0 pim sparse-mode igmp enable igmp version 2配置完成后,先不要急着让PC加组。先在路由器上看一下接口有没有周期性发出普遍查询报文,确认IGMP进程已经活起来,再进入抓包阶段。
3.3 抓包点怎么放:先搞清楚报文路径
IGMP报文只在主机和直连路由器之间传递,所以抓包点必须放在接收者PC和接收者侧路由器之间。在模拟器里,我通常会在这个链路上挂一个抓包工具,或者在PC端直接抓包。
要理解这个链路上的报文,必须时刻提醒自己:IGMP报文的目的地址有很多讲究。路由器发的普遍查询,目的地址是224.0.0.1;主机发的组成员报告,在v1/v2里目的地址是组播组地址本身;主机发的离开报文,目的地址是224.0.0.2;v3报告则发往224.0.0.22。如果抓包时看到目的地址五花八门,先别慌,对着协议的规则归类就行。
抓包工具我用的Wireshark,它对IGMP报文有完整解码,能直接看到每个字段的值。如果你对命令行更熟,tcpdump同样能看,但Wireshark的图形化界面在对照字段时更直观。抓包时建议先抓一小段时间,确认存在周期性的普遍查询报文,再开始加组操作,这样后面生成的报告、离开报文就能和查询区分开,不至于一锅粥。
4. 动手跑通IGMPv2:加入、查询、离开的完整报文生命周期
4.1 成员加入:Report报文与组成员表变化
接收者PC设置好IP后,我会先在网络里测试一个组播流:源侧往239.0.0.1这个组持续发送UDP数据。此时接收者还没加入任何组,所以流量到不了接收者侧。我在PC上发起一个组播接收应用,让它加入239.0.0.1,或者用一个组播测试工具发送IGMP报告,效果一样。
抓包工具在这一刻能立刻抓到一条IGMPv2成员报告报文:协议类型0x16,目的地址239.0.0.1,组地址字段也是239.0.0.1。注意,报告的目的地址是组播组地址,不是224.0.0.2。收到这份报告后,接收者侧路由器的组成员表里就会出现一个条目,指向连接接收者的接口,同时显示这个组的存活时间。
命令查看时,能看到类似这样的核心信息:组地址239.0.0.1,接口GigabitEthernet0/0/2,状态为成员,带一个过期计时器。这个表项就是IGMP协议对“本网段有人要这个组”这件事的最终输出。后续组播流到达这台路由器时,路由器查组播路由表,发现出接口下有组成员,于是把数据从该接口发出去。
这里有个很值得注意的细节:IGMP为每个组维护的是接口级别的成员关系,而不是主机级别的。也就是说,哪怕这个网段里有十台主机加入同一个组,路由器表项里也只是同一个组地址对应同一个接口,不会出现十条记录。这种设计让路由器的状态量可控,也意味着只要有一个成员在,组播流就会广播到整个网段,由各主机自行决定是否接收。
4.2 周期查询与定时器:路由器和主机的“心跳协议”
IGMPv2里,路由器会周期性发送普遍组查询报文,默认间隔通常是125秒,最大响应时间10秒。主机收到查询后,会在0到10秒之间随机选择一个时间,然后发送报告。随机化的目的是避免所有主机在同一瞬间回复,形成报文风暴——在一个成员数量很大的网段里,这个机制格外重要。
抓包时会发现,查询报文的源地址是路由器接口地址,目的地址是224.0.0.1,类型为0x11,组地址字段为0.0.0.0,表示这是一次普遍查询。主机回的报告延续了加入时的行为,同样发往组播组地址。
路由器的组成员表项会随着每次查询响应被刷新。主机侧同样维护着一个组员计时器,每次收到查询都会重置。如果某台主机不想再接收了,理论上它可以默默不再回复查询,路由器经过若干次查询后就会删除表项,但这个方式太慢。所以v2才特意设计了离开机制。
提醒一下:路由器的查询间隔和主机的最大响应时间不是一回事。查询间隔决定路由器多久问一次,最大响应时间决定主机在听到查询后多久内必须回答。把最大响应时间调小,组成员变化会更快被感知,但代价是网络里周期性报文增多;调太大,成员离开的反应会变慢。生产上一般保持在默认值附近,不要盲目调。
4.3 快速离开:Leave报文的完整交互
IGMPv2最有价值的改进就是快速离开。我在实验里让接收者退出239.0.0.1,并在抓包工具上等着看四段式交互。
第一步,主机发送IGMPv2离开报文,类型0x17,目的地址224.0.0.2,组地址字段填入239.0.0.1。第二步,路由器收到离开报文后,马上针对这个组发送特定组查询,类型同样是0x11,但组地址字段不再是0.0.0.0,而是239.0.0.1,目的地址通常填组播组地址或224.0.0.1,源地址是路由器接口地址。第三步,路由器在最大响应时间窗口内等待是否有其它主机回报告。如果没有任何主机响应,第四步,路由器删除这个组的成员表项,同时向上游的PIM邻居发送剪枝消息,通知上游“这个网段不再需要239.0.0.1的流量了”。
整个交互在抓包里一目了然。我之前测过默认参数下的表现,从Leave出发到组成员表删除,整个过程在1到2秒内完成。对比v1靠两分钟超时慢慢淘汰的老办法,v2的体验提升是决定性的。
有一点容易被忽略:只有“最后离开的成员”才需要执行完整交互。如果一个网段里有多台主机都在接收同一个组,其中一台退出时,它发出的Leave报文会促使路由器发特定组查询,但只要有其它主机回报告,组成员表就会保留。换句话说,路由器不关心谁离开了,它只关心“网段里还有没有人要看”。离开报文的真正作用是触发一次“还有没有人”的确认动作,这才是快速离开的本质。
4.4 调参实验:max-response-time和query-interval能改出什么效果
除了默认跑通,IGMP实验最有意思的部分是调参数观察反应。我会把接收者侧接口的最大响应时间从默认10秒改成2秒,然后抓包看普遍查询报文里的字段变化。主机看到查询后,随机延迟范围立刻压缩到2秒内,报告报文的到达时间明显提前,组成员变化也会更快。
再把查询间隔从125秒调到30秒,抓包频率会显著增加,组成员表项的过期时间也会相应缩短。调整这些参数时一定要注意:如果间隔太短,会让接入链路上充满IGMP报文;如果最大响应时间太长,成员加入的响应速度会变慢。更关键的是,这两个参数直接影响后续PIM和二层组播侦听的老化行为,改了一处不调另一处,往往会出现“这边表项还在、那边流量已经断了”的怪现象。
调参实验的另一个价值是帮助你理解协议里的时间和状态关系。IGMP不是瞬间完成的事情,它是一个由查询、响应、随机延迟、定时器刷新构成的持续过程。参数不同,整个系统的收敛速度完全不同。这种对时间维度的感知,靠看书很难建立,亲手调一遍就明白了。
5. IGMPv3实验:源过滤与SSM场景下的报文变化
5.1 IGMPv3报文结构:从简单组地址到复杂记录
把接收者侧接口的IGMP版本改成v3后,我重新让PC加入239.0.0.1。抓包会出现惊人的变化:报告报文的目的地址变成了224.0.0.22,协议类型变成0x22,报文内容不再是简单的“组地址 + 响应时间”,而是一个完整的组记录。
展开报文结构可以看到四个关键部分:记录类型、辅助数据长度、组播地址、源地址列表。这个结构承载的信息量比v2大得多——主机可以一次性上报多个组,每个组可以带一段源列表,列表里每条源地址都是主机显式表达的意愿。
抓包时最容易疑惑的地方是记录类型。如果看到MODE_IS_INCLUDE,意思是“我只接收后面源列表里的源”;MODE_IS_EXCLUDE则是“除了后面列表里的源,其它源我都收”。实验里让主机加入239.0.0.1但不指定源,会看到一条EXCLUDE记录且源列表为空,等价于“这个组所有源都收”,行为上接近v2。一旦指定了源,报文才会显式体现出“我只收某个源”。
5.2 SSM场景:指定源加入的实验验证
SSM实验我换了个组地址段来做,因为实际网络里SSM通常有单独的地址范围。接收者PC发送v3报告,组地址是232.0.0.1,源列表里填入源侧接口的地址10.0.1.2,记录类型是INCLUDE。这份报告告诉路由器:我只想收10.0.1.2发往232.0.0.1的数据,其它源发来的,一律不要。
路由器收到后,会在组成员表里看到的不再是单纯的组表项,而是组地址加源地址的对应关系。这个信息会进一步传递给PIM层,形成以精确(S,G)为粒度的组播路由表项。整个链路从“Client wants the group”进化成了“Client wants data from this source to this group”。
为了验证过滤效果,我在源侧同时从两个不同地址往232.0.0.1发包,一个是10.0.1.2,另一个是10.0.1.3。抓包和数据接收情况能明显看到:只有10.0.1.2发来的流量被转发到接收者网段,10.0.1.3的流量在路由器的出接口处就被挡掉了。这个实验直观证明了IGMPv3源过滤的实际价值:用户不想看的源,在靠近用户的路由器上就被拒绝,不会白白消耗接入带宽。
5.3 新旧版本混合:兼容性机制与踩坑点
生产网络里经常出现v2和v3混跑的情况。我在实验里故意把接收者PC的IGMP版本保持v2,而路由器接口配置v3,然后观察发生什么。
v3路由器会维护一个“老版本主机存活”的状态。收到v2报告后,路由器会自动降级接口行为,继续处理v2报告,但过滤能力失效。此时SSM无法正常工作,因为v2报告里根本没有源列表信息。从抓包看,主机仍然发v2格式的报告,路由器也接受,但整个链路实际上运行在v2兼容模式。
反过来,如果路由器接口是v2,主机是v3,路由器会把v3报告当无法识别或按老版本方式忽略掉,结果可能直接没有组成员表项。这是最常见的配置不匹配坑。实验里踩一次,印象会非常深刻。
兼容性问题给我们一个工程上的提醒:IGMP版本必须在接入侧统一规划。新终端可以v3,老旧终端如果只能v2,应该把接口统一降到v2,换取稳定兼容,而不是放任混跑导致行为不确定。如果你依赖SSM能力,那整个接入链路上的主机都必须支持v3,没有捷径。
6. 二层设备上的IGMP Snooping:组播流量泛洪的真相
6.1 没有Snooping时,组播为什么会让所有端口躺枪
很多人在实验里发现一个古怪现象:三层IGMP配得好好的,组成员表也有,源侧发包了,终端也确实连着路由器,但组播流量到了交换机之后,竟然出现在所有端口上。
原因在于交换机的转发逻辑。普通二层交换机根据MAC地址表转发单播帧,组播帧的特殊之处在于目的MAC是组播MAC,而交换机的MAC地址表里不会天然记录“这个组播MAC应该从哪个端口出去”。发现查不到表项时,交换机只能把帧泛洪到同一VLAN内的所有端口,和广播帧一个待遇。
组播MAC的推导也有讲究:IP组播地址映射到以太网组播MAC时,低23位直接用于映射,比如0100.5e00.0000加上组地址的后23位。这种映射不是一一对应的,多个IP组播地址可能映射到同一个MAC地址,所以二层处理无法靠MAC精确区分组播组。IGMP Snooping解决的就是这个“不知道往哪些端口转发”的问题。
6.2 Snooping表项怎么建、怎么老、怎么刷
IGMP Snooping的原理是让交换机偷听主机和路由器之间的IGMP报文,根据报文内容建立和维护一张“组播MAC对应端口”的表。主机发成员报告时,交换机看到报告报文,就知道发出这个报文的端口属于某个组;路由器发查询报文时,交换机也会识别出哪些端口连着路由器,这些端口会被记为组播路由器端口。
有了这张表之后,组播流量到达交换机,交换机查表,只把数据从对应成员端口和路由器端口转发出去,其它端口不再收到无意义流量。我实验里在交换机上开了Snooping后,先加一台接收者,看组播表里出现一条239.0.0.1对应接收者所在端口的记录;再把第二台接收者接到另一个端口加入同一组,表项里会新增端口,组播流也从两个端口分别出去。
Snooping表项并不是建完就永久生效,它同样依赖定时器老化。主机如果不再回应用户查询,交换机上的对应表项会超时删除。很多视频卡顿问题的根源就在这里:三层IGMP表还在,流也正常到了交换机,但交换机侧的表项已经因为超时或被错误广播老化,导致组播流不再被转发到成员端口。
6.3 一个容易忽略的点:二层IGMP Query与成员老化
二层交换机本身不产生IGMP查询报文,它默认依赖上游路由器发送的查询来刷新表项。如果这段网络里路由器离得远,或者中间经过其它网络设备,交换机可能长时间收不到查询,Snooping表项就会静默老化,成员流量随之中断。
解决办法是给交换机开启IGMP Snooping查询器功能,让交换机在检测到没有其它查询器时,自己作为查询器周期性发送普遍查询。这样可以保证链路里的主机持续响应,Snooping表项不断刷新。
这里必须强调一个顺序问题:Snooping表项的建立依赖主机发送的IGMP报告,而主机发送报告的前提是收到查询。如果网络里既没有路由器查询,交换机也没开查询器功能,主机的加入报告可能只在应用启动时发一次,然后就再也没有后续,交换机老一老就把成员表丢掉。我遇到过太多这种“三层正常、二层断流”的情况,排查到最后一查交换机组播表项是空的,或者早过期了。
7. IGMP故障排查链路:从现象到根因的完整思路
7.1 主机显示已加入却收不到流量:六步定位链路
组播排障最忌讳上来就重启设备或者瞎改配置。我有一套固定排查链路,从最靠近用户的地方开始逐层往上游查。
第一步确认接入设备的组成员表。在直连接收者的路由器接口下查看IGMP组表,确认这个组在不在、对应哪个接口。如果表项根本没有,问题在IGMP层面,直接抓包看主机有没有发报告、路由器有没有发查询。
第二步确认组播路由表。看有没有针对这个组的转发表项,出接口是否包含接收者网段。有表项但出接口不对,通常是PIM或RP配置问题。
第三步确认上游方向。看组播源往这个组发的数据有没有到达入口路由器,入接口的报文计数是否增长。如果入口连流量都没到,问题可能在源侧或中间的转发路径。
第四步检查RPF。PIM转发组播报文的规则是每个接口都做逆向路径检查,组播流到达接口时,设备会检查单播路由表,确认这个接口是到达组播源的最佳路径。如果单播路由出现非对称或多条等价路径,RPF检查可能失败,流量被丢弃。
第五步回到二层。确认接入交换机是否启用了Snooping,查交换机上的组播表项是否指向成员端口。这个判断可以直接决定“三层通了但二层不转发”的元凶。
第六步,如果以上都正常,用抓包确认链路报文的实际到达情况。抓包放在接收者侧,如果看到组播流量报文确实进了终端网卡但应用没显示,那就是主机侧应用问题,和网络无关了。
这套链路的好处是每一层都有明确的判断证据,不会在一个环节反复打转。我排障时很少凭空猜,基本都是沿着这个顺序一路验证下来。
7.2 成员离开后组播流还在:定时器与Snooping的锅
另一种常见现象是主机已经退出组播组了,但网段里还能收到一段时间组播流量。遇到这种情况不要急着下结论说IGMP有bug,先看时间尺度。
如果流量多持续了一两秒,这是正常的。v2离开机制本身就需要时间完成:Leave报文发送、特定组查询、等待报告、删除表项、上游剪枝,这些动作不可能瞬间完成。默认参数下,从Leave到流量停止,一两秒属于合理收敛时间。
如果流量持续了十几秒甚至更久,问题就复杂了。一个典型场景是同一网段里还有其它主机在接收这个组,路由器当然不会剪枝。另一个典型场景是二层交换机没有启用Snooping,组播流在所有端口泛洪,离开行为根本没有细化到交换机端口,哪怕路由器已经停止向该网段转发,交换机内部的泛洪状态也需要自己的老化机制慢慢收敛。
还有一种隐蔽原因是查询器选举混乱。如果网段里有多个三层设备都开启了IGMP,理论上只有查询器负责发送周期性查询。一旦查询器选举异常,多条查询器同时存在,主机的报告行为会变得混乱,组成员表刷新就会出现不可预期的时间延迟。通过抓包可以数一数查询报文的源地址,如果看到多个源地址持续发查询,就需要排查查询器选举问题了。
7.3 我的IGMP实验验证清单
摸爬滚打这么久,我给自己整理了一个组播实验的基础验证清单,每次做实验或排障前都会过一遍。
配置方面:检查单播路由是否互通,IGMP是否在接入接口开启,PIM是否跑起来,RP配置是否一致,接口的IGMP版本是否和终端匹配。二层方面:确认交换机Snooping开启,确认查询器配置合理,确认组播表项端口正确。抓包方面:路由器应该周期性发查询,主机加入时应该有报告,离开时应该有Leave加特定组查询的成对交互。状态查看方面:组成员表、组播路由表、Snooping组表三个层面的表项要能对上,不能出现“路由器有成员、交换机没表”或者“交换机有表、路由器没成员”这种割裂状态。
每次按这个清单走一遍,绝大多数组播问题都能在十分钟内定位到根因。IGMP本身不复杂,复杂的永远是它和PIM、二层Snooping、主机协议栈这些相邻模块之间的配合关系。把这些配合关系通过实验亲手理清一次,比看十遍协议文档都有用。