距离向量路由、Bellman-Ford与收敛问题
距离向量算法(Distance-Vector Routing Protocol)
距离向量算法是分布式的,因为每个结点都要从一个或多个直连邻居接收信息,执行计算,然后将结果分发给邻居。
距离向量算法根据Bellman-Ford方程得来,其中表示从x到y的最小开销,表示x到邻居v的开销,表示从邻居v到终点y的开销。
这个方程的含义很直观:如果从x出发先走到邻居v,再沿v的最低开销路径到达y,开销是;x只需要在所有邻居中选出使这个和最小的那一个,它同时也是x到y的下一跳。
该算法的结点具有的唯一信息是它到直接邻居的链路开销和它从这些邻居接收到的信息,每个结点等待来自任何邻居的更新。
每个结点x维护三样东西:到每个邻居v的链路开销;自己的距离向量,即x对它到每个目的的最低开销的估计;以及从每个邻居收到的最新距离向量。算法的执行过程如下:
初始化:
对每个目的y:D_x(y) = c(x, y)(不是邻居则为∞),D_x(x) = 0
把D_x发给所有邻居
循环:
等待(直连链路开销变化,或收到邻居发来的距离向量)
对每个目的y:D_x(y) = min_v{c(x, v) + D_v(y)}
如果D_x中有任何值发生变化,把新的D_x发给所有邻居距离向量算法是迭代的(不断交换直到没有新信息)、异步的(各结点不必同时计算)和自我终止的(没有变化时就不再发送消息)。
交换距离向量,直到不再变化
解锁完整互动实验、进阶解析与精选参考答案。
知识测验
链路开销变化与无穷计数问题
当某条链路的开销减小时,“好消息”会很快在网络中传开:每个结点算出更小的开销后立即通知邻居,几轮之后就收敛了。
开销增大时情况就不同了。考虑三个结点x、y、z:,,。原先(直达),(经过y)。现在增大到60:
- y发现变化,用z此前通告的计算:,于是改为经过z到达x。可z到x的路径恰恰要经过y,这就形成了路由环路。
- z收到y的新向量,算出,通告给y。
- y又算出8,z又算出9……两者轮流把开销加1。
这样的交换要重复四十多次,直到z算出经过y的开销超过50、改为直达x为止。如果本身也很大甚至不存在,开销会一直增加下去,这称为无穷计数(count-to-infinity)问题。
毒性逆转(poisoned reverse)可以避免这种两个结点之间的环路:如果z经过y到达x,那么z向y通告。y就不会再选择经过z回到x,在上例中y直接算出,很快收敛。不过毒性逆转无法解决涉及三个或更多结点的环路。
观察坏消息“数到无穷”
解锁完整互动实验、进阶解析与精选参考答案。
知识测验
链路状态与距离向量的比较
| 链路状态(LS) | 距离向量(DV) | |
|---|---|---|
| 每个结点掌握的信息 | 全网拓扑与所有链路开销 | 到邻居的开销与邻居的距离向量 |
| 报文 | 每个结点向全网泛洪LSA | 只与邻居交换距离向量 |
| 收敛速度 | 本地运行Dijkstra, | 可能较慢,存在环路与无穷计数问题 |
| 健壮性 | 每个结点独立计算自己的转发表,错误影响有限 | 一个结点通告的错误开销会扩散到全网 |
因特网中两种算法都在使用:OSPF基于链路状态,RIP基于距离向量。RIP以跳数作为开销,最大跳数为15,16表示不可达(“无穷”),从而给无穷计数设了一个上限。
计算一个结点的新距离向量
结点a的邻居为b、c、d,链路开销c(a,b) = 3,c(a,c) = 1,c(a,d) = 6。a刚刚收到以下距离向量(目的依次为a、b、c、d、e):
用Bellman-Ford方程计算D_a(b)、D_a(c)、D_a(d)、D_a(e)以及各自的下一跳。
用Python模拟同步的距离向量交换
用Python表示下面的网络。开始时每个结点只知道自己的直连链路。每一轮中,所有结点都根据邻居在本轮开始时的向量重新计算自己的整个向量。每轮结束后打印所有结点到d的开销,在第一次出现没有任何变化的轮次后停止。