参考文献:《深入理解linux网络技术内幕》
《精通linux内核网络》
代码内核版本:3.1.68
...............................................................................................
1. 初始化
ip_fib_init()
这个函数看似复杂,其实就主要作两件事:
1) 把参数struct notifier_block *nb 注册到netdev_chain通知链上去
2) 系统中所有已经被注册过或激活的网络设备的事件都要被新增的这个通知的回调函数重新调用一遍,这样让设备更新到一个完整的状态
在 路由子系统初始化时,系统会调用ip_fib_init() 函数,ip_fib_init() 中会注册一个回调函数到netdev_chain通知链,这样当别的子系统通知netdev_chain上有特定的事件类型发生时,路由子系统的相应回调 函数就可以作一些反应。
1181 void __init ip_fib_init(void) 1182 { 1183 fib_trie_init(); 1184 1185 register_pernet_subsys(&fib_net_ops); 1186 1187 register_netdevice_notifier(&fib_netdev_notifier); 1188 register_inetaddr_notifier(&fib_inetaddr_notifier); 1189 1190 rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, NULL); 1191 rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, NULL); 1192 rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, NULL); 1193 }
(1) int register_netdevice_notifier(struct notifier_block *nb)
功能: 在内核通知链netdev_chain上注册消息块,用来接收有关网络设备的注册状态等信息
nb:消息块,在里面自己添加消息处理函数
返回值:成功返回0
头文件:#include <linux/netdevice.h>
(2) int unregister_netdevice_notifier(struct notifier_block *nb)
功能:与上面register_netdevice_notifier为一对,用于在通知链netdev_chain上删除消息块
(3) int register_inetaddr_notifier(struct notifier_block *nb)
功能: 在内核通知链inetaddr_chain上注册消息块,用于接收ip地址的改变等事件
nb:消息块,在里面自己添加消息处理函数
返回值:成功返回0
头文件: #include <linux/inetdevice.h>
(4) int unregister_inetaddr_notifier(struct notifier_block *nb)
功能:与上面register_inetaddr_notifier为一对,用于在通知链inetaddr_chain上删除消息块
fib_netdev_notifier的定义:
static struct notifier_block fib_netdev_notifier = {
.notifier_call =fib_netdev_event,
};
fib_netdev_notifier就是一个struct notifier_block,其中.priority默认初始化为0,.next由注册时设定
事件说明
#define NETDEV_UP 0x0001//激活一个网络设备
#define NETDEV_DOWN 0x0002//停止一个网络设备,所有对该设备的引用都应释放
#define NETDEV_REBOOT 0x0003 //检查到网络设备接口硬件崩溃,硬件重启
#define NETDEV_CHANGE 0x0004 //网络设备的数据包队列状态发生改变
#define NETDEV_REGISTER 0x0005//一个网络设备事例注册到系统中,但尚未激活
#define NETDEV_UNREGISTER 0x0006//网络设备驱动已卸载
#define NETDEV_CHANGEMTU 0x0007//MTU发生了改变
#define NETDEV_CHANGEADDR 0x0008//硬件地址发生了改变
#define NETDEV_GOING_DOWN 0x0009//网络设备即将注销,有dev->close报告,通知相关子系统处理
#define NETDEV_CHANGENAME 0x000A//网络设备名改变
#define NETDEV_FEAT_CHANGE 0x000B//网络硬件功能改变
再来大致看一下函数fib_netdev_event() :
1046 static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) 1047 { 1048 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 1049 struct netdev_notifier_info_ext *info_ext = ptr; 1050 struct in_device *in_dev; 1051 struct net *net = dev_net(dev); 1052 1053 if (event == NETDEV_UNREGISTER) { 1054 fib_disable_ip(dev, 2); 1055 rt_flush_dev(dev); 1056 return NOTIFY_DONE; 1057 } 1058 1059 in_dev = __in_dev_get_rtnl(dev); 1060 if (!in_dev) 1061 return NOTIFY_DONE; 1062 1063 switch (event) { 1064 case NETDEV_UP://激活一个网络设备 1065 for_ifa(in_dev) { 1066 fib_add_ifaddr(ifa); 1067 } endfor_ifa(in_dev); 1068 #ifdef CONFIG_IP_ROUTE_MULTIPATH 1069 fib_sync_up(dev); 1070 #endif 1071 atomic_inc(&net->ipv4.dev_addr_genid); 1072 rt_cache_flush(net); 1073 break; 1074 case NETDEV_DOWN://停止一个网络设备,所有对该设备的引用都应释放 1075 fib_disable_ip(dev, 0); 1076 break; 1077 case NETDEV_CHANGEMTU: 1078 fib_sync_mtu(dev, info_ext->ext.mtu); 1079 rt_cache_flush(net); 1080 break; 1081 case NETDEV_CHANGE: 1082 rt_cache_flush(net); 1083 break; 1084 } 1085 return NOTIFY_DONE; 1086 }
使用举例
1 #include <linux/module.h> 2 #include <linux/init.h> 3 #include <linux/kernel.h> 4 #include <linux/types.h> 5 #include <linux/netdevice.h> 6 #include <linux/inetdevice.h> 7 8 //处理网络设备的启动与禁用等事件 9 int test_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) 10 { 11 struct net_device *dev = (struct net_device *)ptr; 12 switch(event) 13 { 14 case NETDEV_UP: 15 if(dev && dev->name) 16 printk("test dev[%s] is up\n",dev->name); 17 break; 18 case NETDEV_DOWN: 19 if(dev && dev->name) 20 printk("test dev[%s] is down\n",dev->name); 21 break; 22 default: 23 break; 24 } 25 26 return NOTIFY_DONE; 27 } 28 29 //处理ip地址的改变事件 30 int test_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr) 31 { 32 33 struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; 34 struct net_device *dev = NULL; 35 36 if(ifa && ifa->ifa_dev) 37 dev = ifa->ifa_dev->dev; 38 39 switch(event) 40 { 41 case NETDEV_UP: 42 if(dev && dev->name) 43 printk("inet[%p] is up\n",dev->name); 44 break; 45 case NETDEV_DOWN: 46 if(dev && dev->name) 47 printk("inet[%p] is down\n",dev->name); 48 default: 49 break; 50 51 } 52 53 return NOTIFY_OK; 54 } 55 56 struct notifier_block inethandle={ 57 .notifier_call = test_inetaddr_event 58 }; 59 60 struct notifier_block devhandle={ 61 .notifier_call = test_netdev_event 62 }; 63 64 static int __init net_event_init(void) 65 { 66 /* 67 在netdev_chain通知链上注册消息块 68 netdev_chain通知链是内核中用于传递有关网络设备注册状态的通知信息 69 */ 70 register_netdevice_notifier(&devhandle); 71 72 /* 73 在inetaddr_chain通知链上注册消息块 74 inetaddr_chain通知链是内核中用于传递有关本地接口上的ipv4地址的插入,删除以及变更的通知信息 75 */ 76 register_inetaddr_notifier(&inethandle); 77 return 0; 78 } 79 80 static void __exit net_event_exit(void) 81 { 82 unregister_netdevice_notifier(&devhandle); 83 unregister_inetaddr_notifier(&inethandle); 84 return; 85 } 86 87 88 module_init(net_event_init); 89 module_exit(net_event_exit); 90 MODULE_LICENSE("GPL");
原文地址:https://www.cnblogs.com/mysky007/p/12251382.html