深入理解Linux网络技术内幕——Notification内核通知表链
为什么要有内核通知表链:
If (subsystem_X_enabled) {
do_something_1
}
if (subsystem_Y_enabled) {
do_something_2
}
If (subsystem_Z_enabled) {
do_something_3
}
... ... ...
Chain则大大的改善了这些不足。

//通知块
struct notifier_block
{
int (*notifier_call)(struct notifier_block *self, unsigned long, void *);//回调函数
struct notifier_block *next; //
int priority; //注册的优先级,用户自行指定,优先级越高回调函数就越早执行
};
//原子通知表链
struct atomic_notifier_head {
spinlock_t lock;
struct notifier_block __rcu *head;
}; //可阻塞通知表链
struct blocking_notifier_head {
struct rw_semaphore rwsem;
struct notifier_block __rcu *head;
}; //原始通知表链
struct raw_notifier_head {
struct notifier_block __rcu *head;
}; //可阻塞通知表链的变体
struct srcu_notifier_head {
struct mutex mutex;
struct srcu_struct srcu;
struct notifier_block __rcu *head;
};
static RAW_NOTIFIER_HEAD(netdev_chain);
#define ATOMIC_NOTIFIER_HEAD(name) \
struct atomic_notifier_head name = \
ATOMIC_NOTIFIER_INIT(name)
#define BLOCKING_NOTIFIER_HEAD(name) \
struct blocking_notifier_head name = \
BLOCKING_NOTIFIER_INIT(name)
#define RAW_NOTIFIER_HEAD(name) \
struct raw_notifier_head name = \
RAW_NOTIFIER_INIT(name)
#define ATOMIC_NOTIFIER_INIT(name) {                \
        .lock = __SPIN_LOCK_UNLOCKED(name.lock),    \
        .head = NULL }
#define BLOCKING_NOTIFIER_INIT(name) {              \
        .rwsem = __RWSEM_INITIALIZER((name).rwsem), \
        .head = NULL }
#define RAW_NOTIFIER_INIT(name) {               \
        .head = NULL }
/* srcu_notifier_heads cannot be initialized statically */
int notifier_chain_register(struct notifier_block **list, struct notifier_block *n)
int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n)
int register_netdevice_notifier(struct notifier_block *nb)
{
raw_notifier_chain_register(&netdev_chain, nb);
}
int raw_notifier_chain_register(struct raw_notifier_head *nh,
struct notifier_block *n)
{
return notifier_chain_register(&nh->head, n);
}
static int __kprobes notifier_call_chain(struct notifier_block **nl,
unsigned long val, void *v,
int nr_to_call, int *nr_calls)
{
int ret = NOTIFY_DONE;
struct notifier_block *nb, *next_nb; nb = rcu_dereference_raw(*nl); while (nb && nr_to_call) {
next_nb = rcu_dereference_raw(nb->next); #ifdef CONFIG_DEBUG_NOTIFIERS
if (unlikely(!func_ptr_is_kernel_text(nb->notifier_call))) {
WARN(1, "Invalid notifier called!");
nb = next_nb;
continue;
}
#endif
ret = nb->notifier_call(nb, val, v); if (nr_calls)
(*nr_calls)++; if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
break;
nb = next_nb;
nr_to_call--;
}
return ret;
}
深入理解Linux网络技术内幕——Notification内核通知表链的更多相关文章
- 深入理解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 定义链 3 链注册 4 链上的通知事件 5 网络子系统的通知链 5.1 包裹函数 5.2 范例 6 测试实例 概述 [注意] 通知链只在内核子系统之间 ...
 - 深入理解Linux网络技术内幕——设备的注册与初始化(二)
		
设备注册于设备除名 设备注册与设备除名一般有 register_netdev和unregister_netdev完成.这两个是包裹函数,负责上锁,真正起作用的是其调用的register_net ...
 - 深入理解Linux网络技术内幕——用户空间与内核空间交互
		
概述: 内核空间与用户空间经常需要进行交互.举个例子:当用户空间使用一些配置命令如ifconfig或route时,内核处理程序就要响应这些处理请求. 用户空间与内核有多种交互方式,最常 ...
 - 深入理解linux网络技术内幕读书笔记(七)--组件初始化的内核基础架构
		
