1. 程式人生 > >linux協議棧pf_packet相關分析

linux協議棧pf_packet相關分析

一:名詞解釋:

1,BSD socket層:

bsd socket是Berkeley套接字應用程式介面(API)包括了一個用C語言寫成的應用程式開發庫,主要用於實現程序間通訊,在計算機網路通訊方面被廣泛使用。

Berkeley套接字介面的定義在幾個標頭檔案中。這些檔案的名字和內容與具體的實現之間有些許的不同。 大體上包括:
<sys/socket.h><netinet/in.h><sys/un.h><arpa/inet.h><netdb.h>

這個列表是一個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

各層主要函式以及位置功能說明:         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   各層主要函式以及位置功能說明:         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核心網路棧程式碼的準備知識

6,2.4中PACKET模組程式碼分析

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