← 全部文章

零足迹

Osprey 如何在不成为网络一部分的前提下看清网络

Michel Wijnberg

地球上每一款监控产品都声称自己”无代理”。它们中的大多数,指的是通过 SSH 登进去抓取 show 命令的屏幕输出,这种”无代理”就跟窃贼算是”客人”一样。

Osprey 走的是另一条路,我想把它说清楚,包括营销话术并不完全属实的那一部分。

Osprey 有三种获取数据的方式。三种对于愿意去看的运维人员来说都是可见的(这不是一款隐 身产品),但只有其中一种会把 Osprey 放进路由协议自己的数据库里,那一种才值得认真 审视。


1. GRE 记录器:一条永远无法承载流量的真实邻接

最有意思的一种。Osprey 可以在 GRE 隧道上建立真正的 IGP 邻接:一条真实的 OSPFv2、 OSPFv3 或 IS-IS 邻居关系,有真实的 Hello、真实的 DBD 交换、真实的泛洪。它学习 LSDB 的 方式和路由器一模一样:被人告知。

这严格优于遍历 MIB,因为您拿到的是协议实际分发的那份数据库,序列号、老化时间和校验和 都完好无损,而且变更在泛洪的那一刻就能看到,而不是等到下一个轮询周期。

这也意味着路由器确实看得见一个邻居。我把话说白:**Osprey 会出现在 LSDB 里。**它 必须出现。RFC 2328 §12.4.1 要求区域内的每一台路由器都产生一条 Type 1 Router-LSA,而 一台建立了邻接却不产生 Router-LSA 的路由器,是一台有问题的路由器。

所以问题不是”我们能不能隐形”,因为不能,而是”我们能不能做到无法影响转发”。这个问题 有实实在在的答案:

// originateRouterLSA creates and installs our Router-LSA in the LSDB.
// RFC 2328 Section 12.4.1 requires every router to originate a Type 1 LSA.
// We use cost 65535 (maximum) so no router will ever route traffic through
// Osprey. Only the P2P link is advertised. NO stub network for the tunnel
// inner subnet. Advertising the tunnel subnet (even at max cost) causes SPF
// on other routers to install a route for the tunnel prefix, which can
// disrupt the GRE outer path and kill the adjacency.

这里面有两个刻意为之的决定,其中第二个是拿一次实验室故障换来的教训。

最大度量值。记录器把自己唯一那条点到点链路以开销 65535 通告出去,而这是两重保证 中较弱的一重。度量值只能让一条路径变得不受欢迎,而当它是唯一一条时,不受欢迎的路径 照样会被选中。真正的保证在于形状:记录器恰好只有一条邻接,所以它在图里是一个叶子节 点,而任何 SPF 都不可能找到一条穿过叶子的路径。再加上它不通告任何属于自己的前 缀,也就没有任何东西可以被路由过去。最大度量值只是压在一个本就无法承载中转的拓 扑之上的双保险。

不通告 stub 网络。记录器只通告那条 P2P 链路,别的什么都不通告。特别是,它不会 把隧道的内层子网作为 stub 网络通告出去。这一点很微妙。如果它通告了,区域内的每一台路 由器都会安装一条指向隧道前缀的路由。这条路由随后可能盖过 GRE 隧道本身所依赖的承载路 径,从而破坏外层传输,进而杀死邻接,最终让记录器掉线,一次漂亮的自作自受式震荡。什么 可达的东西都不通告,就一次性避开了这整类问题,而且依然满足 RFC 2328。

IS-IS 版本更严格

IS-IS 为这件事提供了专门的机制,所以 IS-IS 记录器就用它。它自产生的 LSP 带着一组硬性 不变量:

不变量原因
OL 位 = 1过载位。ISO 10589 强制要求其他所有路由器把过载路由器当作不可中转。这是首要保证,而不是度量值上的小把戏。
ATT 位 = 0000绝不吸引 L1 缺省路由。纯 L1 路由器不得把缺省路由指向 Osprey。
P 位 = 0不做分区修复。
TLV 22 度量值 = 0xFFFFFF最大宽度量值,与 OL 位构成双保险。
不带 TLV 128 / 130 / 135 / 236这些是 IP 可达性 TLV。发出其中任何一个都会注入路由。
不带 TLV 134不带 TE Router ID。否则会把 Osprey 塞进流量工程数据库。
不带 TLV 222 / 242不做多拓扑,不做路由器能力通告,不做 segment routing。

请把这张表读成”代码做不到的事情”的清单,而不是”设置项”的清单。没有任何配置开关能关掉 过载位,也没有任何代码路径会封装 IP 可达性 TLV,因为要保证您永远不会通告一个前缀,最 安全的办法就是根本不实现通告前缀。

所以:可见、参与,且在结构上无法吸引哪怕一个报文。这个断言比”隐形”强得多,而且和”隐形” 不同,它是真的。


2. SNMP:用无聊的方式拿到 LSDB,外加 LSDB 里没有的一切

不是每台设备都会给您一条邻接,而且有些东西本来就不在链路状态数据库里。所以 Osprey 也 做轮询。

SNMP 目标:192 台设备,全部在线,300 秒轮询间隔,凭据已掩码
SNMP 目标:192 台设备,全部在线,300 秒轮询间隔,凭据已掩码

这个实验室里有 192 个目标,个个是绿的,按 300 秒周期轮询,上次轮询以秒计。

凭据那一列显示为 ***,而这个掩码发生在哪里值得说清楚:**在 API 处理程序里,不是在浏 览器里。**凭据以 AES-256-GCM 加密静态存储,每一条读取路径都会在序列化之前把响应过一遍 掩码。前端根本就不会收到 community 字符串或 v3 的 auth/priv 口令,所以没有”显示”按钮, 而且不改服务端就不可能有。

