linux协议栈pf_packet相关分析

 

一:名词解释:

1,BSD socket层:

bsd socket是Berkeley套接字应用程序接口(API)包括了一个用C语言写成的应用程序开发库,主要用于实现进程间通讯,在计算机网络通讯方面被广泛使用。

Berkeley套接字接口的定义在几个头文件中。这些文件的名字和内容与具体的实现之间有些许的不同。 大体上包括:

这个列表是一个Berkeley套接字API库提供的函数或者方法的概要:
socket() 创建一个新的确定类型的套接字,类型用一个整型数值标识,并为它分配系统资源。
bind() 一般用于服务器端,将一个套接字与一个套接字地址结构相关联,比如,一个指定的本地端口和IP地址。
listen() 用于服务器端,使一个绑定的TCP套接字进入监听状态。
connect() 用于客户端,为一个套接字分配一个自由的本地端口号。 如果是TCP套接字的话,它会试图获得一个新的TCP连接。
accept() 用于服务器端。 它接受一个从远端客户端发出的创建一个新的TCP连接的接入请求,创建一个新的套接字,与该连接相应的套接字地址相关联。
send()和recv(),或者write()和read(),或者recvfrom()和sendto(), 用于往/从远程套接字发送和接受数据。
close() 用于系统释放分配给一个套接字的资源。 如果是TCP,连接会被中断。
gethostbyname()和gethostbyaddr() 用于解析主机名和地址.
select() 用于修整有如下情况的套接字列表: 准备读,准备写或者是有错误。


poll() 用于检查套接字的状态。 套接字可以被测试,看是否可以写入、读取或是有错误。
getsockopt() 用于查询指定的套接字一个特定的套接字选项的当前值。
setsockopt() 用于为指定的套接字设定一个特定的套接字选项。

http://zh.wikipedia.org/wiki/Berkeley套接字

2,协议栈 Protocol Stack 

协议族是一组协议的集合, 协议栈是协议的实现,指网络中各层协议的总和(有顺序的一组协议),  协议栈的工作原理类似于栈,遵守FIFO的原则。其形象的反映了一个网络中文件传输的过程:由上层协议到底层协议,再由底层协议到上层协议。使用最广泛的是英特网协 议栈,由上到下的协议分别是:应用层(HTTP,TELNET,DNS,EMAIL等),运输层(TCP,UDP),网络层(IP),链路层(WI- FI,以太网,令牌环,FDDI等),物理层.

TCP/IP也称”国际协议簇”, 即不仅指 TCP/IP协议本身,而且包括与其有关的协议。 TCP为传输控制协议,IP为网际协议,是网络层最重要的协议。采用TCP/IP协议通过互联网传送信息可减少网络中的传输阻塞,方便大批量的数据在网上 传输,从而提高网络的传输效率。 TCP/IP协议族中包括上百个互为关联的协议,其中有:Telnet(Remote Login):提供远程登录功能; FTP (FileTransfer Protocol):远程文件传输协议,允许用户将远程主机上的文件拷贝到自己的计算机上; SMTP (Simple Messagetransfer Protocol):简单信息传输协议,主要用于传输电子邮件;NFS(Network File Server):网络文件服务器,可使多台计算机透明地访问彼此的目录 ; UDP ( User DatagramProtocol):用户数据包协议。

3,INET socket层

BSD socket向用户提供了一个一致性的网络编程接口,他的底层是INET PF_UNIX PF_IPX  PF_PACKET PF_INET6 等协议栈。INET socket层是其中的IPv4网络协议的接口,相当于建立了AF_INET形式的socket,该层使用sock结构保存接口上额外的参数,主要的文件有net/ipv4/protocol.c、net/ipv4/af_inet.c和net/core/sock.c。

socket层支持包括TCP/IP协议在内的Internet协议族,一个协议使用另一个协议的服务。它与BSD socket层的接口要通过一系列Internet协议簇,socket操作,这一操作是在网络初始化时就已经注册到BSD socket层的。BSD socket层从已注册的INET proto_ops数据结构中调用INET层socket支持例程来为它执行工作。例如,一个地址族为INET的BSD socket建立请求,将用到下层的INET socket的建立函数。。在这些操作中,BSD socket层把用来描述BSD socket的socket 结构传构到INET层。为了不把BSD socket与TCP/IP的特定信息搞混,INET socket层使用它自己的数据结构 --sock,它与BSD socket结构相连。这意味着后来的INET socket调用能够很容易地重新找到sock结构。sock结构的协议操作指针(sock->sk_prot)也在初始化时建立,它依赖与被请求的协议。如果请求的是TCP,那么sock结构的协议操作指针将指向TCP连接所必需的TCP协议操作集。proto_ops(socket->ops)结构由地址族类型和一系列指向与特定地址族对应的socket操作例程的函数指针组成。

推断:bsd socket层封装了操作inet socket层的函数,inet socket层可以替换成其他协议层,比如pf_packet

4,TCP/UDP层,IP层;

实现传输层和网络层的操作,TCP/UDP层使用inet_protocol和proto结构,主要文件有

