zoukankan      html  css  js  c++  java
  • 通知链netdev_chain和inetaddr_chain区别以及使用

    参考文献:《深入理解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
    ",dev->name);
    17              break;
    18         case NETDEV_DOWN:
    19              if(dev && dev->name)
    20                  printk("test  dev[%s] is down
    ",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
    ",dev->name);
    44             break;
    45         case NETDEV_DOWN:
    46              if(dev && dev->name)
    47                  printk("inet[%p] is down
    ",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");
  • 相关阅读:
    linux下编译GDAL3.x(集成Proj和Geos等)
    CSS后代选择器、子元素选择器、相邻兄弟选择器区别与详解
    CSS hover伪类改变其他元素的样式
    PHP 删除数组指定元素
    CakePHP 调试方法 汇总
    Linux/Mac OS 在终端使用 code 命令打开项目 VSCode
    苹果 MacOS 安装 Source Code Pro
    MacOS 安装 Homebrew 错误处理 Connection refused
    修改 VSCode 终端 Terminal 的字体
    spring cloud gateway自定义过滤器
  • 原文地址:https://www.cnblogs.com/mysky007/p/12251382.html
Copyright © 2011-2022 走看看