Linux协议栈代码阅读笔记(三)报文接收

原创 2013年12月02日 13:58:23
(基于linux-2.6.21.7)


(一)网卡接收报文


以Intel PRO/1000网卡为例。

网卡收到报文后,产生中断。
驱动程序的中断处理函数e1000_intr(源码文件:\drivers\net\e1000\e1000_main.c)对报文进行接收。
中断处理程序先做一些基本的接收工作,然后开始如下的执行路径(从e1000_intr内部开始):

(注意,内核与网卡驱动之间,有两套数据交互接口:一套老的,一套新的。新的接口(称为NAPI)有更好的效率。
因此,我们这里只看基于NAPI接口的执行路径。)


__netif_rx_schedule (源码文件:net\core\dev.c)
    __raise_softirq_irqoff(NET_RX_SOFTIRQ); /* 启动报文接收软中断 */
net_rx_action(由上一步触发,(源码文件:net\core\dev.c)
    dev->poll(即e1000_clean,源码文件:\drivers\net\e1000\e1000_main.c)
        adapter->clean_rx(即e1000_clean_rx_irq,源码文件:\drivers\net\e1000\e1000_main.c)
            netif_receive_skb(源码文件:net\core\dev.c)


netif_receive_skb根据以太头中的type值(当然,还有别的信息,在下还没弄明白)查找一个匹配的packet_type条目,
然后调用pt_prev->func对报文进行处理。pt_prev为指向查找到的packet_type条目的指针。
大部分packet_type条目都位于ptype_base中(源码文件:net\core\dev.c)。
各协议模块通过dev_add_pack接口向ptype_base中添加条目。
packet_type条目的一个关键成员是type,它是ethernet头中的type字段的某个值。
另一个关键成员是func,他是该协议模块对报文进行接收处理的函数。


例如,ip模块向ptype_base添加的packet_type为ip_packet_type,其定义如下:


(源码文件:net\ipv4\af_inet.c)


static struct packet_type ip_packet_type = {
.type = __constant_htons(ETH_P_IP),
.func = ip_rcv,
.gso_send_check = inet_gso_send_check,
.gso_segment = inet_gso_segment,
};


再如,arp模块向ptype_base添加的packet_type为arp_packet_type,其定义如下:
(源码文件:net\ipv4\Arp.c)


static struct packet_type arp_packet_type = {
.type = __constant_htons(ETH_P_ARP),
.func = arp_rcv,
};


接下来,我们看看IP协议模块对报文的接收处理。


(二)IP协议模块对报文的接收处理
根据ip_packet_type的定义,ip报文的接收处理由ip_rcv完成。
我们这里仅关注目的ip为本机的报文。
几个关键的执行路径如下:


ip_rcv (源码文件:net\ipv4\ip_input.c)
    ip_rcv_finish
        ip_route_input /* 查找路由,确定报文是上送给host还是转发出去 */
        dst_input
            skb->dst->input(具体函数ip_route_input决定。由于ip为本机,因此对应ip_local_deliver)
                ip_local_deliver_finish


ip_local_deliver_finish中,调用ipprot->handler对报文进行处理。
ipprot是net_protocol指针,他是根据IP报文的protocol(例如udp、tcp啦),引用inet_protos[protocol]得到的。


inet_protos定义如下(源码文件:net\ipv4\protocol.c)。
struct net_protocol *inet_protos[MAX_INET_PROTOS];
inet_protos数组元素指向一个inet_protos结构。
此结构的关键信息是handler函数。他是本协议模块对报文进行接收处理的函数。
例如,tcp、udp、icmp协议的net_protocol结构定义如下。


(源码文件:net\ipv4\af_inet.c)
static struct net_protocol tcp_protocol = {
.handler = tcp_v4_rcv,
.err_handler = tcp_v4_err,
.gso_send_check = tcp_v4_gso_send_check,
.gso_segment = tcp_tso_segment,
.no_policy = 1,
};


static struct net_protocol udp_protocol = {
.handler = udp_rcv,
.err_handler = udp_err,
.no_policy = 1,
};


static struct net_protocol icmp_protocol = {
.handler = icmp_rcv,
};


各协议模块的handler函数对收到到报文进行处理,并将相应的数据提交到各个socket中。
用户则通过一组socket接口将数据读走。
socket则相当于一个媒介,他处于用户和协议模块之间。
也就是说,socket层对于用户与协议模块都是可见的。
二者最终都是与socket进行交互。


最后,ip_local_deliver_finish中,实际上还做了raw socket方面的处理。
在将报文传递给inet_protos[protocol]之前,还要先看看有没有相应的raw_socket。
如果有的话,需要将报文复制给raw_socket一份。



版权声明:本文没有任何版权限制,任何人可以以任何方式使用本文。

【Linux 驱动】Netfilter/iptables (六) 内核协议栈编程(发送skb)

内核态基于 Netfilter 构造skb数据包 前面第四篇介绍了 Netfilter Hook 机制,我们知道了数据包在协议栈中传递时会经过不同的HOOK点,而每个HOOK点上又被Netfilte...
  • yeswenqian
  • yeswenqian
  • 2015年12月25日 10:33
  • 2461

htonl(), ntohl(), htons(), ntohs() 函数具体应用

htons和htonl函数具体应用 htons和htonl函数,是用来将主机字节顺序转换为网络字节顺序 在进行网络抓包时,抓到的包的数据是网络字节顺序,在进行编程时,要进行主机字节顺序和网络字节顺...
  • u010355144
  • u010355144
  • 2015年04月09日 19:18
  • 573

linux源码分析之字节序(4)-- little_endian.h

本节主要分析小端字节顺序。 首先,我们要回顾上一节讲过的大端、小端的概念:         字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端、大端两种字节顺序。小端字节序指...
  • liuruiqun
  • liuruiqun
  • 2015年04月16日 14:57
  • 681

Linux协议栈代码阅读笔记(一)

Linux协议栈代码阅读笔记(一) (基于linux-2.6.21.7) (一)用户态通过诸如下面的C库函数访问协议栈服务 int socket(int domain, int type, in...
  • crazycoder8848
  • crazycoder8848
  • 2013年09月26日 23:08
  • 2017

Linux TCP 协议栈数据流走读

1. 综述Linux的TCP协议非常复杂,看了几天Linux内核的tcp实现犹如雾里看花。在这里主要是根据书籍《The Linux Networking Architecture》 24章,以及结合网...
  • Al_xin
  • Al_xin
  • 2016年08月24日 22:34
  • 1862

Linux内核ARP的处理函数分析(arp_rcv, arp_send)

Linux内核ARP的处理函数分析(arp_rcv, arp_send) int arp_rcv(struct sk_buff *skb, struct net_device *dev,    ...
  • dayancn
  • dayancn
  • 2015年04月26日 23:19
  • 2130

linux源码分析之字节序(3)-- big_endian.h

本节主要分析大端字节顺序。 首先,我们要理解大端、小端的概念:         字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端、大端两种字节顺序。小端字节序指低字节数据存...
  • liuruiqun
  • liuruiqun
  • 2015年04月16日 14:36
  • 1268

Linux内核协议栈IP报文的上送转发及下发

这里主要分析在网络功能简单配置,且报文正常的情况下,报文的处理过程。 网卡接收到IP报文,经过一些执行路径后,最终进入ip_rcv做处理。  ip_rcv在网络功能简单配置,且报文正常的情况下,就是简...
  • crazycoder8848
  • crazycoder8848
  • 2016年07月21日 16:29
  • 1504

代码阅读和实践笔记

高级c数据类型 C指针 c程序中,指针一般用来: 构造链式数据结构 引用动态分配的数据结构 #define new(type) (type*) calloc(sizeof((type),1)...
  • laoj1228
  • laoj1228
  • 2017年01月14日 22:20
  • 229

arp_rcv函数实现分析

/* * 函数用于网络层收到一个arp请求时 */int arp_rcv(struct sk_buff *skb, /*接收到的包缓冲区指针*/    struct net_device *dev, ...
  • jccz_zys
  • jccz_zys
  • 2006年11月22日 14:00
  • 3134
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux协议栈代码阅读笔记(三)报文接收
举报原因:
原因补充:

(最多只允许输入30个字)