linux内核网络设备初始化,深入理解Linux网络技术内幕——网络设备初始化

概述

内核的初始化过程过程中,与网络相关的工作如下所示:

8c075645e682363c108d5621caf07e22.png

内核引导时执行start_kernel,start_kernel结束之前会调用rest_init,rest_init初始化内核线程init(在Linux3-12中为kernel_init)。

asmlinkage void __init start_kernel(void)

{

...

parse_early_param();//间接调用parse_args

parse_args(...); //处理内核引导程序(boot loader)在引导期间传给内核的参数,

...

init_IRQ(); //初始化硬件中断

tick_init();

init_timers(); //定时器用于支持后续初始化工作的运行。

hrtimers_init();

softirq_init(); //初始化软件中断

...

rest_init(); //这里会通过kernel_thread函数调用内核线程init(kernel_init).

}

static init __ref kernel_init(void *unused)

{

kernel_init_freeable(); //Linux-3.12 在这里调用do_basic_setup

free_initmem(); //用于释放已经不再需要的内存。

.....

run_init_process(execute_command)

...

}

static void __init do_basic_setup(void)

{

cpuset_init_smp();

usermodehelper_init();

shmem_init();

driver_init();

init_irq_proc();

do_ctors();

usermodehelper_enable();

do_initcalls(); //初始化内核子系统和内建的设备驱动

random_int_secret_init();

}

设备的注册和初始化

一个设备要能够正常工作,他就必须被内核所识别,并且与正确的驱动关联起来。设备驱动程序以私有结构体的形式保存了驱动本设备所需要的所有信息,并且与其他和本设备有交互的组件相互影响。

设备的注册和初始化一部分由内核完成,一部分由设备驱动程序完成。

设备的初始化包括了硬件初始化、软件初始化、功能初始化三部分:硬件初始化:由设备驱动程序和通用总线层完成,有时也需要用户提供一些参数。主要任务是将硬件功能配置成IRQ和I/O地址,以便能够跟内核相互作用。软件初始化:设备使用之前必须关注当前配置或启用的网络协议,

一般需要用户提供诸如ip地址之类的参数。功能初始化: Linux内核提供了一系列的网络选项,有些网络选项对每一个设备都需要进行单独配置(如实现Qos的子系统),这些配置决定了数据包进入队列和离开设备的出口队列的方式 。

NIC初始化目标

网络设备在Linux中都是以net_device实例进行初始化的,本节先不讨论这个,本节主要介绍设备驱动程序如何分配/建立设备与内核通信所需要的资源。IRQ线:NIC必须分派一个IRQ,用于在必要时唤起内核的注意(虚拟设备不需要分配IRQ,因为它的工作都是在内部实现。)/proc/interrupts文件可用于观察当前中断线分派状态。I/O端口和内存注册: 驱动程序会将设备的一块内存映射到系统内存,使得驱动程序的读写操作能够通过系统内存直接进行。注册和释放操作分别由request_region和

release_region进行。

设备与内核之间的交互

几乎所有设备与内核的交互都是通过以下两种方式:

内核的轮询:

内核定时检查设备的状态,判断设备是否有什么请求。

设备驱动的中断请求:

设备驱动发送硬件信号引起内核注意

内核轮询在其他文章会介绍,本文主要介绍硬件中断中与网络有关的概念。

硬件中断

每一个中断都会运行一个中断处理程序,这些中断响应程序都是设备驱动为设备量身定做的。一般而言,当设备注册一个NIC时,它首先会请求并分配一个IRQ,然后要为IRQ注册(如果设备被卸载了,则需要注销)一个IRQ响应程序。相应的内核代码在kernel/irq/manage.c和arch/XXX/kernel/irq.c。(其中XXX为处理器架构)

int request_threaded_irq(unsigned int irq, irq_handler_t handler,

irq_handler_t thread_fn, unsigned long irqflags,

const char *devname, void *dev_id)

void free_irq(unsigned int irq, void *dev_id)

注意:irq的注册和释放函数都带有参数dev_id。因为IRQ是可以共享的,因此需要IRQ number和dev_id共同来唯一表示中断。

另,在注册IRQ时,必须保证IRQ还未有设备请求,除非所有设备都支持IRQ共享。

内核接收到一个中断信号时,会通过IRQ number调用关联的中断响应程序。IRQ number与中断响应程序以表的形式保存。由于多个设备可能共享IRQ的关系,IRQ number与中断响应程序的关系可能是一对多的。

中断类型:接收到数据帧、帧传输失败、DMA传输已成功完成、设备已经有足够内存来创建新的传输会话(可用NIC可用内存达到一定数值时产生一个中断)

为了防止内核在设备内存不足时多次提交传输请求,设备驱动可以关闭内核出口队列,待到资源足够是才重启。下面是一个范例:

static netdev_tx_t

