<返回更多

Linux网络包从中断到接收的一生

2020-07-09    
加入收藏

内容来自SJTU,IPADS OS-16-Network

Linux网络包从中断到接收的一生

linux

既然要讲,那就把一个包的整个包生都说了算了

触发中断

Top Half

Bottom Half

Linux网络包从中断到接收的一生

kqueue

因为epoll没有论文,就说说kqueue是怎么做的吧,kqueue会根据socket绑定的knote链表(每个监听的kqueue都可能创建一个knote),将knote通过反向指针获得kqueue,将knote加入kqueue的就绪队列末尾。如果此时恰好有进程正在监听的话,将会唤醒进程,kqueue会被扫描,并从就绪队列处获得所有的event,从而了解已经就绪的所有socket。

Batch

netif_receive_skb_list()

Linux的NAPI还会继续延迟软中断的处理,等待其积累足够的skb后进行轮询,一次性处理所有的skb。

SKB

skb并不是直接存储报文,而是存储指针,指针只需要移动,就能完成解包,而本身的报文并不需要修改。上一层的协议栈会在处理当前层的同时设置好下一层的头指针,并且移动data指针。与此同时,skb本身是双向链表实现的队列。qlen为链表元素长度,lock为添加元素时的锁。

Linux网络包从中断到接收的一生

skb结构


谈到指针的用法,这里举个做OS lab时印象深刻的奇淫巧技,也是C的指针变态的地方

#define list_entry(ptr, type, field) 
	container_of(ptr, type, field)
#define container_of(ptr, type, field) 
	((type *)((void *)(ptr) - (u64)(&(((type *)(0))->field))))

(u64)(&(((type *)(0))->field))))指的是field在结构体type中的偏移量,通过减去这个偏移量我们就能找出某个对象所在上级type对象的地址,也就是container。

一般来说,我们都会使用下面这样的方式,让链表节点去包裹数据。

struct page_list_node {
        struct page p;
	struct list_node *prev;
	struct list_node *next;
};

但是,通过指针操作,却可以让数据去包裹链表节点

struct list_head {
	struct list_head *prev;
	struct list_head *next;
};

struct page{
	struct list_head      list_node;
}

在仅仅知道链表节点的情况下,借助成员偏移量即可知道容器对象的位置并取出

list_entry(somenode,struct page,list_node);

list_head本身可以存在于任何对象上,而他们的entry却能根据参数而指向不同的类型,感觉有点泛型的味道了。

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>