MyException - 我的异常网
当前位置:我的异常网» Linux/Unix » 深入懂得Linux网络技术内幕——设备的注册与初始化

深入懂得Linux网络技术内幕——设备的注册与初始化(二)

www.MyException.Cn  网友分享于:2015-02-11  浏览:0次
深入理解Linux网络技术内幕——设备的注册与初始化(二)

设备注册于设备除名

    设备注册与设备除名一般有 register_netdev和unregister_netdev完成。这两个是包裹函数,负责上锁,真正起作用的是其调用的register_netdevice和unregister_netdevice。参见:net/core/dev.c。
    下图描述了设备注册过程中的一些状态变化



    状态的改变会用到UNINITIALIZED和REGISTERED之间的状态REGISTERING。这些进程有netdev_run_todo进行。参照“切割操作:netdev_run_todo”
    为设备进行注册和除名时,设备驱动程序可以使用net_device的两个虚拟函数init和uninit进行私有数据的初始化和清理工作。
    设备除名时,只有对net_device的引用计数为0,netdev_wait_allrefs才会返回,除名工作才会顺利完成。
    设备的注册和除名操作都是由netdev_run_todo完成的。

切割操作:netdev_run_todo

    register_netdevice会负责一部分的注册工作,然后再让netdev_run_todo予以完成。
    net_device的改变会通过rtnl_lock和rtnl_unlock收到Routing Netlink信号量的保护。这也是为什么register_netdev执行时需要请求锁,并且在返回时要释放锁的原因。一旦register_netdevice完成了它自己的工作,它会通过net_set_todo将net_device结构体添加到net_todo_list中。net_todo_list包含一系列有注册(或除名)操作需要被完成的设备列表。这份列表有register_netdev在释放锁时间接予以处理。
    因此rtnl_unlock不仅会释放锁,还会调用 netdev_run_todo。netdev_run_todo会浏览net_todo_list列表,然后完成全部的实例注册。

void rtnl_unlock(void)
{
    /* This fellow will unlock it for us. */
    netdev_run_todo();                                                          
}
EXPORT_SYMBOL(rtnl_unlock);
    netdev_run_todo所进行的工作不需要持有锁。


设备注册状态通知

    内核组件和应用程序都可能想知道设备的注册、除名、开启、关闭。设备装态信息通过两种方式传送通知。
netdev_chain
Netlink的 RTMGRP_LINK多播组

netdev_chain通知链:
    设备的注册和除名阶段各个状态的变化都是通过netdev_chain来进行通告的。对其感兴趣的内核组件可以分别通过register_netdevice_notifier和unregister_netdevice_notifier来针对该链进行注册和除名。
    netdev_chain报告的事件定义在:
//格式:
#define NETDEV_UP   0x0001  /* For now you can't veto a device up/down */
#define NETDEV_DOWN 0x0002
......
 
//含义:
NETDEV_UP        //该报告表明设备被启用,由dev_open产生报告
NETDEV_DOWN      //设备已关闭,由dev_close生成报告
NETDEV_REBOOT    //因硬件设备,设备已重启
NETDEV_CHANGE    //设备的状态或者配置发生改变
NETDEV_REGISTER        //设备已经注册
NETDEV_UNREGISTER      //设备已经除名
NETDEV_CHANGEMTU       //
NETDE   //
NETDEV_PRE_UP               //
NETDEV_PRE_TYPE_CHANGE      //
NETDEV_POST_TYPE_CHANGE     //
NETDEV_POST_INIT            //
NETDEV_UNREGISTER_FINAL     //
NETDEV_RELEASE              //
NETDEV_NOTIFY_PEERS         //
NETDEV_JOIN                 //
NETDEV_CHANGEUPPER  
V_CHANGEADDR      //设备硬件地址(或关联的广播地址)发生改变
NETDEV_GOING_DOWN      //
NETDEV_CHANGENAME      //设备名称发生改变
NETDEV_FEAT_CHANGE     //
NETDEV_BONDING_FAILOVER  
        //
NETDEV_RESEND_IGMP          //


 很多设备都在netdev_chain中注册,如:路由,防火墙
RTnetlink链接通知
    当设备发生一些状态改变(或其它事件),会通过rtmsg_ifinfo把通知传给link多播组。

设备注册:

    设备注册不仅仅只是把net_device嵌入到全局表dev_base和哈希表dev_name_head、dev_index_head中,它还包括初始化net_device部分参数,发送广播通告(提醒其他模块本设备加入)、以及一些其他的工作。
int register_netdev(struct net_device *dev)
{
    int err; 
 
    rtnl_lock();
    err = register_netdevice(dev);                                                                                       
    rtnl_unlock();
    return err; 
}
    register_netdevice开始设备注册工作,并调用net_set_todo,而net_set_todo最终会调用netdev_run_todo完成注册。
    register_netdevice的工作主要包括以下部分:
  •     初始化net_device的部分字段
  •     如果内核支持Divert功能,则用alloc_divert_blk分配该功能所需的数据空间块,并连接至dev->divert
  •     如果设备驱动已经对dev->init进行初始化,则执行此函数。
  •     由dev_new_index分配给设备一个识别码。
  •     把net_device插入到全局表dev_base,以及两张哈希表dev_name_head,dev_index_head。
  •     检查功能标识是否有无效的组合。
  •     设置dev->state中的__LINK_STATE_PRESENT标识,使得设备能为内核所用。
  •     用dev_init_scheduler初始化设备队列规则,以便流量控制用于实现Qos。
  •     通过netdev_chain通知表链通知所有对本设备注册感兴趣的子系统。
    当netdev_run_todo被调用完成注册时,它只更新dev->reg_state,并将设备注册进入sysfs。