el3_start_xmit(struct sk_buff *skb, struct net_device *dev)

{

……

netif_stop_queue (dev);

……

dev->trans_start = jiffies;

if (inw(ioaddr + TX_FREE) > 1536)

netif_start_queue(dev);

else

/* Interrupt us when the FIFO has room for max-sized packet. */

outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);

……

}

IRQ共享:IRQ线是很有限的资源,为了让一个系统能支持更多的设备,只能让多个设备共享IRQ线。IRQ共享的机制是这样的,内核收到中断请求,然后调用所有与该中断相关联的响应例程,然后有各个响应例程自行判断过滤是否对这个中断进行处理。(注意,IRQ与响应程序是一对多的,发生一个IRQ,哪些响应程序要处理,哪些不需要不是有内核去判断,而是各个中断响应程序自己判断,内核则是调用所有的响应程序。)

IRQ与IRQ响应程序的组织:用全局的vector:irq_desc来组织,irq_desc包含所有IRQ,每个IRQ对应自己的链表,链表中是该IRQ关联的所有响应程序。只有IRQ共享时,IRQ链表的节点才会超过一个。整个组织如下图:

ab9ca40dfa3cef5ca36e69097108449d.png

初始化选项

所有的系统内建组件以及作为模块加载的设备都能通过用户的输入参数调整所实现的功能、重写其默认值,或者在引导前后有不同的值。

模块选项:(module_param系列的宏)

模块加载时可以定义。如果是内建的组件,由于在引导期间无法配置,可以通过sys/进行运行时配置。

引导期间内核选项:(__setup系列宏)

引导期间提供。用于可以内建到内核的模块。

设备处理层的初始化

网络代码初始化有以下重要的部分:流量控制,每个CPU输入队列初始化。这些初始化工作在引导期间由net_dev_init完成:

static int __init net_dev_init(void)

subsys_initcall(net_dev_init);

用户空间辅助程序

/sbin/modprobe 在内核需要加载某个模块时调用,判断内核传递的模块是不是/etc/modprobe.conf文件中定义的别名

/sbin/hotplug 在内核检测到一个新设备插入或拔出系统时调用,它的任务是根据设备标识加载正确的驱动

32084430ed4121ce0861eccf95b84527.png

以模块方式加载

kmod模块加载器允许内核组件通过调用request_module请求加载某个模块

举个例子;如果系统管理员使用ifconfig配置某个网卡,但这个网卡驱动还没有加载,如eth0,内核就会给/sbin/modprobe发送一个请求,让它加载名称为

eth0的模块。如果/etc/modprobe.conf中包含“alias eth0 xxx”的字符,/sbin/modprobe就会尝试加载xxx.ko模块。

module_param 宏定义在引入sysfs后可以通过文件来访问得到模块参数

模块选项有三项 , 第一项参数名称,第二项参数类型,第三项表示参数作为文件在sys文件系统中所有的权限。

每个模块都会在sys/modules下生成对应的目录,通过目录下的文件可以获取模块参数。

pnp热插拔

hotplug允许内核检测热插拔设备的插入和拔出并通知用户进程(/sbin/hotplug),用户进程根据这些通知来加载相应的驱动

在编译内核时,会在kernel目录下生成modules.pcimap和modules.usbmap两个文件,这两个文件分别包含了内核所支持设备的pci id和usb id,文件中还包

含于每个设备的id相对应的内核模块名称,当用户进程收到内核关于pnp的通知后,会使用这个文件来查找正确的设备驱动

虚拟设备

虚拟设备一般也使用net_device结构体进行实例化(也有一些例外,如别名接口设备)。

虚拟设备一般会有用户空间配置工具来对其进行配置。尤其是无法使用ifconfig来进行配置的高级字段。

虚拟设备一般会有一个/proc接口目录,其内容详细程度取决于虚拟设备的设计。

虚拟设备与这是设备的对应关系不是一一对应的。这就导致了虚拟设备可能需要进行流量控制的配置。

虚拟设备的流量是简介从真实物理设备获得的,因而不需要分配IRQ、IO端口和IO内存。

虚拟设备与其他真实物理设备一样,能对特殊的事件通知做出相应的反应。

/proc调整

深入理解linux网络技术内幕读书笔记(三)--用户空间与内核的接口

Table of Contents 1 概论 1.1 procfs (/proc 文件系统) 1.1.1 编程接口 1.2 sysctl (/proc/sys目录) 1.2.1 编程接口 1.3 sy ...

深入理解linux网络技术内幕读书笔记(五)--网络设备初始化

Table of Contents 1 简介 2 系统初始化概论 2.1 引导期间选项 2.2 中断和定时器 2.3 初始化函数 3 设备注册和初始化 3.1 硬件初始化 3.2 软件初始化 3.3 ...

深入理解linux网络技术内幕读书笔记(八)--设备注册与初始化

