//路由缓存内存量指定办法:
//1.通过启动参数rhash_entries指定hash表bucket个数
//2.根据物理内存页数确定使用的内存量
//根据物理页数分配缓存内存:
//1.goal目标内存页数=总页数/(2**(26-PAGE_SHIFT))
//2.最接近goal内存页数的order,用于从伙伴系统中分配
//3.rt_hash_mask=order页可容纳的bucket数
//4.对齐rt_hash_mask到2的幂次
//5.从伙伴系统中分配order页物理内存
//路由缓存阈值:
//1.gc_thresh=bucket个数,当路由缓存数超过此阈值时,rt_garbage_collect同步回收内存
//2.ip_rt_max_size=16*(bucket个数),当路由缓存超过此阈值时,dst_alloc会失败
//路由子系统初始化
//调用路径:ip_init->ip_rt_init
//函数主要任务:
//1.分配dst缓存的slab缓存
//2.分配路由缓存表
//3.向netdev_chain注册监听块
//4.初始化默认路由表
//5.初始化路由缓存使用的定时器
//5.1 垃圾回收定时器
//5.2 缓存刷新定时器
//5.3 缓存周期性刷新定时器
//6.初始化IPSec与路由子系统交互的衔接点
1.1 int __init ip_rt_init(void)
{
int i, order, goal, rc = 0;
//
rt_hash_rnd = (int) ((num_physpages ^ (num_physpages>>8)) ^
(jiffies ^ (jiffies >> 7)));
//dst缓存
ipv4_dst_ops.kmem_cachep = kmem_cache_create("ip_dst_cache",
sizeof(struct rtable),
0, SLAB_HWCACHE_ALIGN,
NULL, NULL);
//根据物理内存数计算路由缓存使用的内存页数
goal = num_physpages >> (26 - PAGE_SHIFT);
if (rhash_entries)//rhash_entries为启动参数,
goal = (rhash_entries * sizeof(struct rt_hash_bucket)) >> PAGE_SHIFT;
//计算缓存使用内存页个数以2为底的order
for (order = 0; (1UL << order) < goal; order++);
//rt_hash_mask为bucket的个数
do {
rt_hash_mask = (1UL << order) * PAGE_SIZE /
sizeof(struct rt_hash_bucket);
//使rt_hash_mask 对齐到2的幂次
while (rt_hash_mask & (rt_hash_mask - 1))
rt_hash_mask--;
//分配路由缓存
rt_hash_table = (struct rt_hash_bucket *)
__get_free_pages(GFP_ATOMIC, order);
} while (rt_hash_table == NULL && --order > 0);
for (rt_hash_log = 0; (1 << rt_hash_log) != rt_hash_mask; rt_hash_log++);
//初始化每个bucket使用的自选锁
rt_hash_mask--;
for (i = 0; i <= rt_hash_mask; i++) {
spin_lock_init(&rt_hash_table[i].lock);
rt_hash_table[i].chain = NULL;
}
//垃圾回收的域值
ipv4_dst_ops.gc_thresh = (rt_hash_mask + 1);
//路由缓存最多保存的缓存个数
ip_rt_max_size = (rt_hash_mask + 1) * 16;
//per-cpu统计变量
rt_cache_stat = alloc_percpu(struct rt_cache_stat);
//向netdev_chain注册监听块,用netlink为地址和路由命令注册处理函数
devinet_init();
//初始化默认路由表
ip_fib_init();
//缓存刷新定时器
init_timer(&rt_flush_timer);
rt_flush_timer.function = rt_run_flush;
//垃圾回收定时器
init_timer(&rt_periodic_timer);
rt_periodic_timer.function = rt_check_expire;
//缓存刷新周期定时器
init_timer(&rt_secret_timer);
rt_secret_timer.function = rt_secret_rebuild;
rt_periodic_timer.expires = jiffies + net_random() % ip_rt_gc_interval +
ip_rt_gc_interval;
add_timer(&rt_periodic_timer);
rt_secret_timer.expires = jiffies + net_random() % ip_rt_secret_interval +
ip_rt_secret_interval;
add_timer(&rt_secret_timer);
//处理路由子系统与IPSec的衔接
#ifdef CONFIG_XFRM
xfrm_init();
xfrm4_init();
#endif
return rc;
}
//监听外部事件
//调用路径:ip_rt_init->devinet_init
1.2 void __init devinet_init(void)
{
//netdev_chian监听块
register_netdevice_notifier(&ip_netdev_notifier);
//通过netlink为路由命令注册处理程序
rtnetlink_links[PF_INET] = inet_rtnetlink_table;
}