1.什么是邻居子系统
邻居:是指同一个IP局域网内的主机,或者邻居之间在三层上仅相隔一跳距离。
邻居子系统:提供了三层协议地址与二层协议地址之间的映射关系。同时还提供了二层首部缓存,用以加速发送数据报文,
以ipv4 发送数据为例,在发送数据时,先进行路由查找,如果查找到目的地址路径,再查看邻居表中是否存在响应的映射关系,
如果没有则新建邻居关系,然后判断邻居是否可用,如果不可用则将报文缓存到发送队列,然后发送建立邻居请求,在接收到应答后,
将邻居设置为可用状态,并且将缓存中的报文发送出去。如果在指定时间内没有收到响应报文,则将对应邻居设置为无用状态,并且超时后将
缓存报文丢弃。简单来说就是为 :为每个协议缓存L3到L2的地址提供缓存的添加,删除,改变和查找 ,为每个协议缓存的数据项提供老化机制,为每个邻居提供一个请求队列
2、邻居系统相关参数
2.1邻居子系统的状态
/* * Neighbor Cache Entry States. */ #define NUD_INCOMPLETE 0x01 #define NUD_REACHABLE 0x02 #define NUD_STALE 0x04 #define NUD_DELAY 0x08 #define NUD_PROBE 0x10 #define NUD_FAILED 0x20 /* Dummy states */ #define NUD_NOARP 0x40 #define NUD_PERMANENT 0x80 #define NUD_NONE 0x00 /* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change and make no address resolution or NUD. NUD_PERMANENT is also cannot be deleted by garbage collectors. */ /* * NUD stands for "neighbor unreachability detection" */ #define NUD_IN_TIMER (NUD_INCOMPLETE|NUD_REACHABLE|NUD_DELAY|NUD_PROBE) #define NUD_VALID (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY) #define NUD_CONNECTED (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE)
NUD_INCOMPLETE :该状态是请求报文已发送,但尚未收到应答的状态。该状态下还没解析到硬件地址,因此尚无可用硬件地址,如果有报文要输出到该邻居,会将其缓存起来。
这个状态会启动一个定时器,如果在定时器到期时还没有接收到邻居的回应,则会重复发送请求报文,否则发送请求报文的次数打到上限,便会进入NUD_FAILED。
NUD_REACHABLE :该状态以及得到并缓存了邻居的硬件地址。进入该状态首先设置邻居项相关的output函数(该状态使用neighbors_ops结构的connectd_outpt),
然后查看是否存在要发送给该邻居的报文。如果在该状态下闲置时间达到上限,便会进入NUD_STATLE。
NUD_STALE :该状态一旦有报文要输出到该邻居,则会进入NUD_DELAY并将该报文输出。如果在该状态下闲置时间达到上限,且此时的引用计数为1,
则通过垃圾回收机制将其删除,在该状态下,报文的输出不收限制,使用慢速发送过程
NUD_DELAY :该状态下表示NUD_STATE状态下发送的报文已经发出,需得到邻居的可达性确认的状态。在为接收到邻居的应答或确认时也会定时地重发请求,
如果发送请求报文的次数到上限,如果收到邻居的应答,进入NUD_REACHABLE,否则进入NUD_FAILED,在该状态下,报文的输出不收限制,使用慢速发送过程。
NUD_PROBE :过渡状态,和NUD_INCOMPLETE 状态类似,在未收到邻居状态的应答或者确认时,也会定时的重发请求,直到收到邻居的应答、确认、或者尝试发送请求报文的次数达到上限,如果收到
应答或者确认就会进入NUD_REACHABLE,如果尝试发送请求到达上限,则进入NUD_FAILD状态,在该状态,报文的输出也不受限制,使用慢速发送过程。
NUD_FAILED :由于没有收到应答报文而无法访问状态,
NUD_NOARP :标识邻居无需将三层地址协议映射到二层地址协议。发往lo回环接口的报文其arp表项为NUD_NOARP
NUD_PERMANENT : 设置邻居表项的硬件地址已经变味静态,不需要去将三层地址翻译映射到二层地址。
这些是基本状态,根据这些基本状态组合了几个相对有语义的状态。
-
NUD_VALID 表示该地址会是一个有效的地址
NUD_PERMANENT NUD_NOARP NUD_REACHABLE NUD_PROBE NUD_STALE NUD_DELAY
-
NUD_CONNECTED 是 NUD_VALID 的子集,去除了待决的中间状态
NUD_PERMANENT NUD_NOARP NUD_REACHABLE
-
NUD_IN_TIMER 表示在这个状态下正在执行一个定时任务,一般是状态不明了的时候根据状态变迁图可以看到那些状态需要设置定时器
NUD_INCOMPLETE NUD_DELAY NUD_PROBE
2.2 邻居表项的添加和删除
应用层可以通过arp ip 命令添加 删除邻居表项;在添加路由项和路径绑定时也会触发创建邻居项。当接收到并非请求的应答报文同样也能触发创建邻居表项。
邻居表项的删除除了ip arp 外就是在垃圾定时器回收回调中处理。
有关邻居操作的netlink消息:
struct ndmsg { __u8 ndm_family; //地址族 __u8 ndm_pad1; __u16 ndm_pad2; __s32 ndm_ifindex; //邻居项的网络设备索引号 __u16 ndm_state; //邻居项的状态 __u8 ndm_flags;// NTF_PROXY 代理项 NTF_ROUTER 路由 __u8 ndm_type; }; enum {//neigh netlink 消息的扩展属性字段 NDA_UNSPEC, NDA_DST, NDA_LLADDR, NDA_CACHEINFO, NDA_PROBES, __NDA_MAX }; #define NDA_MAX (__NDA_MAX - 1) /* * Neighbor Cache Entry Flags */ #define NTF_USE 0x01 #define NTF_PROXY 0x08 /* == ATF_PUBL */ #define NTF_ROUTER 0x80 #define NTF_SELF 0x02 #define NTF_MASTER 0x04
执行ip neighbour del 等 会调用内核的neigh_del neigh_add 函数
static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 详见 内核,再次不做详细说明