在客户端做掩码是演戏。在处理程序里做掩码才是控制措施。

这里 SNMP 干四件事:

  • 重建 LSDB,用在没有挂记录器的地方(上一篇文章里那 13,382 条 LSA 就是这么来的,缺失的头部字段被诚实地声明出来)
  • 接口计数器,用于流量、错误和利用率
  • EIGRP,它根本没有可加入的数据库,完全从 CISCO-EIGRP-MIB 读取
  • 二层邻居,通过 LLDP 和 CDP

最后一项比听起来重要:

CDP/LLDP 邻居:303 条邻接,66 台唯一远端设备
CDP/LLDP 邻居:303 条邻接,66 台唯一远端设备

303 条二层邻接,66 台唯一远端设备。正是这一层让 Osprey 能说出一条 AS 间 BGP 会话到底跨 过了哪个物理端口,而不是含糊地说”这两台路由器之间的某条链路”。表里就能看到其中一 条 AS 间链路:从 ams1-gw1 Et1/1e-ams1-gw1 的那条 CDP 条目,那就是 AS 200 ↔ AS 100 的边界。


3. BMP:让路由器自己说话

对 BGP 来说,首选的路子不是去问,而是去听。

BMP(RFC 7854)是这样一种协议:路由器通过一条普通的 TCP 会话,把自己的 Adj-RIB-In,也 就是各个对等体向它通告的那些路径,推送给监控站。没有轮询循环,不用解析 show ip bgp,除会话本身之外也不给控制平面增加查询负载。发什么、什么时候发,由路由器 决定。

BGP 对等体:57 个对等体上的 378 条会话,374 条 up,4 条 down
BGP 对等体:57 个对等体上的 378 条会话,374 条 up,4 条 down

这里是 57 个对等体上的 378 条会话,但它们并非都是同一条路来的,而这个区别被记录了下 来,而不是被抹平。

这个实验室里有六台路由器是 BMP 导出器(ams1-gw1jfk1-gw1e-ams1-gw1e-sin1-gw1i-jfk1-gw1i-sin1-gw1),它们贡献了 24 条会话:包括实验室里的 每一条 eBGP 会话。剩下的 354 条来自对根本不导出 BMP 的路由器做 BGP4-MIB 的 SNMP 遍历。

通往数据的这两条路都是正当的,也都值得保留;只是它们并不一样好。BMP 数据流带着对等体 通告过的每一条路径,还有路由器视角下的 Peer Up 和 Peer Down。SNMP 遍历给您的是轮询那 一刻的会话表,两次轮询之间什么都没有。这里涉及的是哪一份 RIB:RFC 7854 监控的是 Adj-RIB-In,也就是这台路由器还没做任何选择之前收到的东西。路由器自己选出的那张表,也 就是 Loc-RIB,属于后来另立的扩展(RFC 9069),这些导出器并不发送,所以在这些候选路径 之上做的最优路径(best-path)选择是 Osprey 自己算的,并且被如实标注出来。

因此每一行都带一个 source 列,记录它是从哪条路来的,而这个值在上层是要承重的。当 Osprey 之后拼接一条跨 AS 路径、需要为某一跳跨域转发给出理由时,一条 eBGP 会话是带着出 处(bmp-peer 还是 snmp-peer)的证据,而绝不是一条匿名事实。同一张表,但分了等级。

两个地址族共用每台导出器的同一条 BMP 会话,所以您会看到 IPv4 和 IPv6 的行共享同一台上 报路由器。

那张表里的 eBGP 行才是有意思的,因为它们是三个租户之间的接缝:

ASAS
e-ams1-gw1100ams1-gw1200
i-sin1-gw1300e-sin1-gw1100
i-jfk1-gw1300jfk1-gw1200

一个三角形:阿姆斯特丹的 AS 200 ↔ AS 100,新加坡的 AS 100 ↔ AS 300,纽约的 AS 200 ↔ AS 300。六条会话,两个地址族合计十二行。正是这个三角形才让跨域路径拼接成为可能,那也 是第三篇文章的主题。


Osprey 在结构上做不到的事

有些约束值得当作约束来讲,而不是当作功能,因为正是它们让其余的一切值得信任:

  • **不注入路由。**记录器只产生一条 Router-LSA,描述一条最大开销的 P2P 链路,别的什么 都没有。它没有任何通告前缀的代码路径。
  • **不转发报文。**Osprey 不在数据平面里。没有转发表,没有 FIB,没有可以配错的东西。
  • **不写配置。**界面里的 SSH 终端就是一个终端。按键是您敲的,会话被记录下来供审计,而 Osprey 自己从不下发配置命令。
  • **单向数据流。**采集器和 BMP 摄入数据并发布到 NATS;引擎持久化到 PostgreSQL;API 服 务前端。没有服务会向上游回调。除了人在终端里敲字之外,从 Web 界面到路由器不存在任何 通路。

诚实的总结

Osprey 在要紧的意义上是被动的:它无法吸引流量,无法注入路由,也无法转发报文。但它并不 隐形,我宁可现在告诉您,也不愿意让您从一条比预期多出一行的 show ip ospf neighbor 里 自己发现。

如果某个厂商告诉您他们的工具会加入您的 IGP 而且没人看得出来,请问问他们的 Router-LSA 长什么样。


下一篇:为什么您的路径工具很可能在骗您,以及证明这一点的 4,032 对测量: 逐跳的真相