网络设备初始化

QQ截图20120514081656

在内核引导时,会执行start_kernel对一些子系统做初始化,部分显示于上图。start_kernel终止前会调用kernel_init内核线程,由其负责初始化的后续工作。

init进程的运行

kernel_init内核线程最终会调用init_post()函数,该函数负责确定运行在系统上的第一个进程,也就是其他进程的父进程

   1:  /* This is a non __init function. Force it to be noinline otherwise gcc
   2:   * makes it inline to init() and it becomes part of init.text section
   3:   */
   4:  static noinline int init_post(void)
   5:  {
   6:      /* need to finish all async __init code before freeing the memory */
   7:      async_synchronize_full();
   8:      free_initmem();
   9:      mark_rodata_ro();
  10:      system_state = SYSTEM_RUNNING;
  11:      numa_default_policy();
  12:   
  13:   
  14:      current->signal->flags |= SIGNAL_UNKILLABLE;
  15:   
  16:      if (ramdisk_execute_command) {
  17:          run_init_process(ramdisk_execute_command);
  18:          printk(KERN_WARNING "Failed to execute %s\n",
  19:                  ramdisk_execute_command);
  20:      }
  21:   
  22:      /*
  23:       * We try each of these until one succeeds.
  24:       *
  25:       * The Bourne shell can be used instead of init if we are
  26:       * trying to recover a really broken machine.
  27:       */
  28:      if (execute_command) {
  29:          run_init_process(execute_command);
  30:          printk(KERN_WARNING "Failed to execute %s.  Attempting "
  31:                      "defaults...\n", execute_command);
  32:      }
  33:      run_init_process("/sbin/init");
  34:      run_init_process("/etc/init");
 35:     run_init_process("/bin/init");
 36:     run_init_process("/bin/sh");
  37:   
  38:      panic("No init found.  Try passing init= option to kernel. "
  39:            "See Linux Documentation/init.txt for guidance.");
  40:  }

该进程的PID为1,一致运行到系统做完工作。正常情况下,运行的程序是init。然而,管理员可以通过init=引导期间选项指定另外一个不同程序。不提供这个选项时,内核就会尝试从一组众所周知的位置去执行init命令,如果都找不到init,就会发生内核panic。

设备注册和初始化

一个网络设备可用,就必须被内核认可,并且关联正确的驱动程序。驱动程序把驱动设备所需的所有信息存储在私用数据结构中,然后与其他需要此设备的内核组件交互。注册和初始化任务的一部分由内核负责,而其他部分由设备驱动程序负责。

硬件初始化

由设备驱动程序和通用总线层合作完成。驱动程序有时独自而有时通过用户提供的参数的协助,把每个设备的这类功能配置成IRQ和I/O地址,使其能与内核交互。与较高层的协议和功能相比,这项活动更接近设备驱动程序。

软件初始化

在设备能够被使用之前,依赖于所开启和配置的网络协议为何而定,用户需要提供其他一些配置参数,如IP地址等。

功能初始化

Linux内核有很多网络选项。因为有些选项需要针对每个设备进行配置,因此,设备初始化引导程序必须负责这些选项。

中断类型

通过中断,NIC能够告知其驱动程序几种不同的事情,包括:

接收一帧,最常见的、标准的情况。

传输失败,这种通知消息只有当被称为二进制指数后退功能失败时,才由ethernet设备产生。注意,驱动程序不会把这种通知信息转送到哪些较高层的网络层,这些网络层会通过其他方式得知这种失败。

DMA传输已成功完成,给定一个帧传输,当帧上载至NIC的内存准备在此媒介上传输时,驱动程序就会将持有该帧的缓冲区释放掉。使用同步传输时,该帧已上传至NIC,驱动程序就会立刻知道。但使用DMA时,也就是使用异步传输,设备驱动程序必须等待NIC发出明确的中断事件。

