最近学习路由子系统,进行了一些总结。因为个人喜欢比较喜欢ubuntu的哲学精神,因此想将自己在技术上的一些总结进行记录,一是做为一种记录方便以后查阅,二是做为一种分享吧。有什么不对的地方,请不吝赐教,本人将感激不尽!
内核版本是linux-2.6.31.8
介绍路由子系统的初始化流程
inet_init() @net/ipv4/Af_inet.c
--- >ip_init() @net/ipv4/ip_output.c
//路由子系统初始化函数
--->ip_rt_init() @net/ipv4/route.c
//使用通知链注册一个处理函数,用Netlink套接字为地址和路由命令注册处理函数
--->devinet_init() @net/ipv4/devinet.c
//初始化默认路由表,用两个通知链注册两个处理函数
注册了对ipv4路由表进行操作的接口
--->ip_fib_init() @net/ipv4/fib_frontend.c
//路由子系统相关的初始化工作在这个函数里完成
int __init ip_rt_init(void)
{
intrc = 0;
#ifdef CONFIG_NET_CLS_ROUTE
ip_rt_acct= __alloc_percpu(256 * sizeof(struct ip_rt_acct), __alignof__(structip_rt_acct));
if(!ip_rt_acct)
panic("IP:failed to allocate ip_rt_acct\n");
#endif
//ipv4_dst_ops提供了一组虚函数,这些函数能使更高层的协议调用具体协议中操作缓存表项的函数;分配新的缓存表项时会用到dst_alloc(&ipv4_dst_ops)dst_alloc(&ip6_dst_ops)
ipv4_dst_ops.kmem_cachep = kmem_cache_create("ip_dst_cache",sizeof(struct rtable), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
ipv4_dst_blackhole_ops.kmem_cachep= ipv4_dst_ops.kmem_cachep;
//用hash表定义的路由缓存,这里为路由缓存分配内存
rt_hash_table = (struct rt_hash_bucket *)
alloc_large_system_hash("IProute cache",
sizeof(structrt_hash_bucket),
rhash_entries ,//内核默认的缓存容量可以被用户启动选项rhash_entries所覆盖,该选项保存的hash表的容量
(num_physpages>= 128 * 1024) ?
15: 17,
0,
&rt_hash_log,//rt_hash_mask以2为对数所得的值,也是表示hash表的容量
&rt_hash_mask,//表示hash表rt_hash_table的容量,即bucket的数目
rhash_entries? 0 : 512 * 1024);
memset(rt_hash_table,0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket));
rt_hash_lock_init() ;//初始化rt_hash_table表,各个桶的锁
ipv4_dst_ops.gc_thresh = (rt_hash_mask + 1);//路由缓存垃圾回收的峰值,在后面删除路由缓存项时会涉及
ip_rt_max_size= (rt_hash_mask + 1) * 16; //路由缓存表最大能容纳的路由缓存项目数
devinet_init() ;//注册与设备状态相关的处理函数
ip_fib_init();//注册与设备IP配置相关的处理函数
/*All the timers, started at system startup tend
to synchronize. Perturb it a bit.
*/
INIT_DELAYED_WORK_DEFERRABLE(&expires_work,rt_worker_func); //垃圾回收定时器,在rt_worker_func里面会调用rt_check_expire清除过期的缓存项
expires_ljiffies= jiffies;
schedule_delayed_work(&expires_work,
net_random()% ip_rt_gc_interval + ip_rt_gc_interval);
if(register_pernet_subsys(&rt_secret_timer_ops))
printk(KERN_ERR"Unable to setup rt_secret_timer\n");
if(ip_rt_proc_init())
printk(KERN_ERR"Unable to create route proc files\n");
#ifdef CONFIG_XFRM //IPSEC相关的初始化
xfrm_init();
xfrm4_init();
#endif
rtnl_register(PF_INET,RTM_GETROUTE, inet_rtm_getroute, NULL);
#ifdef CONFIG_SYSCTL
register_pernet_subsys(&sysctl_route_ops);
#endif
#ifdef CONFIG_MV_ETH_NFP
fp_rule_db_init(rt_hash_mask+ 1);
fp_arp_db_init(rt_hash_mask+ 1);
#endif /* CONFIG_MV_ETH_NFP */
returnrc;
}
1. 网络设备状态的变化
a) NETDEV_UNREGISTER //注销设备原因可能是用户从内核中删除该设备的驱动程序或拔出一块热插拔设备,比如PCMCIA以太网卡
b) NETDEV_UP //启动设备
c) NETDEV_DOWN //关闭设备原因可能是用户拔出网线或发出一条管理命令关闭设备
d) NETDEV_CHANGEMTU //改变了设备的MTU
e) NETDEV_CHANGE //
因此在初始化路由子系统的时候,路由子系统在通知链netdev_chain与inetaddr_chain上注册了处理函数进行处理网络设备状态变化和网络设备上IP配置的变化。注册的处理函数如下:
static struct notifier_block fib_inetaddr_notifier = {
.notifier_call = fib_inetaddr_event, //处理网络设备IP地址变化的情况
};
static struct notifier_block fib_netdev_notifier = {
.notifier_call = fib_netdev_event, //处理网络设备状态变化的情况
};