// 关闭设备上的ip协议
// 函数主要任务:
// 1.删除与设备相关的路由信息
// 2.刷新路由缓存
// 3.通知邻居子系统,与该设备有关的邻居项失效
1.1 static void fib_disable_ip(struct net_device *dev, int force)
{
if (fib_sync_down(0, dev, force))
fib_flush();
rt_cache_flush(0);
arp_ifdown(dev);
}
// 设备状态改变/删除ip,标记失效路由信息
// 参数:
// local,被删除的ip地址
// dev,被关闭的设备
// force:
// 0, local有效,表示ip地址被删除
// 1, dev有效,表示dev被关闭
// 2, dev有效,表示dev被注销
// 返回值:返回标记为dead的fib_info的数量
// 函数主要任务:
// 1.ip地址被删除
// 1.1 遍历fib_info_laddrhash,标记所有使用该地址作为首选源地址的fib_info->fib_flags|=RTNH_F_DEAD
// 2.设备状态发生改变
// 2.1 遍历fib_info_devhash,标记所有使用该设备的fib_nh->nh_flags|=RTNF_F_DEAD,如果fib_info的所有下一跳均失效,
// 或者设备注销,则标记fib_info->fib_flags|=RTNH_F_DEAD
// 3.返回失效fib_info个数
// 注:
// 1.
// fib_info_hash 所有fib_info结构被插入到这个hash表
// fib_info_laddrhash 路由表项有一个首选源地址时,插入到这个表
// 2.
// fib_create_info 添加新fib_info到fib_info_hash, fib_info_laddrhash,fib_info_cnt统计实例个数,当超过
// fib_hash_size时,fib_info_hash, fib_info_laddrhash容量同时增加一倍。
// 3.
// fib_info_devhash 索引与设备相关的所有下一跳的hash表
// 4.
// fib_info_devhash 静态分配256个bucket
2.1 int fib_sync_down(u32 local, struct net_device *dev, int force)
{
int ret = 0;
int scope = RT_SCOPE_NOWHERE;
//表示设备状态发生改变
if (force)
scope = -1;
//1.处理ip地址被删除
if (local && fib_info_laddrhash) {
unsigned int hash = fib_laddr_hashfn(local);
struct hlist_head *head = &fib_info_laddrhash[hash];
struct hlist_node *node;
struct fib_info *fi;
//遍历fib_info_laddr的bucket
hlist_for_each_entry(fi, node, head, fib_lhash) {
//凡是与该首选源地址相关的路由信息,均标识为失效
if (fi->fib_prefsrc == local) {
fi->fib_flags |= RTNH_F_DEAD;
ret++;//统计标识为失效的节点个数
}
}
}
//2.处理设备状态改变
if (dev) {
struct fib_info *prev_fi = NULL;
//对设备index hash
unsigned int hash = fib_devindex_hashfn(dev->ifindex);
struct hlist_head *head = &fib_info_devhash[hash];
struct hlist_node *node;
struct fib_nh *nh;
//遍历使用该设备的下一跳
hlist_for_each_entry(nh, node, head, nh_hash) {
struct fib_info *fi = nh->nh_parent;
int dead;
if (nh->nh_dev != dev || fi == prev_fi)
continue;
prev_fi = fi;
dead = 0;
//遍历路由信息的所有下一跳
change_nexthops(fi) {
//统计失效的下一跳个数
if (nh->nh_flags&RTNH_F_DEAD)
dead++;
else if (nh->nh_dev == dev &&
nh->nh_scope != scope) {
nh->nh_flags |= RTNH_F_DEAD;
//多路径路由
#ifdef CONFIG_IP_ROUTE_MULTIPATH
//下一跳失效,调整路由权重
spin_lock_bh(&fib_multipath_lock);
fi->fib_power -= nh->nh_power;
nh->nh_power = 0;
spin_unlock_bh(&fib_multipath_lock);
#endif
dead++;
}
#ifdef CONFIG_IP_ROUTE_MULTIPATH
//设备注销,与该设备相关的路由信息均失效
if (force > 1 && nh->nh_dev == dev) {
dead = fi->fib_nhs;
break;
}
#endif
} endfor_nexthops(fi)
//所有下一跳均失效,则标记该路由信息失效
if (dead == fi->fib_nhs) {
fi->fib_flags |= RTNH_F_DEAD;
ret++;
}
}
}
return ret;
}
// 删除失效路由信息
// 函数主要任务:
// 1.由路由表刷新路由表
// 2.刷新路由缓存
3.1 static void fib_flush(void)
{
int flushed = 0;
// 编译支持多路由表
#ifdef CONFIG_IP_MULTIPLE_TABLES
struct fib_table *tb;
int id;
//遍历255个路由表
for (id = RT_TABLE_MAX; id>0; id--) {
if ((tb = fib_get_table(id))==NULL)
continue;
//特定于路由表的刷新操作
flushed += tb->tb_flush(tb);
}
#else /* CONFIG_IP_MULTIPLE_TABLES */
flushed += ip_fib_main_table->tb_flush(ip_fib_main_table);
flushed += ip_fib_local_table->tb_flush(ip_fib_local_table);
#endif /* CONFIG_IP_MULTIPLE_TABLES */
//删除的路由个数>0,刷新路由缓存
if (flushed)
rt_cache_flush(-1);
}
// 设备开启,激活使用该设备的下一跳
// 在路由的某些下一跳为alive时,更新fib_info结构内该路由的一些参数。
// 返回值:RTNH_F_DEAD标识被清除的fib_info结构的个数
// 函数主要任务:
// 1.1 遍历与设备相关的下一跳信息
// 1.2 清除下一跳的RTNH_F_DEAD标志
// 1.3 清除该下一跳相关的路由信息的RTNH_F_DEAD标志
// 1.4 返回清除RTNH_F_DEAD标志的fib_info个数
// 注:只有内核支持多路径路由时才使用该函数
4.1 int fib_sync_up(struct net_device *dev)
{
struct fib_info *prev_fi;
unsigned int hash;
struct hlist_head *head;
struct hlist_node *node;
struct fib_nh *nh;
int ret;
//设备需要开启状态
if (!(dev->flags&IFF_UP))
return 0;
prev_fi = NULL;
hash = fib_devindex_hashfn(dev->ifindex);
head = &fib_info_devhash[hash];
ret = 0;
//与设备相关的所有下一跳
hlist_for_each_entry(nh, node, head, nh_hash) {
struct fib_info *fi = nh->nh_parent;
int alive;
if (nh->nh_dev != dev || fi == prev_fi)
continue;
prev_fi = fi;
alive = 0;
//遍历路由信息的下一跳,统计有效下一跳的个数
change_nexthops(fi) {
if (!(nh->nh_flags&RTNH_F_DEAD)) {
alive++;
continue;
}
if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
continue;
if (nh->nh_dev != dev || __in_dev_get(dev) == NULL)
continue;
alive++;
//设备开启,清除之前由于设备关闭而设置的RTNH_F_DEAD标志
spin_lock_bh(&fib_multipath_lock);
nh->nh_power = 0;
nh->nh_flags &= ~RTNH_F_DEAD;
spin_unlock_bh(&fib_multipath_lock);
} endfor_nexthops(fi)
//只要路由信息有一个有效的下一跳,则该路由信息有效
if (alive > 0) {
fi->fib_flags &= ~RTNH_F_DEAD;
ret++;
}
}
return ret;
}
// 绑定路由缓存到邻居子系统
5.1 int arp_bind_neighbour(struct dst_entry *dst)
{
struct net_device *dev = dst->dev;
struct neighbour *n = dst->neighbour;
if (dev == NULL)
return -EINVAL;
//此路由缓存还没有绑定邻居项
if (n == NULL) {
u32 nexthop = ((struct rtable*)dst)->rt_gateway;
//回环设备,点到点设备不需要绑定到邻居子系统
if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT))
nexthop = 0;
//根据出口设备,下一跳地址,寻找邻居项
n = __neigh_lookup_errno(
&arp_tbl, &nexthop, dev);
//绑定到路由缓存
dst->neighbour = n;
}
return 0;
}