net/ipv4/udp.c、net/ipv4/datagram.c、net/ipv4/tcp_input.c和net/ipv4/tcp_out.c。ip层使用packet_type结构表示,主要文件包括net/ipv4文件夹下的ip_forward.c,ip_fragment.c,ip_input.c,ip_output.c。

5,驱动硬件接口层:

实现网络层操作,该层使用net_device结构表示,主要的文件包括net/core/dev.c和driver/net目录下的所有文件。使用PPP,SLIP,Eethernet协议。

6,总结

本文要使用的Linux Net/4网络源代码的,其中大部分位于目录/usr/src/linux-2.x/net,列表如下,
插口层
BSD Socket
/net/socket.c
/net/protocols.c
INET Socket
/ipv4/protocol.c
/ipv4/af_inet.c
/net/ipv4/core/sock.c
协议层
TCP/UDP
/net/ipv4/udp.c
/net/ipv4/datagram.c
/net/ipv4/tcp_input.c
/net/ipv4//tcp_output.c
/net/ipv4/tcp.c
/net/ipv4/tcp_minisocks.c
/net/ipv4/tcp_timer.c etc...
IP
/net/ipv4/ip_forward.c
/net/ipv4/ip_fragment.c
/net/ipv4/ip_input.c
/net/ipv4/ip_output.c
接口层
net/core/dev.c
driver/net
Ethernet


二:linux内核接收网络数据包处理流程

1,收包

^

|--------------bsd socket层---------
| sys_read fs/read_write.c
| sock_read net/socket.c
| sock_recvmsg net/socket.c

|--------------inet socket层(也可以是PF_pocket层)-----------

inet_create
| inet_recvmsg net/ipv4/af_inet.c
| udp_recvmsg net/ipv4/udp.c
| skb_recv_datagram net/core/datagram.c
| ------------------------------------------- 传输层--------
| sock_queue_rcv_skb include/net/sock.h
| udp_queue_rcv_skb net/ipv4/udp.c
| udp_rcv net/ipv4/udp.c
| ip_local_deliver_finish net/ipv4/ip_input.c
| ip_local_deliver net/ipv4/ip_input.c
| ip_recv net/ipv4/ip_input.c
| net_rx_action net/dev.c
| ----------------------------------链路层----------
| netif_rx net/dev.c
| el3_rx driver/net/3c309.c
| el3_interrupt driver/net/3c309.c



三:linux内核网络数据包发送流程

如果socket(PF_INET,SOCK_DGRAM,IPPROTO_IP)

|--------------socket

| sys_write fs/read_write.c 
| sock_writev net/socket.c
| sock_sendmsg net/socket.c
| inet_sendmsg net/ipv4/af_inet.c

|----------------传输层(协议栈)-----------
| udp_sendmsg net/ipv4/udp.c
| ip_build_xmit net/ipv4/ip_output.c
| output_maybe_reroute net/ipv4/ip_output.c
| ip_output net/ipv4/ip_output.c
| ip_finish_output net/ipv4/ip_output.c

|--------------链路层(网卡驱动)---------------
| dev_queue_xmit net/dev.c
| --------------------------------------------
| el3_start_xmit driver/net/3c309.c
V

推断使用socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))

|--------------socket

| sys_write fs/read_write.c 
| sock_writev net/socket.c
| sock_sendmsg net/socket.c (sock->ops = &packet_ops_spkt;)
|----------------传输层(协议栈)-----------
|packet_sendmsg_spkt  net/packet/af_packet.c

|--------------链路层(网卡驱动)---------------
| dev_queue_xmit net/dev.c
| --------------------------------------------
| el3_start_xmit driver/net/3c309.c
V

 


linux协议栈pf_packet相关分析_第1张图片

各层主要函数以及位置功能说明:
 
        1)sock_write:初始化msghdr{}结构 net/socket.c
 
        2)sock_sendmsg:net/socket.c
 
        3)inet_sendmsg:net/ipv4/af_net.c
 
        4)tcp_sendmsg:申请sk_buff{}结构的空间,把msghdr{}结构中的数据填入sk_buff空间。net/ipv4/tcp.c
 
        5)tcp_send_skb:net/ipv4/tcp_output.c
 
        6)tcp_transmit_skb:net/ipv4/tcp_output.c
 
        7)ip_queue_xmit:net/ipv4/ip_output.c
 
        8)ip_queue_xmit2:net/ipv4/ip_output.c
 
        9)ip_output:net/ipv4/ip_output.c
 
        10)ip_finish_output:net/ipv4/ip_output.c
 
        11)ip_finish_output2:net/ipv4/ip_output.c
 
        12)neigh_resolve_output:net/core/neighbour.c
 
        13)dev_queue_xmit:net/core/dev.c
  linux协议栈pf_packet相关分析_第2张图片