Table of Contents 1 设备注册之时 2 设备除名之时 3 分配net_device结构 4 NIC注册和除名架构 4.1 注册 4.2 除名 5 设备初始化 6 设备类型初始化: x ...

深入理解linux网络技术内幕读书笔记(七)--组件初始化的内核基础架构

Table of Contents 1 引导期间的内核选项 2 注册关键字 3 模块初始化代码 引导期间的内核选项 linux运行用户把内核配置选项传给引导记录,然后引导记录再把选项传给内核. 在引导 ...

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

设备注册于设备除名     设备注册与设备除名一般有 register_netdev和unregister_netdev完成.这两个是包裹函数,负责上锁,真正起作用的是其调用的register_net ...

深入理解Linux网络技术内幕——内核基础架构和组件初始化

引导期间的内核选项     Linux允许用户把内核配置选项传给引导记录,再有引导记录传给内核,以便对内核进行调整.     start_kernel中调用两次parse_args,用于引导期间配置用 ...

深入理解linux网络技术内幕读书笔记(四)--通知链

Table of Contents 1 概述 2 定义链 3 链注册 4 链上的通知事件 5 网络子系统的通知链 5.1 包裹函数 5.2 范例 6 测试实例 概述 [注意] 通知链只在内核子系统之间 ...

深入理解Linux网络技术内幕——中断与网络驱动程序

接收到帧时通知驱动程序     在网络环境中.设备(网卡)接收到一个数据帧时,须要通知驱动程序进行处理. 有一下几种通知机制: 轮询:     内核不断检查设备是否有话要说.(比較耗资源,但在一些情况 ...

深入理解linux网络技术内幕读书笔记(十)--帧的接收

Table of Contents 1 概述 1.1 帧接收的中断处理 2 设备的开启与关闭 3 队列 4 通知内核帧已接收:NAPI和netif_rx 4.1 NAPI简介 4.1.1 NAPI优点 ...

随机推荐

Android4.4 往短信收件箱中插入自定义短信(伪造短信)

这段时间稍微有点空闲,把前一段学习Android做过的一些小项目整理整理.虽然没有什么工程量很大的项目,但是对于一个新手,解决这些问题还是花了一段时间.感觉还是非常有记录的意义呢~~~么么哒*—* 今 ...

BZOJ4386 : [POI2015]Wycieczki

将每个点拆成三个点,并将转移转化为矩阵乘法,然后倍增即可求出第$k$短路的长度,注意对爆long long情况的处理. 时间复杂度$O(n^3\log k)$. #include

一步一步来做WebQQ机器人-(二)(第一次登陆)

// 预计会有这些步骤,当然某些步骤可能会合并: 验证码 第一次登陆 第二次登陆 保持在线和接收消息 获取好友和群列表 发送消息 变成智能的(*゚∀゚*) webqq的登陆,分为2步,本文主要讲第一次 ...

vs2012用wpf制作透明窗口中报错的解决方案

在开发wpf项目时,需要调用外部com组件,同时需要制作透明窗口,于是问题出现了,当我们在设置 AllowsTransparency="True"后,com组件显示不出来了,只有透 ...

C# 常用控件及单击事件

1.窗体 1.常用属性 (1)Name属性:用来获取或设置窗体的名称,在应用程序中可通过Name属性来引用窗体. (2)WindowState属性: 用来获取或设置窗体的窗口状态. 取值有三种: No ...

51nod 1423 最大二“货” 单调栈

利用单调栈,高效求出每个区间内的最大值和次大值的亦或值. 先正向扫描,利用单调递减栈,若当前栈为空栈,则直接压入栈中,若为非空栈,弹出栈顶元素,每弹出一个元素,则求一次亦或值,保留最大值 接着进行反向 ...

[C]控制外部变量访问权限的extern和static关键字

一.extern 概述 编译器是由上至下编译源文件的,当遇到一些函数引用外部全局变量,而这个变量被定义在该函数声明主体的下方,又或者引用自其它的编译单元,这个情况就需要extern来向编译器表明此变量 ...

CSS实现垂直居中的5种思路

前面的话 相对于水平居中,人们对于垂直居中略显为难,大部分原因是vertical-align不能正确使用.实际上,实现垂直居中也是围绕几个思路展开的.本文将介绍关于垂直居中的5种思路 line-hei ...

【SVD、特征值分解、PCA关系】

一.SVD    1.含义: 把矩阵分解为缩放矩阵+旋转矩阵+特征向量矩阵. A矩阵的作用是将一个向量从V这组正交基向量的空间旋转到U这组正交基向量的空间,并对每个方向进行了一定的缩放,缩放因子就是各 ...

docker 安装nginx、php-fpm

运行环境: 创建目录: mkdir -p /Users/sui/docker/nginx/conf.d && mkdir /Users/sui/www && cd /U ...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值