深入理解Linux网络技术内幕——中断与网络驱动程序
接收到帧时通知驱动程序
有一下几种通知机制:
多数网络驱动程序使用中断。
然后保持帧的接收(加载),直到输入队列达到指定的数目、或者一直做下去知道队列清空、或者经过指定时间。
这样的机制会导致帧处理的延时。比方指定时间为100ms。而帧可能在第0ms、第50ms、也可能在第100ms刚好到达,平均延时为50ms。
中断处理函数
为什么有下半部函数
下半部函数解决方式
不同的解决方式的区别主要在于执行环境及并发与上锁。
/***********************Linux-2.6.32************************************/
//include/linux/hardirq.h
in_irq() //CPU正服务于硬件中断时,返回True
in_softirq() //CPU正服务于软件中断时,返回True
in_interrupt() //CPU正在服务于一个硬件中断或软件中断。或抢占功能关闭时,返回True //arch/x86/include/asm/hardirq.h
local_softirq_pending() //本地CPU至少有一个IRQ出于未决状态时,返回True //include/linux/interrupt.h
__raise_softirq_irqoff() //设置与软IRQ相关联的标识,将IRQ标记为未决
raise_softirq_irqoff() //__raise_softirq_irqoff包裹函数,当in_interrupt为False时,唤醒ksoftirqd
raise_softirq() //包裹raise_softirq_irqoff,调用raise_softirq_irqoff前先关中断 //kernel/softirq.c
__local_bh_enable() //开启本地CPU的下半部
local_bh_enable() //假设有不论什么软IRQ未决,且in_interrupt返回False,则invoke_softirq
local_bh_disable() //关闭CPU下半部 //include/linux/irqflags.h
local_irq_enable() //开启本地CPU中断功能
local_irq_disable() //关闭本地CPU中断功能
local_irq_save() //先把本地CPU中断状态保存,再予以关闭
local_irq_restore() //恢复本地CPU之前的中断状态,恢复local_irq_save保存的中断信息 //include/linux/spinlock.h
spin_lock_bh() //取得回旋锁。关闭下半部及抢占功能
spin_unlock_bh() //释放回旋锁,重新启动下半部抢占功能
抢占功能
//inculde/linux/preempt.h
preempt_disable() //为当前任务关闭抢占功能。可反复调用,递增引用计数器
preempt_enable() //抢占功能再度开启,(须要先检查引用计数器是否为0)
preempt_enable_no_resch() //递减引用计数器,仅仅有引用计数器为0时,抢占功能才干再度开启
preempt_check_resched() //由preempt_enable调用,检查引用计数器是否为0. // arch/x86/include/asm/thread_info.h
struct thread_info {
……
int preempt_count; /* 0 => preemptable,
<0 => BUG */ //抢占计数器,指定进程能否被抢占
……
};
下半部函数
旧式下半部函数(linux-2.2曾经)
enum {
TIMER_BH = 0,
CONSOLE_BH,
TQUEUE_BH,
DIGI_BH,
SERIAL_BH,
RISCOM8_BH,
SPECIALIX_BH,
AURORA_BH,
ESP_BH,
NET_BH, //网络下半部
SCSI_BH,
IMMEDIATE_BH,
KEYBOARD_BH,
CYCLADES_BH,
CM206_BH,
JS_BH,
MACSERIAL_BH,
ISICOM_BH
};
_ _initfunc(int net_dev_init(void))
{
... ... ...
init_bh(NET_BH, net_bh);
... ... ...
}
extern inline void mark_bh(int nr)
{
set_bit(nr, &bh_active);
};
skb_queue_tail(&backlog, skb);
mark_bh(NET_BH);
return
引入软IRQ
(软IRQ能够视为IRQ的多线程版本号)
//include/linux/interrupt.h
enum
{
HI_SOFTIRQ=0, //高优先级微任务
TIMER_SOFTIRQ,
NET_TX_SOFTIRQ, //网络软IRQ
NET_RX_SOFTIRQ, //网络软IRQ
BLOCK_SOFTIRQ,
BLOCK_IOPOLL_SOFTIRQ,
TASKLET_SOFTIRQ, //低优先级微任务软IRQ
SCHED_SOFTIRQ,
HRTIMER_SOFTIRQ,
RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */ NR_SOFTIRQS
};
/*
* Incoming packets are placed on per-cpu queues so that
* no locking is needed.
*/
struct softnet_data
{
struct Qdisc *output_queue; //qdisc是queueing discipline的简写。也就是排队规则,即qos.这里也就是输出帧的控制。
struct sk_buff_head input_pkt_queue; //当输入帧被驱动取得之前,就保存在这个队列里,(不适用与napi驱动,napi有自己的私有队列)
struct list_head poll_list; //表示有输入帧待处理的设备链表。
struct sk_buff *completion_queue; //表示已经成功被传递出的帧的链表。 struct napi_struct backlog; //用来兼容非napi的驱动。
};
static int __init net_dev_init(void)
{
......
for_each_possible_cpu(i) {
struct softnet_data *queue; queue = &per_cpu(softnet_data, i);
skb_queue_head_init(&queue->input_pkt_queue);
queue->completion_queue = NULL;
INIT_LIST_HEAD(&queue->poll_list); queue->backlog.poll = process_backlog;
queue->backlog.weight = weight_p;
queue->backlog.gro_list = NULL;
queue->backlog.gro_count = 0;
}
......
}
软IRQ的注冊于调度机制
// kernel/softirq.c
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
softirq_vec[nr].action = action;
}
__raise_softirq_irqoff() //设置与软IRQ相关联的标识,将IRQ标记为未决
raise_softirq_irqoff() //__raise_softirq_irqoff包裹函数,当in_interrupt为False时,唤醒ksoftirqd
raise_softirq() //包裹raise_softirq_irqoff,调用raise_softirq_irqoff前先关中断
微任务
/*
* Tasklets
*/
struct tasklet_head
{
struct tasklet_struct *head;
struct tasklet_struct **tail;
}; static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);
static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);
struct tasklet_struct
{
struct tasklet_struct *next; //把关联到同一个CPU的结构链接起来
unsigned long state; //位图标识,其可能的取值由TASKLET_STATE_XXX枚举
atomic_t count; //计数器,0表示微任务被关闭,不可运行。非0表示微任务已经开启
void (*func)(unsigned long); //要运行的函数
unsigned long data; //上面函数的參数
}; enum
{
TASKLET_STATE_SCHED, /* Tasklet is scheduled for execution */
TASKLET_STATE_RUN /* Tasklet is running (SMP only) */
};
深入理解Linux网络技术内幕——中断与网络驱动程序的更多相关文章
- 深入理解linux网络技术内幕读书笔记(三)--用户空间与内核的接口
Table of Contents 1 概论 1.1 procfs (/proc 文件系统) 1.1.1 编程接口 1.2 sysctl (/proc/sys目录) 1.2.1 编程接口 1.3 sy ...
- 深入理解Linux网络技术内幕——网络设备初始化
概述 内核的初始化过程过程中,与网络相关的工作如下所示: 内核引导时执行start_kernel,start_kernel结束之前会调用rest_init,rest_init初始化内核线 ...
- 深入理解linux网络技术内幕读书笔记(九)--中断与网络驱动程序
Table of Contents 1 接收到帧时通知驱动程序 1.1 轮询 1.2 中断 2 中断处理程序 3 抢占功能 4 下半部函数 4.1 内核2.4版本以后的下半部函数: 引入软IRQ 5 ...
- 深入理解linux网络技术内幕读书笔记(十)--帧的接收
Table of Contents 1 概述 1.1 帧接收的中断处理 2 设备的开启与关闭 3 队列 4 通知内核帧已接收:NAPI和netif_rx 4.1 NAPI简介 4.1.1 NAPI优点 ...
- 《深入理解Linux网络技术内幕》阅读笔记 --- 路由基本概念
一.路由的基本概念 1.一条路由就是一组参数,这些参数存储了往一个给定目的地转发流量所需的信息,而一条路由所需的最少的参数集合为:(1)目的网络,(2)出口设备,(3)下一跳网关 2.路由中的相关术语 ...
- 深入理解linux网络技术内幕读书笔记(五)--网络设备初始化
Table of Contents 1 简介 2 系统初始化概论 2.1 引导期间选项 2.2 中断和定时器 2.3 初始化函数 3 设备注册和初始化 3.1 硬件初始化 3.2 软件初始化 3.3 ...
- 深入理解linux网络技术内幕读书笔记(六)--PCI层与网络接口卡
Table of Contents 1 本章涉及的数据结构 1.1 pci_device_id结构 1.2 pci_dev结构 1.3 pci_driver结构 2 PCI NIC设备驱动程序的注册 ...
- 深入理解linux网络技术内幕读书笔记(四)--通知链
Table of Contents 1 概述 2 定义链 3 链注册 4 链上的通知事件 5 网络子系统的通知链 5.1 包裹函数 5.2 范例 6 测试实例 概述 [注意] 通知链只在内核子系统之间 ...
- 深入理解linux网络技术内幕读书笔记(二)--关键数据结构
Table of Contents 1 套接字缓冲区: sk_buff结构 1.1 网络选项及内核结构 1.2 结构说明及操作函数 2 net_device结构 2.1 MTU 2.2 结构说明及操作 ...
随机推荐
- 限制TextBox输入,只能输入整数
public class TextBoxInt : TextBox { public TextBoxInt() { KeyDown += TextBoxInt_KeyDown; TextChanged ...
- poj--1517
n从0取到9,一个for循环,n++,n=0,n<=9 n=4,求1/4!+1/3!+1/2!+1/1!+1/0! 需要一个for循环,i=n,i>=0,i-- sum+=factoria ...
- [Regionals 2012 :: Asia - Tokyo ]
链接: https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=56 ...
- Service的基本组成
Service与Activity的最大区别就是一有界面,一个没有界面. 如果某些程序操作很消耗时间,那么可以将这些程序定义在Service之中,这样就可以完成程序的后台运行, 其实Service就是一 ...
- 微软将Bing变开放平台 同谷歌争夺开发者
微软在编译者大会上宣布将Bing作为平台开放,此举显然旨在改变谷歌(微博)一家独大的局面. 报道称,微软知道如何创建平台.因此当它发布新平台时,都值得业界仔细关注.就在上周之前,微软Bing给大家的印 ...
- pagination分页插件
最近做了个项目,有用到分页, 这类插件应该是很常用的, 虽然网上很多现成的分页插件, 但是还是想着自己写一个, 给自己积累点东西, 顺便练练手, 写了差不多3个小时左右, 代码如下: 代码: < ...
- Linux学习之tail命令
tail 命令从指定点开始将文件写到标准输出.使用tail命令的-f选项可以方便的查阅正在改变的日志文件,tail -f filename会把filename里最尾部的内容显示在屏幕上,并且不但刷新, ...
- Zend Studio 12 大集合
前言 本文记录了我个人使用Zend Studio 12的点点滴滴,不定时更新. 内容来源于网络,如有侵权,告知后可删除. 下载 官方链接点击链接,填入相关信息即可下载. 破解 声明:请购买正版,非万不 ...
- OSG中的几何体
osg::Shape类 继承自osg::Object类: osg::Shape类是各种内嵌几何体的基类,不但可以用于剔除和碰撞检测,还可用于生成预定义的几何体对象: 常见的内嵌几何体包括: osg:: ...
- Android 学习之 开源项目PullToRefresh的使用
首先 下载 Android-PullToRefresh-master 下载地址 https://github.com/chrisbanes/Android-PullToRefresh 下载之后将其解 ...