neighboring subsystem 浅析
neighbor 在协议栈里指的是同一个 LAN 下面的邻居,也就是他们在 L3 上通过媒介或者点对点连接在了一起。邻居子系统同时也可以理解为一个 L2 和 L3 地址的转换器。邻居子系统的目的就在于上层协议不应该关心下层的地址信息,我发送过来的 IP 地址应该让下层来决定发送到哪个 MAC 地址。neighbor solicitation and neighbor advertisement,可以分别对应 ARP 的 request 请求和 ARP 的 reply 请求。
邻居子系统主要缓存两大块的内容,一个是 L3 到 L2 的映射解析的缓存,一个是 L2 头的缓存,缓存 L2 头的原因是大部分 L2 的头基本上是重复的,所以通过缓存头部可以加快协议的封装。
以下有几个相关结构体需要介绍一下。
struct neighbour 代表的是一个邻居的信息,比如 L2 和 L3 地址等。
struct neigh_table 代表的是一种邻居协议的接口(比如 ARP)。
struct neigh_params 代表的是邻居协议在每个设备上的不同参数。
struct neigh_ops 邻居对应的一些操作函数。
struct hh_cache 缓存 L2 的头部,不是所有的设备都支持头部缓存。
struct rttable 和 struct dst_enry, IPv4 的路由缓存信息是通过 struct rttable 缓存的。
这是 dst_entry, hh_cache 和 neighbour 之间的关系。
neighbor 结构是用 hash 存储的,key 是 L3 地址加设备(对应的 device 结构体)加一个随机值。hash 表通过 neigh_hash_alloc 和 neigh_hash_free 来分配和释放。neigh_lookup 就是通过 key 从 hash table 中找到对应的 neighbour 结构体,实现都不复杂,这里理解就可以了。
一般邻居子系统的缓存流程是这样的,如果 L3 的请求到达,地址解析缓存没有命中,把 L3 packet 入队,开始neighbor solicitation 等收到 neighbor advertisement 之后再出队并且发送。