Table of Contents 1 引导期间的内核选项 2 注册关键字 3 模块初始化代码 引导期间的内核选项 linux运行用户把内核配置选项传给引导记录,然后引导记录再把选项传给内核. 在引导 ...
 - 深入理解Linux网络技术内幕——内核基础架构和组件初始化
		
引导期间的内核选项 Linux允许用户把内核配置选项传给引导记录,再有引导记录传给内核,以便对内核进行调整. start_kernel中调用两次parse_args,用于引导期间配置用 ...
 - 《深入理解Linux网络技术内幕》阅读笔记 --- 路由基本概念
		
一.路由的基本概念 1.一条路由就是一组参数,这些参数存储了往一个给定目的地转发流量所需的信息,而一条路由所需的最少的参数集合为:(1)目的网络,(2)出口设备,(3)下一跳网关 2.路由中的相关术语 ...
 - 深入理解linux网络技术内幕读书笔记(十)--帧的接收
		
Table of Contents 1 概述 1.1 帧接收的中断处理 2 设备的开启与关闭 3 队列 4 通知内核帧已接收:NAPI和netif_rx 4.1 NAPI简介 4.1.1 NAPI优点 ...
 - 深入理解linux网络技术内幕读书笔记(九)--中断与网络驱动程序
		
Table of Contents 1 接收到帧时通知驱动程序 1.1 轮询 1.2 中断 2 中断处理程序 3 抢占功能 4 下半部函数 4.1 内核2.4版本以后的下半部函数: 引入软IRQ 5 ...
 
随机推荐
- [Java中实现国际化] - 配合thymeleaf实现中英文自动切换(多语言)
			
MOOC该链接第三章第二节 尚硅谷SpringBoot全集 web开发国际化 xjbo (7天,过期可以留言索取) resources下建立文件 上到下为: 默认的,英语(美国),中文(中国) en ...
 - Window下Latex加速编译方法以及西农毕设论文模板推荐
			
近些日子用Latex写了一遍文章,一共有11页,但是在window下编译需要2分多的时间,使用的是xeletex编译器. 经过查找,得到了以下方法: 如果坚持使用windows下的latex,使用以下 ...
 - Lua面向对象 --- 单例
			
GameManager.lua: --单例模式是利用一个全局表来实现的 GameManager = {} Manager = {__index = GameManager} function Game ...
 - Python 爬虫-Robots协议
			
2017-07-25 21:08:16 一.网络爬虫的规模 二.网络爬虫的限制 • 来源审查:判断User‐Agent进行限制 检查来访HTTP协议头的User‐Agent域,只响应浏览器或友好爬虫的 ...
 - Linux 虚拟内存和物理内存的理解
			
关于Linux 虚拟内存和物理内存的理解. 首先,让我们看下虚拟内存: 第一层理解 1. 每个进程都有自己独立的4G内存空间,各个进程的内存空间具有类似的结构 2. 一个新进程建立的时候,将会建立起自 ...
 - 雷林鹏分享:C# 索引器(Indexer)
			
C# 索引器(Indexer) 索引器(Indexer) 允许一个对象可以像数组一样被索引.当您为类定义一个索引器时,该类的行为就会像一个 虚拟数组(virtual array) 一样.您可以使用数组 ...
 - 12月10日 render( locals:{...}) 传入本地变量。
			
Jdstor第一部分后台设计,4-4上传图片. 3.4 Using Partials--3.4.4 Passing Local Variables You can also pass local va ...
 - golang martini 源码阅读笔记之inject
			
martini是go语言写的一个超级轻量的web开源框架,具体源码可在github搜索找到.13年那会开始接触go语言时有稍微看过这个框架,由于之后没有继续使用go就慢慢忽略了,最近由于手头项目可能会 ...
 - AndroidStudio使用偷懒插件Butterknife和GsonFormat
			
1.Android ButterKnife Zelezny Android Studio上安装插件,如图: 配合ButterKnife实现注解,从此不用写findViewById,想着就爽啊.在Act ...
 - Confluence 6 安装 Active Directory 证书服务器
			
如果证书服务器已经安装了的话,跳过这一步骤,直接进入下一步.下面步骤中的屏幕截图是从 Windows 2008 服务器版上安装的截图,针对 2000 和 2003 安装过程是一样的. 作为系统管理员登 ...