设备除名:

    设备除名需要复原设备注册期间所进行的所有工作和一些其他事项:
  •     用dev_close关闭设备
  •     释放所有分配的资源(IRQ、I/O端口...)
  •     从全局表dev_base和两张哈希表中删除设备
  •     当该设备的所有引用都释放后,释放net_device结构的空间、该驱动程序的私有数据结构、以及相链接的内存区域块。
  •     删除添加到/proc 和/sys的所有文件
    net_device中三个函数指针比较有用:      
dev->stop       //用以关闭设备,通常包括关闭netif_stop_queue出口,释放硬件资源等
dev->uninit     //主要负责引用计数,少用到
dev->destructor //少数虚拟设备使用,通常初始化为: free_netdev 或其包裹函数

设备除名有int unregister_netdevice(struct net_device *dev)进行,其主要工作如下:
  •     如果设备没关闭,使用dev_close关闭
  •     从全局表dev_base和两张哈希表中删除设备
  •     所有与该设备关联的队列规则实例,由dev_shutdown销毁
  •     发送NETDEV_UNREGISTER消息到netdev_chain通知链。
  •     除名消息也必须通知用户空间。
  •     任何链接至net_device的数据块被释放
  •     register_netdevice中dev_init的所有操作都要有dev_uninit复原。
    最后调用net_set_todo,使得net_run_todo能完成除名。

引用计数

    只有当设备引用计数都被释放时,net_device结构才能被释放。
     引用计数保存在dev->refcnt中。当引用新增或删除时,使用dev_hold和dev_put更新引用计数。
    当设备以register_netdevice注册时,dev->refcnt初始化为1, 这第一个引用有负责网络设备数据库的内核代码所持有。因此,只有当设备除名时,该值才有可能降为0.
    

网络设备的启用和关闭

    设备一旦注册即可使用,但是如果没有明确的开启其功能,设备仍然无法接收和传输数据流。
    设备的开启请求由dev_open完成:
//net/core/dev.c
int dev_open(struct net_device *dev)
static int __dev_open(struct net_device *dev)
    启用设备包括下列工作:
  •     如果 dev->open初始化了,就调用dev->open。
  •     设置dev_state中的__LINK_STATE_START标识,以表明设备开启或在运行中
  •     设置dev_flags中的IFF_UP,标识设备为开启。
  •     调用dev_activate初始化流量控制所需使用到的出口队列规则,然后启用看门狗定时器。
  •     向netdev_chain发送NETDEV_UP通知
    设备的启用必须显示执行,但设备的关闭则可以通过用户命令显式执行或者通过其他程序隐式执行。
    设备关闭有以下任务:
  •     向netdev_chain发送 NETDEV_GOING_DOWN通知
  •     调用dev_deactivat关闭队列规则
  •     清除dev->state的_ _LINK_STATE_START标志,以表明设备禁用了
  •     如果正在执行读取入口队列数据包的轮询操作,则等待该操作完成。因为dev->state关系,入口队列不会再有入队操作,所以读取当前已经在队列中的即可
  •     如果dev->stop有定义,执行它。
  •     清除dev->flags的IFF_UP操作。
  •     向netdev_chain发送NEtdEV_DOWN通知。
    

更新队列规则状态:


    以后再补充




从用户空间配置设备相关信息

    许多工具可以用来配置设备相关参数:
  •     ipconfig和mii-tool 来自net-tool套件
  •     ethtool    来自ethtool套件
  •     ip link:来自IP ROUTER2 套件
 










文章评论

漫画:程序员的工作
漫画:程序员的工作
每天工作4小时的程序员
每天工作4小时的程序员
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
Java程序员必看电影
Java程序员必看电影
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
中美印日四国程序员比较
中美印日四国程序员比较
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
程序员都该阅读的书
程序员都该阅读的书
为什么程序员都是夜猫子
为什么程序员都是夜猫子
 程序员的样子
程序员的样子
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
如何成为一名黑客
如何成为一名黑客
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
编程语言是女人
编程语言是女人
老程序员的下场
老程序员的下场
鲜为人知的编程真相
鲜为人知的编程真相
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
10个调试和排错的小建议
10个调试和排错的小建议
我的丈夫是个程序员
我的丈夫是个程序员
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
我是如何打败拖延症的
我是如何打败拖延症的
旅行,写作,编程
旅行,写作,编程
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
程序员应该关注的一些事儿
程序员应该关注的一些事儿
总结2014中国互联网十大段子
总结2014中国互联网十大段子
程序员的鄙视链
程序员的鄙视链
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
程序员和编码员之间的区别
程序员和编码员之间的区别
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
程序员必看的十大电影
程序员必看的十大电影
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
一个程序员的时间管理
一个程序员的时间管理
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
2013年美国开发者薪资调查报告
2013年美国开发者薪资调查报告
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有