1. 目标
lab6 主要要实现一个路由的机制,首先互联网由多个局域网组成(不太严谨的说法),在 lab5 中我们只能支持在单个局域网中传递消息,确定目标地址(arp)。
而跨局域网的情况下,需要确定跨局域网的路由器地址,这里就需要用到路由表。
路由器的主要工作就是为经过路由器的每个数据包寻找一条最佳的传输路径,并将该数据有效地传送到目的站点。由此可见,选择最佳路径的策略即路由算法是路由器的关键所在。为了完成这项工作,在路由器中保存着各种传输路径的相关数据——路由表(Routing Table),供路由选择时使用,表中包含的信息决定了数据转发的策略。打个比方,路由表就像我们平时使用的地图一样,标识着各种路线,路由表中保存着子网的标志信息、网上路由器的个数和下一个路由器的名字等内容。路由表可以是由系统管理员固定设置好的,也可以由系统动态修改,可以由路由器自动调整,也可以由主机控制。
lab6 中主要要实现的是两个接口
//! Send a single datagram from the appropriate outbound interface to the next hop,
//! as specified by the route with the longest prefix_length that matches the
//! datagram's destination address.
void route_one_datagram(InternetDatagram &dgram);
//! Add a route (a forwarding rule)
void add_route(const uint32_t route_prefix,
const uint8_t prefix_length,
const std::optional<Address> next_hop,
const size_t interface_num);
添加路由规则和正确路由一个数据报。
2. 实现
2.1 add_route
添加路由的逻辑比较简单,其实就是将参数中路由规则添加到路由表中,需要自定义一个路由表缓存结构。其中比较关键的参数为 route_prefix
和 prefix_length
,这两者可以构建出一个 ip 范围。
假设有 ip “18.47.0.0/16”,那么它的 route_prefix
就是 305070080 (18 × 224 + 47 × 216)
,而 prefix_length 则是 16。
这里选择将参数都塞到一个结构体 RouteRule
,然后用 vector
存放 RouteRule
。
2.2 route_one_datagram
路由表的目的是为了确认数据报的目标地址是否在路由表中有匹配的路由,路由匹配规则参考下图
由此可以确定,匹配一个路由的规则为:
route_prefix
右移 32 - prefix_length
位,目标 ip 地址也同样右移相同位数,然后比较两者是否相等,相等表示路由规则匹配。此外需要区别一种特殊情况,即 prefix_length
为 0,这时路由是满足匹配条件的。
接口的大致流程如下:
- 根据路由匹配规则,遍历路由表获取匹配的路由
- 当存在多条路由匹配的时候,选择
prefix_length
最长的路由规则 - 如果没有匹配的路由,则 drop 数据报
- 递减 datagram 的 ttl,如果递减完后 ttl 为 0 或者递减前 ttl 为 0,则 drop 数据报
- 条件满足的情况下,发送数据报
TTL是 Time To Live的缩写,该字段指定IP包被路由器丢弃之前允许通过的最大网段数量。TTL是IPv4报头的一个8 bit字段。