选定一条流和一个接收方,然后逐个跳点追踪这一对,而不是把组播当作一个品类来测。源特定组播设计只会精确地失败在四处之一:接收方从未加入、路由器在反向路径上丢弃了数据包、内核没有状态,或者隧道从未交付过副本。按这个顺序排查,每跳只花几分钟,就能告诉你实际命中的是哪一处。

先固定源、组和接收方

在触碰任何设备之前写下三个值:将要发送的源地址、接收方要加入的组地址,以及接收方所在的子网。举一条示例 IPv4 流,源 10.50.0.10 和组 232.20.30.40 就是适合源特定设计的典型组合。比这三个值更含糊的情况都无法测试。

232/8 网段专供源特定组播使用,该模型在 RFC 4607 中有描述。如果你以为自己在跑 SSM,而组落在该网段之外,先停下来确认部署的真实意图,因为接收方的加入和路由器的转发决策都依赖模型保持一致。

确认接收方已加入该源

只针对组的成员报告不是源特定加入。问接收方请求的是哪个源,并在第一跳路由器上看组状态里是否出现了源列表。如果报告中不带源,路由器会把它当成任意源加入,整个设计就会悄悄退化成你没计划过的样子。

在 Linux 接收方上,检查套接字实际订阅了什么、内核记录了什么。应用的配置文件不是证据,成员关系表才是。要在接收方真正运行时读它,因为创建该条目的进程退出后条目还会短暂残留。上一次测试留下的陈旧条目,是虚假信心的可靠来源。

ip maddr show dev eth0
cat /proc/net/igmp | sed -n '1,40p'

如果加入存在且源符合预期,就转向路由器。如果缺失,再多的隧道配置也没用,因为没有东西可转发。

先验证反向路径,再看隧道

组播路由会做反向路径检查,如果数据包从一个并非单播路由所指的接口到达,就会被丢弃。这是明明在发送的流却始终到不了下一跳的最常见原因,而且它在应用层完全不会产生任何有用的报错。

在朝向源的路由器上,把通往源的路由与数据包实际到达的接口做比较。在朝向接收方的路由器上,对接收方自己的子网做同样的事,并确认出接口列表包含通往它的链路。任一方向不匹配都是 RPF 失败,而不是成员关系失败。

然后确认源的 TTL 足够大,能撑过你设计的那些路由跳点。在第一台路由器上可用、到第二台就中断的流,往往首先是 TTL 问题而不是策略问题。

读内核的组播状态,而不是读配置

配置说明你要求了什么,内核说明正在发生什么。在每一台 Linux 跳点上读取组播路由条目,确认针对确切的源与组对存在入接口和出接口列表。用通配源写的组条目是另一个对象,它解释不了源特定流。

ip mroute show from 10.50.0.10 iif eth1
ip route get 10.50.0.10

路由守护进程会在该状态之上保留自己的视角,打印它的命令取决于装的是哪种实现。原则始终一样:先问守护进程它对该源组对的上游条目,再问内核是否存在转发条目。守护进程自认为在转发、而内核没有条目,就是这台主机上的配置范围问题。

两者不一致时,修主机,别修 VPN。下游任何东西都补偿不了一个不转发你所要的流的跳点。在流正常时,把每一跳的源组对、入接口和出接口列表记下来。那份记录能把下一次故障变成对照,而不是从头调查。

决定隧道到底如何复制

组播跑在 VPN 上,真正的分水岭就在这里。点对点隧道把数据包交给对端唯一的一个 peer,所以一份副本只到达一个客户端。桥接网段更像共享链路,因为隧道承载帧,由网桥决定向哪里泛洪。这是两种不同的交付模型;按第一种运行却假定第二种的设计,会对一个接收方看似可用,对下一个就失败。

通过多点服务器服务多个接收方时,复制必须显式设计。在网关上安装一条组播路由,并不能让 VPN 服务器知道哪些 peer 该收到副本,客户端侧也没有任何路由能替它做这个决定。需求是很多接收方时,请使用受支持的复制或刻意选定的替代方案,并把选了哪一个写下来。

最后,在接收方做窄口径验证:确切的源、组和端口,在你预期的接口上,只让一个被授权的接收方处于加入状态。SSM 选择的是发送者,而这一选择既不是对该发送者的认证,也不等于允许其他组播流量穿越同一条策略。

相关文章