zoukankan      html  css  js  c++  java
  • 深入理解linux网络技术内幕读书笔记(五)--网络设备初始化


    简介

      如果要使一个网络设备可用,它就必须能被内核正确识别并且与正确的设备驱动关联起来。首先,设备驱动既可以做为内核模块动态加载,也可以是内核的一个静态组件。
    其次,设备可以在启动时识别,也可以在运行时加载识别(热插拔设备 USB PCI IEEE…)。


    系统初始化概论

    下图为系统初始化流程

    https://images0.cnblogs.com/blog/479389/201402/202309237122543.jpg

    图5-1:内核初始化


    引导期间选项

    调用两次parse_args(一次是直接调用, 而另外一次是通过parse_early_param间接调用)以处理引导加载程序(bootloader, 如LILO或GRUB)
    在引导期间传给内核的配置参数。


    中断和定时器

    硬中断和软中断分别由init_IRQ和softirq_init做初始化。

    初始化函数

    内核子系统及内建的设备驱动程序由do_initcall初始化。


    设备注册和初始化

    注册和初始化的任务的一部分的内核负责,而其他部分由设备驱动程序负责。

    硬件初始化

    由设备驱动在总线(pci,usb)的协调下完成,主要分配中断号和i/o地址。

    软件初始化

    在设备可用前需要配置一些参数,如ip地址

    功能初始化

    与设备相关,如流量控制


    NIC初始化的基本目标

    IRQ线

    NIC必须被分派一个IRQ。

    I/O端口和内存注册

    I/O端口和内存f分别使用request_region和release_region注册及释放。


    硬件中断

    注册中断


    1:  static inline int __must_check
    2:  request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
    3:           const char *name, void *dev)
    4:  {
    5:       return request_threaded_irq(irq, handler, NULL, flags, name, dev);
    6:  }
    

    解除中断


    1:  extern void free_irq(unsigned int, void *);
    

    模块选项

    每个模块都在/sys/modules中分派一个目录。子目录/sys/modules/module/parameters中的每个文件就是
    改模块所输出的每个参数。


    设备处理层初始化

    [注] net/core/dev.c

     1:  /*
     2:   *   Initialize the DEV module. At boot time this walks the device list and
     3:   *   unhooks any devices that fail to initialise (normally hardware not
     4:   *   present) and leaves us with a valid list of present and active devices.
     5:   *
     6:   */
     7:  
     8:  /*
     9:   *       This is called single threaded during boot, so no need
    10:   *       to take the rtnl semaphore.
    11:   */
    12:  static int __init net_dev_init(void)
    13:  {
    14:       int i, rc = -ENOMEM;
    15:  
    16:       BUG_ON(!dev_boot_phase);
    17:  
    18:       if (dev_proc_init())
    19:           goto out;
    20:  
    21:       if (netdev_kobject_init())
    22:           goto out;
    23:  
    24:       INIT_LIST_HEAD(&ptype_all);
    25:       for (i = 0; i < PTYPE_HASH_SIZE; i++)
    26:           INIT_LIST_HEAD(&ptype_base[i]);
    27:  
    28:       if (register_pernet_subsys(&netdev_net_ops))
    29:           goto out;
    30:  
    31:       /*
    32:        *  Initialise the packet receive queues.
    33:        */
    34:  
    35:       for_each_possible_cpu(i) {
    36:           struct softnet_data *sd = &per_cpu(softnet_data, i);
    37:  
    38:           memset(sd, 0, sizeof(*sd));
    39:           skb_queue_head_init(&sd->input_pkt_queue);
    40:           skb_queue_head_init(&sd->process_queue);
    41:           sd->completion_queue = NULL;
    42:           INIT_LIST_HEAD(&sd->poll_list);
    43:           sd->output_queue = NULL;
    44:           sd->output_queue_tailp = &sd->output_queue;
    45:  #ifdef CONFIG_RPS
    46:           sd->csd.func = rps_trigger_softirq;
    47:           sd->csd.info = sd;
    48:           sd->csd.flags = 0;
    49:           sd->cpu = i;
    50:  #endif
    51:  
    52:           sd->backlog.poll = process_backlog;
    53:           sd->backlog.weight = weight_p;
    54:           sd->backlog.gro_list = NULL;
    55:           sd->backlog.gro_count = 0;
    56:       }
    57:  
    58:       dev_boot_phase = 0;
    59:  
    60:       /* The loopback device is special if any other network devices
    61:        * is present in a network namespace the loopback device must
    62:        * be present. Since we now dynamically allocate and free the
    63:        * loopback device ensure this invariant is maintained by
    64:        * keeping the loopback device as the first device on the
    65:        * list of network devices.  Ensuring the loopback devices
    66:        * is the first device that appears and the last network device
    67:        * that disappears.
    68:        */
    69:       if (register_pernet_device(&loopback_net_ops))
    70:           goto out;
    71:  
    72:       if (register_pernet_device(&default_device_ops))
    73:           goto out;
    74:  
    75:       open_softirq(NET_TX_SOFTIRQ, net_tx_action);
    76:       open_softirq(NET_RX_SOFTIRQ, net_rx_action);
    77:  
    78:       hotcpu_notifier(dev_cpu_callback, 0);
    79:       dst_init();
    80:       dev_mcast_init();
    81:       rc = 0;
    82:  out:
    83:       return rc;
    84:  }
    85:  
    86:  subsys_initcall(net_dev_init);
    
    net_dev_init中包含如下功能的初始化

    • 初始化cpu相关数据结构,用于网络软中断
    • 调用dev_proc_init,dev_mcast_init在/proc下增加相应的文件
    • 调用netdev_sysfs在/sys下增加相应配置文件
    • 调用net_random_init初始化cpu种子数组,这些数组用于在net_random中生成随机数
    • 调用dst_init初始化dst
    • 初始化网络处理函数数组ptype_base,这些函数用来多路分解接收到的包
    • 在通知链表上注册回调函数用于接收cpu热插拔事件

    除了上述初始化,对于网络设备来说更重要的是 初始化它的net_device结构,这个会在第8章详细讲


    动态加载设备/设备驱动

    讲动态加载之前先介绍2个用户空间程序和1个内核函数

    • /sbin/modprobe 在内核需要加载某个模块时调用,判断内核传递的模块是不是/etc/modprobe.conf文件中定义的别名
    • /sbin/hotplug 在内核检测到一个新设备插入或拔出系统时调用,它的任务是根据设备标识加载正确的驱动

    内核函数call_usermodehelper 上面两个用户进程统一由这个函数调用,其中参数arg1指示call_usermodehelper调用哪个用户进程,arg2指示call..使用哪个配
    置脚本,流程详见下图;
    实际上看懂了上面所说的,动态加载的概念应该很清楚了,最后再说说使用场景

    1. 以模块方式加载
      kmod模块加载器允许内核组件通过调用request_module请求加载某个模块
      举个例子;如果系统管理员使用ifconfig配置某个网卡,但这个网卡驱动还没有加载,如eth0,内核就会给/sbin/modprobe发送一个请求,让它加载名称为
      eth0的模块。如果/etc/modprobe.conf中包含“alias eth0 xxx”的字符,/sbin/modprobe就会尝试加载xxx.ko模块。
      module_param 宏定义在引入sysfs后可以通过文件来访问得到模块参数
      模块选项有三项 , 第一项参数名称,第二项参数类型,第三项表示参数作为文件在sys文件系统中所有的权限。
      每个模块都会在sys/modules下生成对应的目录,通过目录下的文件可以获取模块参数。
    2. pnp热插拔
      hotplug允许内核检测热插拔设备的插入和拔出并通知用户进程(/sbin/hotplug),用户进程根据这些通知来加载相应的驱动
      在编译内核时,会在kernel目录下生成modules.pcimap和modules.usbmap两个文件,这两个文件分别包含了内核所支持设备的pci id和usb id,文件中还包
      含于每个设备的id相对应的内核模块名称,当用户进程收到内核关于pnp的通知后,会使用这个文件来查找正确的设备驱动


    Footnotes:

    1 DEFINITION NOT FOUND: 0


    2 DEFINITION NOT FOUND: 1

  • 相关阅读:
    NodeJS、NPM安装配置步骤(windows版本)
    23种设计模式全解析
    js阻止浏览器默认事件
    js获取不同浏览器盒子宽度高度
    H5之重力感应篇
    JS中的call()和apply()方法
    html学习笔记
    less(css)语言快速入门
    power designer简单教程
    Strom开发配置手册
  • 原文地址:https://www.cnblogs.com/mosp/p/3553398.html
Copyright © 2011-2022 走看看