FRRouting/OSPFv2 路由计算

从链路状态计算 OSPF 区域内路由

FRRouting 的 OSPF 守护进程用 Dijkstra 计算区域内最短路径,并为路由表生成下一跳。

frr-10.2通信与流量核验 2026-10-12
相关概念

工程问题#

路由器收到链路状态通告后,需要根据区域内的网络拓扑与链路代价,计算到各目标的最低代价路径。结果不仅是距离,还要能确定下一跳,并处理相同代价的多条路径。

实际实现#

ospfd 将区域内路由器与中转网络作为顶点,以链路状态数据库提供邻接关系和非负代价。ospf_spf_calculate 反复选择代价最小的候选顶点,ospf_spf_next 更新邻居的距离和下一跳。frr-10.2 用跳表维护候选优先队列:发现更低代价时先删除,尝试更新合法下一跳与距离后重新插入,相同代价则继续计算可用的下一跳。

处理流程#

  1. SPF 调度任务按区域建立新的路由计算结果,以本机的 Router-LSA 作为根。
  2. 检查当前顶点的链路状态通告,计算到邻居的累计代价,过滤失效或缺少反向连接的链路。
  3. 对尚未确定的顶点更新代价与下一跳;更低代价重新排序,相同代价处理等价路径。
  4. 取出最小代价候选顶点加入最短路径树,并登记中转网络与路由器;候选耗尽后再补入末梢网络路由。

源码片段#

固定版本 · 原文摘录
ospfd/ospf_spf.cfrr-10.2 · L66–L81
查看原文件
66static int vertex_cmp(const struct vertex *v1, const struct vertex *v2)67{68	if (v1->distance != v2->distance)69		return v1->distance - v2->distance;7071	if (v1->type != v2->type) {72		switch (v1->type) {73		case OSPF_VERTEX_NETWORK:74			return -1;75		case OSPF_VERTEX_ROUTER:76			return 1;77		}78	}79	return 0;80}81DECLARE_SKIPLIST_NONUNIQ(vertex_pqueue, struct vertex, pqi, vertex_cmp);
vertex_cmp / vertex_pqueue

候选顶点先按累计代价排序,代价相同时将网络顶点排在路由器顶点之前。DECLARE_SKIPLIST_NONUNIQ 明确表明这个版本用跳表维护优先队列;文件中的旧 heap 注释不能作为二叉堆实现的依据。

ospfd/ospf_spf.cfrr-10.2 · L1749–L1761
查看原文件
1749	for (;;) {1750		/* RFC2328 16.1. (2). */1751		ospf_spf_next(v, area, &candidate);17521753		/* RFC2328 16.1. (3). */1754		v = vertex_pqueue_pop(&candidate);1755		if (!v)1756			/* No more vertices left. */1757			break;17581759		v->lsa_p->stat = LSA_SPF_IN_SPFTREE;17601761		ospf_vertex_add_parent(v);
ospf_spf_calculate

每轮先检查当前顶点的邻边,再弹出累计代价最小的候选顶点,将其标记为已经加入最短路径树。候选队列为空时结束;主循环后续把可达网络和路由器写入相应的新路由表。

ospfd/ospf_spf.cfrr-10.2 · L1499–L1519
查看原文件
1499			else if (w->distance == distance) {1500				/*1501				 * Found an equal-cost path to W.1502				 * Calculate nexthop of to W from V.1503				 */1504				ospf_nexthop_calculation(area, v, w, l,1505							 distance, lsa_pos);1506			}1507			else {1508				/*1509				 * Found a lower-cost path to W.1510				 * nexthop_calculation is conditional, if it1511				 * finds valid nexthop it will call1512				 * spf_add_parents, which will flush the old1513				 * parents.1514				 */1515				vertex_pqueue_del(candidate, w);1516				ospf_nexthop_calculation(area, v, w, l,1517							 distance, lsa_pos);1518				vertex_pqueue_add(candidate, w);1519			}
ospf_spf_next

相同代价的路径交给下一跳计算处理;发现更低代价时,先从候选队列移除顶点,尝试计算合法下一跳并更新距离,最后重新入队。只有找到合法下一跳才会修改距离和父节点;重新入队使候选集按更新后的实际代价排序。

ospfd/ospf_spf.cfrr-10.2 · L1862–L1878
查看原文件
1862	/* Execute SPF for each area including backbone, see RFC 2328 16.1. */1863	monotime(&spf_start_time);1864	new_table = route_table_init(); /* routing table */1865	new_rtrs = route_table_init();  /* ABR/ASBR routing table */18661867	/* If we have opaque enabled then track all router reachability */1868	if (CHECK_FLAG(ospf->opaque, OPAQUE_OPERATION_READY_BIT))1869		all_rtrs = route_table_init();18701871	ospf_spf_calculate_areas(ospf, new_table, all_rtrs, new_rtrs);1872	spf_time = monotime_since(&spf_start_time, NULL);18731874	ospf_vl_shut_unapproved(ospf);18751876	/* Calculate inter-area routes, see RFC 2328 16.2. */1877	monotime(&start_time);1878	ospf_ia_routing(ospf, new_table, new_rtrs);
ospf_spf_calculate_schedule_worker

SPF 调度任务建立新的路由表,逐个区域执行 SPF,再计算区域间路由。这个调用方说明 Dijkstra 参与的是控制面的路由计算;实际报文转发时的目的地址查表属于另一条路径。

四段原文分别展示候选队列、Dijkstra 主循环、候选更新和真实调度调用方;LSA 校验、下一跳继承、末梢网络与路由安装请结合完整源文件阅读。

收益与取舍#

工程分析

带来的收益

  • 一次单源计算得到本路由器到区域内各目标的最短路径,无需逐个目标重新搜索。
  • 距离计算与下一跳维护结合,结果可以用于建立路由表,并支持等价多路径。

付出的代价

  • 链路状态数据库、候选队列与父节点信息占用内存;拓扑变化还会触发重新计算,FRR 用 SPF 定时与退避合并频繁事件。
  • 经典 Dijkstra 的非负权条件在这里由 OSPF 链路代价满足。完整处理成本还包含 LSA 查找、链路有效性检查和多下一跳维护,不能直接把教材复杂度当成整个协议的开销。

可比较的选择

线性扫描候选顶点仍可执行 Dijkstra,但每轮寻找最小代价顶点要扫描候选集合;此版本以跳表维持有序候选集,增加节点与索引维护成本。

距离向量路由通过邻居交换距离和下一跳,可减少对完整区域拓扑的依赖;协议状态、收敛与防环方式不同,不能直接替换 OSPF 内部的 SPF 计算函数。

版本与适用范围#

依据 FRRouting frr-10.2 的 OSPFv2 区域内 SPF。这里描述控制面如何计算路由与下一跳,不是数据面收到报文后的最长前缀查找;区域间路由、外部路由与 TI-LFA 还各有额外处理。候选队列在此版本是跳表,不能据旧注释写成二叉堆。

参考来源#

源码、官方文档与原始论文
01
FRRouting · OSPF SPF 实现

ospfd/ospf_spf.c · vertex_cmp / ospf_spf_next / ospf_spf_calculate / ospf_spf_calculate_schedule_worker

源码frr-10.2

相关实现与比较#

1 个相关案例
9 个匹配案例