各层主要函数以及位置功能说明:
 
        1)sock_read:初始化msghdr{}的结构类型变量msg,并且将需要接收的数据存放的地址传给msg.msg_iov->iov_base.      net/socket.c
 
        2)sock_recvmsg: 调用函数指针sock->ops->recvmsg()完成在INET Socket层的数据接收过程.其中sock->ops被初始化为inet_stream_ops,其成员recvmsg对应的函数实现为inet_recvmsg()函数. net/socket.c
 
        3)sys_recv()/sys_recvfrom():分别对应着面向连接和面向无连接的协议两种情况. net/socket.c
 
        4)inet_recvmsg:调用sk->prot->recvmsg函数完成数据接收,这个函数对于tcp协议便是tcp_recvmsg net/ipv4/af_net.c
 
        5)tcp_recvmsg:从网络协议栈接收数据的动作,自上而下的触发动作一直到这个函数为止,出现了一次等待的过程.函数tcp_recvmsg可能会被动地等待在sk的接收数据队列上,也就是说,系统中肯定有其他地方会去修改这个队列使得tcp_recvmsg可以进行下去.入口参数sk是这个网络连接对应的sock{}指针,msg用于存放接收到的数据.接收数据的时候会去遍历接收队列中的数据,找到序列号合适的.
 
        但读取队列为空时tcp_recvmsg就会调用tcp_v4_do_rcv使用backlog队列填充接收队列.
 
        6)tcp_v4_rcv:tcp_v4_rcv被ip_local_deliver函数调用,是从IP层协议向INET Socket层提交的"数据到"请求,入口参数skb存放接收到的数据,len是接收的数据的长度,这个函数首先移动skb->data指针,让它指向tcp头,然后更新tcp层的一些数据统计,然后进行tcp的一些值的校验.再从INET Socket层中已经建立的sock{}结构变量中查找正在等待当前到达数据的哪一项.可能这个sock{}结构已经建立,或者还处于监听端口、等待数据连接的状态。返回的sock结构指针存放在sk中。然后根据其他进程对sk的操作情况,将skb发送到合适的位置.调用如下:
 
        TCP包接收器(tcp_v4_rcv)将TCP包投递到目的套接字进行接收处理. 当套接字正被用户锁定,TCP包将暂时排入该套接字的后备队列(sk_add_backlog).这时如果某一用户线程企图锁定该套接字(lock_sock),该线程被排入套接字的后备处理等待队列(sk->lock.wq).当用户释放上锁的套接字时(release_sock,在tcp_recvmsg中调用),后备队列中的TCP包被立即注入TCP包处理器(tcp_v4_do_rcv)进行处理,然后唤醒等待队列中最先的一个用户来获得其锁定权. 如果套接字未被上锁,当用户正在读取该套接字时, TCP包将被排入套接字的预备队列(tcp_prequeue),将其传递到该用户线程上下文中进行处理.如果添加到sk->prequeue不成功,便可以添加到 sk->receive_queue队列中(用户线程可以登记到预备队列,当预备队列中出现第一个包时就唤醒等待线程.)   /net/tcp_ipv4.c
 
        7)ip_rcv、ip_rcv_finish:从以太网接收数据,放到skb里,作ip层的一些数据及选项检查,调用ip_route_input()做路由处理,判断是进行ip转发还是将数据传递到高一层的协议.调用skb->dst->input函数指针,这个指针的实现可能有多种情况,如果路由得到的结果说明这个数据包应该转发到其他主机,这里的input便是ip_forward;如果数据包是给本机的,那么input指针初始化为ip_local_deliver函数./net/ipv4/ip_input.c
 
        8)ip_local_deliver、ip_local_deliver_finish:入口参数skb存放需要传送到上层协议的数据,从ip头中获取是否已经分拆的信息,如果已经分拆,则调用函数ip_defrag将数据包重组。然后通过调用ip_prot->handler指针调用tcp_v4_rcv(tcp)。ip_prot是inet_protocol结构指针,是用来ip层登记协议的,比如由udp,tcp,icmp等协议。 /net/ipv4/ip_input.c

1,linux协议栈分析sk_buff的结构分析:

在内核中sk_buff表示一个网络数据包,它是一个双向链表,而链表头就是sk_buff_head,在老的内核里面sk_buff会有一个list域直接指向sk_buff_head也就是链表头,现在在2.6.32里面这个域已经被删除了。

http://simohayha.iteye.com/blog/556168


2,linux协议栈struct sk_buff *skb相关的操作函数

struct sk_buff * skb

skb为要引用的缓冲区 

http://blog.csdn.net/jasenwan88/article/details/7365060


3,Linux.协议栈分析.AF_PACKET

当通过socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))来创建处理链路层数据包时,内核会首先调用packet_create创建套接字

http://acm.hrbeu.edu.cn/~puppy/2012/02/09/linux-协议栈分析-af_packet/

4,Linux 网卡驱动相关——01-02-03

http://www.cnblogs.com/zhuyp1015/archive/2012/08/04.html

5.linux内核网络栈代码的准备知识

http://www.cnblogs.com/better-zyy/archive/2012/03/16/2400811.html

6,2.4中PACKET模块代码分析

http://linux.chinaunix.net/techdoc/net/2006/01/18/926921.shtml

你可能感兴趣的:(c,linux)