设备有足够的内存处理新传输,当出口队列没有足够空间保存一个最大尺寸的帧时,NIC设备驱动程序会停止出口队列而关闭传输。当内存可用时,该队列又会再次开启。设备驱动程序可以再传输前关闭出口队列(以防止内核对该设备产生另一次传输请求),然后只有当NIC有足够可用内存时才予以重启。如果没有,该设备会要求一个中断,允许其稍后重新传输。

自动化与热插拔

模块不仅可以根据用户指令或自动化脚本装载,还可以由内核自身请求装载。这种装载机制,在下面两种情况下很有用处:

1,内核确认一个需要的功能当前不可用。例如,需要装载一个文件系统,但内核不支持。内核可以尝试加载所需的模块,然后重试装载文件系统。

2,一个新设备连接到可热插拔的总线。内核检测到新设备并自动装载包含适合当驱动程序的模块。

usb热插拔实例

  • usb宿主机控制器在总线上检测到一个新设备并报告给其设备驱动程序。宿主机控制器分配一个新的device实例并调用usb_new_device注册它。
  • usb_new_device触发对kobject_uevent的调用。该函数对所述对象kobject实例,调用其中注册的特定于子系统的事件通知程序。
  • 对usb设备对象,usb_event用作通知函数。该函数准备一个消息,其中包含了所有必要的信息,使得udevd能够对新的usb海量存储设备的插入,做出适当的反应。

IB0}1HLTOQLEF_253~Q}E5Cudevd守护进程可以检查来源于内核的所有消息。产生的消息如上图所示。由于一个新的设备加入,ACTION的值为add,DEVICE表示该设备在USB文件系统中的位置,可以据此查找该设备的有关信息,INTERFACE,确定了新设备所属接口的类别。通过比较MODALIAS和各个模块提供的别名,udevd可以找到需要插入的模块。模块的别名提取依赖于depmod程序,该程序扫描所有可用的模块,提取别名信息,并存储到文本文件/lib/modules/2.6.x/modules.alias中。但事情还没有结束,在usb存储模块加载到内核之后,块设备层识别出该设备和其中包含的分区。有产生新的通知:

image该信息提供了新检测到的分区名称和分区上找到的文件系统的有关信息 ,对udevd来说,该信息已经足够用于自动挂载文件系统,这样u盘就可以使用。

虚拟设备

虚拟设备是建立在一个或多个真实设备之上的抽象,其与真实设备的对应:

 

image 虚拟设备和真实设备的交互方式略有不同,

初始化,大多数虚拟设备如同真实设备一样,都会分派一个net_device数据结构。通常,大多数虚拟设备的net_device函数指针所初始化的函数都是所谓的包裹函数,其中包含的函数指针都是相关的真实设备所用的函数指针。然而,并非所有的虚拟设备都会被分派一个net_device实例。别名设备就是一例,别名设备作为相关联的真实设备上的简单标签来实现。

配置,提供特殊用户空间工具来配置虚拟设备是很常见的事,尤其是哪些只应用于这些虚拟设备的高层字段,无法使用如ifconfig标准工具予以配置。

外部接口,每个虚拟设备通常都会输出一个文件或一个内含一些文件的目录到/proc文件系统内。这些文件所输出的信息详略则取决于虚拟设备的种类及其设计。

传输,当虚拟设备与真实设备之间的关系不是一对一时,用于传输的函数可能需要选择所用的真实设备及其其他任务。

接收,因为虚拟设备都是软件对象,不需要参与系统上真实资源的交互,如IRQ和内存的分配。其流量是间接获得的,来自于执行这些任务的物理设备。

外部通知信息,内核中其他内核组件对特定事件发出通知信息,对虚拟设备而言,就如同真实设备一样,依然有其利益所在。因为虚拟设备的逻辑是实现在真实设备之上的,真实设备对此逻辑毫无所知,因此无法把这些通知信息传过去,因此,通知信息必须直接面向虚拟设备。

你可能感兴趣的:(网络设备初始化)