最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

一文講解sk_buff結構詳解

2022-08-09 16:30 作者:補給站Linux內(nèi)核  | 我要投稿

struct sk_buff可能是linux網(wǎng)絡代碼中最重要的數(shù)據(jù)結構,它表示接收或發(fā)送數(shù)據(jù)包的包頭信息,并包含很多成員變量供網(wǎng)絡代碼中的各子系統(tǒng)使用。 這個結構被網(wǎng)絡的不同層(MAC或者其他二層鏈路協(xié)議,三層的IP,四層的TCP或UDP等)使用,并且其中的成員變量在結構從一層向另一層傳遞時改變。 L4向L3傳遞前會添加一個L4的頭部,同樣,L3向L2傳遞前,會添加一個L3的頭部。添加頭部比在不同層之間拷貝數(shù)據(jù)的效率更高。由于在緩沖區(qū)的頭部 添加數(shù)據(jù)意味著要修改指向緩沖區(qū)的指針,這是個復雜的操作,所以內(nèi)核提供了一個函數(shù)skb_reserve來完成這個功能。協(xié)議棧中的每一層在往下一層傳 遞緩沖區(qū)前,第一件事就是調(diào)用skb_reserve在緩沖區(qū)的頭部給協(xié)議頭預留一定的空間。 skb_reserve同樣被設備驅動使用來對齊接收到包的包頭。如果緩沖區(qū)向上層協(xié)議傳遞,舊的協(xié)議層的頭部信息就沒什么用了。例如,L2的頭部只有在 網(wǎng)絡驅動處理L2的協(xié)議時有用,L3是不會關心它的信息的。但是,內(nèi)核并沒有把L2的頭部從緩沖區(qū)中刪除,而是把有效荷載的指針指向L3的頭部,這樣做, 可以節(jié)省CPU時間。

有些sk_buff成員變量的作用是方便查找或者是連接數(shù)據(jù)結構本身。內(nèi)核可以把sk_buff組織成一個雙向鏈表。當然,這個鏈表的結構要比常見的雙向 鏈表的結構復雜一點。就像任何一個雙向鏈表一樣,sk_buff中有兩個指針next和prev,其中,next指向下一個節(jié)點,而prev指向上一個節(jié) 點。在第一個節(jié)點前面會插入另一個結構sk_buff_head,這是一個輔助節(jié)點(作為sk_buff雙向鏈表的頭),它的定義如下:

sk_buff->sk這是一個指向擁有這個sk_buff的sock結構的指針。這個指針在網(wǎng)絡包由本機發(fā)出或者由本機進程接收時有效,因為插口相關的信息被L4(TCP或 UDP)或者用戶空間程序使用。如果sk_buff只在轉發(fā)中使用(這意味著,源地址和目的地址都不是本機地址),這個指針是NULL


【文章福利】小編推薦自己的Linux內(nèi)核技術交流群:【891587639】整理了一些個人覺得比較好的學習書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦!?。。ê曨l教程、電子書、實戰(zhàn)項目及代碼)? ??


**sk_buff->len ** 表示當前協(xié)議數(shù)據(jù)包的長度 。它包括主緩沖區(qū)中的數(shù)據(jù)長度(data指針指向它)和分片中的數(shù)據(jù)長度。

sk_buff->data_len和len不同,data_len只計算分片中數(shù)據(jù)的長度

sk_buff->mac_len這是mac頭的長度

sk_buff->users這是一個引用計數(shù),用于計算有多少實體引用了這個sk_buff緩沖區(qū)。它的主要用途是防止釋放sk_buff后,還有其他實體引用這個sk_buff。 因此,每個引用這個緩沖區(qū)的實體都必須在適當?shù)臅r候增加或減小這個變量。這個計數(shù)器只保護sk_buff結構本身,而緩沖區(qū)的數(shù)據(jù)部分由類似的計數(shù)器 (dataref)來保護.有時可以用atomic_inc和atomic_dec函數(shù)來直接增加或減小users,但是,通常還是使用函數(shù) skb_get和kfree_skb來操作這個變量。

sk_buff->truesize這是緩沖區(qū)的總長度,包括sk_buff結構和數(shù)據(jù)部分。如果申請一個len字節(jié)的緩沖區(qū),alloc_skb函數(shù)會把它初始化成len+sizeof(sk_buff)。當skb->len變化時,這個變量也會變化。

sk_buff->headsk_buff->datask_buff->tailsk_buff->end它們表示緩沖區(qū)和數(shù)據(jù)部分的邊界。在每一層申請緩沖區(qū)時,它會分配比協(xié)議頭或協(xié)議數(shù)據(jù)大的空間。head和end指向緩沖區(qū)的頭部和尾部,而data和 tail指向實際數(shù)據(jù)的頭部和尾部。每一層會在head和data之間填充協(xié)議頭,或者在tail和end之間添加新的協(xié)議數(shù)據(jù)。數(shù)據(jù)部分會在尾部包含一 個附加的頭部。


**void (destructor)(struct sk_buff skb)這個函數(shù)指針可以初始化成一個在緩沖區(qū)釋放時完成某些動作的函數(shù)。如果緩沖區(qū)不屬于一個socket,這個函數(shù)指針通常是不會被賦值的。如果緩沖區(qū)屬于一 個socket,這個函數(shù)指針會被賦值為sock_rfree或sock_wfree(分別由skb_set_owner_r或 skb_set_owner_w函數(shù)初始化)。這兩個sock_xxx函數(shù)用于更新socket的隊列中的內(nèi)存容量。

sk_buff->tstamp這個變量只對接收到的包有意義。它代表包接收時的時間戳,或者有時代表包準備發(fā)出時的時間戳。它在netif_rx里面由函數(shù)net_timestamp設置,而netif_rx是設備驅動收到一個包后調(diào)用的函數(shù)。

sk_buff->dev這個變量的類型是net_device,net_device它代表一個網(wǎng)絡設備。dev的作用與這個包是準備發(fā)出的包還是剛接收的包有關。當收到一個包 時,設備驅動會把sk_buff的dev指針指向收到這個包的網(wǎng)絡設備;當一個包被發(fā)送時,這個變量代表將要發(fā)送這個包的設備。在發(fā)送網(wǎng)絡包時設置這個值 的代碼要比接收網(wǎng)絡包時設置這個值的代碼復雜。有些網(wǎng)絡功能可以把多個網(wǎng) 絡設備組成一個虛擬的網(wǎng)絡設備(也就是說,這些設備沒有和物理設備直接關聯(lián)),并由一個虛擬網(wǎng)絡設備驅動管理。當虛擬設備被使用時,dev指針指向虛擬設 備的net_device結構。而虛擬設備驅動會在一組設備中選擇一個設備并把dev指針修改為這個設備的net_device結構。因此,在某些情況 下,指向傳輸設備的指針會在包處理過程中被改變。

sk_buff->input_dev這是收到包的網(wǎng)絡設備的指針。如果包是本地生成的,這個值為NULL。對以太網(wǎng)設備來說,這個值由eth_type_trans 初始化,它主要被流量控制代碼使用。

sk_buff->hsk_buff->nhsk_buff->mac這些是指向TCP/IP各層協(xié)議頭的指針:h指向L4(傳輸層),nh指向L3(網(wǎng)絡層),mac指向L2(數(shù)據(jù)鏈路層)。每個指針的類型都是一個聯(lián)合, 包含多個數(shù)據(jù)結構,每一個數(shù)據(jù)結構都表示內(nèi)核在這一層可以解析的協(xié)議。例如,h是一個包含內(nèi)核所能解析的L4協(xié)議的數(shù)據(jù)結構的聯(lián)合。每一個聯(lián)合都有一個 raw變量用于初始化,后續(xù)的訪問都是通過協(xié)議相關的變量進行的。 當接收一個包時,處理n層協(xié)議頭的函數(shù)從其下層(n-1層)收到一個緩沖區(qū),它的skb->data指向n層協(xié)議的頭。處理n層協(xié)議的函數(shù)把本層的 指針(例如,L3對應的是skb->nh指針)初始化為skb->data,因為這個指針(data指針)的值會在處理下一層協(xié)議時改變 (skb->data將被初始化成緩沖區(qū)里的其他地址)。在處理n層協(xié)議的函數(shù)結束時,在把包傳遞給n+1層的處理函數(shù)前,它會把skb-> data指針指向n層協(xié)議頭的末尾,這正好是n+1層協(xié)議的協(xié)議頭。 當網(wǎng)卡驅動程序收到一個UDP數(shù)據(jù)報后,它創(chuàng)建一個結構體struct sk_buff,確保sk_buff->data成員指向的空間足夠存放收到的數(shù)據(jù)(對于數(shù)據(jù)報分片的情況,因為比較復雜,我們暫時忽略,我們假設 一次收到的是一個完整的UDP數(shù)據(jù)報)。把收到的數(shù)據(jù)全部拷貝到sk_buff->data指向的空間,然后,把skb->mac.raw指 向data,此時,數(shù)據(jù)報的開始位置是一個以太網(wǎng)頭,所以skb->mac.raw指向鏈路層的以太網(wǎng)頭。然后通過調(diào)用skb_pull剝掉以太網(wǎng) 頭,所謂剝掉以太網(wǎng)頭,只是把data加上sizeof(struct ethhdr),同時len減去這個值,這樣,在邏輯上,skb已經(jīng)不包含以太網(wǎng)頭了,但通過skb->mac.raw還能找到它。這就是我們通常 所說的,IP數(shù)據(jù)報被收到后,在鏈路層被剝?nèi)ヒ蕴W(wǎng)頭。

sk_buff->dst這個變量在路由子系統(tǒng)中使用

sk_buff->sp這個變量被IPSec協(xié)議用于跟蹤傳輸?shù)男畔?/p>

sk_buff->cb[48]這是一個“control buffer”,或者說是一個私有信息的存儲空間,由每一層自己維護并使用。它在分配sk_buff結構時分配(它目前的大小是48字節(jié),已經(jīng)足夠為每一 層存儲必要的私有信息了)。在每一層中,訪問這個變量的代碼通常用宏實現(xiàn)以增強代碼的可讀性。例如,TCP用這個變量存儲tcp_skb_cb結構。 下面這個宏被TCP代碼用來訪問cb變量。在這個宏里面,有一個簡單的類型轉換: #define TCP_SKB_CB(__skb) ((struct tcp_skb_cb *)&((__skb)->cb[0]))

下面的例子是TCP子系統(tǒng)在收到一個分段時填充相關數(shù)據(jù)結構的代碼:

int tcp_v4_rcv(struct sk_buff *skb) { ? ?... ? ?th = skb->h.th; ? ?TCP_SKB_CB(skb)->seq = ntohl(th->seq); ? ?TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + ? ? ? ? ? ? ? ? skb->len - th->doff * 4); ? ?TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); ? ?TCP_SKB_CB(skb)->when = 0; ? ?TCP_SKB_CB(skb)->flags = skb->nh.iph->tos; ? ?TCP_SKB_CB(skb)->sacked = 0; ? ?... }

如果想要了解cb中的參數(shù)是如何被取出的,可以查看net/ipv4/tcp_output.c中的tcp_transmit_skb函數(shù)。這個函數(shù)被TCP用于向IP層發(fā)送一個分段。

sk_buff->csumsk_buff->ip_summed表示校驗和以及相關狀態(tài)標記

sk_buff->cloned一個布爾標記,當被設置時,表示這個結構是另一個sk_buff的克隆

sk_buff->pkt_type這個變量表示幀的類型,分類是由L2的目的地址來決定的。這個值在網(wǎng)卡驅動程序中由函數(shù)eth_type_trans通過判斷目的以太網(wǎng)地址來確定。如果 目的地址是FF:FF:FF:FF:FF:FF,則為廣播地址,pkt_type = PACKET_BROADCAST;如果最高位為1,則為組播地址,pkt_type = PACKET_MULTICAST;如果目的mac地址跟本機mac地址不相等,則不是發(fā)給本機的數(shù)據(jù)報,pkt_type = PACKET_OTHERHOST;否則就是缺省值PACKET_HOST。 /* Packet types /#define PACKET_HOST 0 / To us /#define PACKET_BROADCAST 1 / To all /#define PACKET_MULTICAST 2 / To group /#define PACKET_OTHERHOST 3 / To someone else /#define PACKET_OUTGOING 4 / Outgoing of any type */

sk_buff->priority這個變量描述發(fā)送或轉發(fā)包的QoS類別。如果包是本地生成的,socket層會設置priority變量。如果包是將要被轉發(fā)的, rt_tos2priority函數(shù)會根據(jù)ip頭中的Tos域來計算賦給這個變量的值。這個變量的值與DSCP(DiffServ CodePoint)沒有任何關系。

sk_buff->protocol這個變量是高層協(xié)議從二層設備的角度所看到的協(xié)議。典型的協(xié)議包括IP,IPV6和ARP。完整的列表在 include/linux/if_ether.h中。由于每個協(xié)議都有自己的協(xié)議處理函數(shù)來處理接收到的包,因此,這個域被設備驅動用于通知上層調(diào)用哪 個協(xié)議處理函數(shù)。每個網(wǎng)絡驅動都調(diào)用netif_rx來通知上層網(wǎng)絡協(xié)議的協(xié)議處理函數(shù),因此protocol變量必須在這些協(xié)議處理函數(shù)調(diào)用之前初始 化。

linux內(nèi)核是模塊化的,你可以選擇包含或者刪除某些功能。因此,sk_buff結構里面的一些成員變量只有在內(nèi)核選擇支持某些功能時才有效,比如防火墻(netfilter)或者qos: __u32 nfctinfo ... #ifdef CONFIG_NETFILTER struct nf_conntrack *nfct; #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) struct sk_buff *nfct_reasm; #endif #ifdef CONFIG_BRIDGE_NETFILTER struct nf_bridge_info nf_bridge;#endif__u32 nfmark;#endif / CONFIG_NETFILTER */

這些變量被netfilter使用(防火墻代碼),內(nèi)核編譯選項是“Device Drivers->Networking support-> Networking options-> Network packet filtering”和兩個子選項“Network packet filtering debugging”和“Bridged IP/ARP packets filtering” #ifdef CONFIG_NET_SCHED __u16 tc_index; #ifdef CONFIG_NET_CLS_ACT __u16 tc_verd; #endif #endif 這兩個變量被流量控制代碼使用。tc_index只有在編譯時定義了CONFIG_NET_SCHED符號才有效;tc_verd只有在編譯時定義了CONFIG_NET_CLS_ACT符號才有效。這兩個符號可以通過選擇特定的編譯選項來定義: Networking ---> Networking options ---> QoS and/or fair queueing ---> [] QoS and/or fair queueing[] Actions

QoS選項不能被編譯成內(nèi)核模塊。原因就是,內(nèi)核編譯之后,由某個選項所控制的數(shù)據(jù)結構是不能動態(tài)變化的。一般來說,如果某個選項會修改內(nèi)核數(shù)據(jù)結構(比 如說,在sk_buff里面增加一個項tc_index),那么,包含這個選項的組件就不能被編譯成內(nèi)核模塊。 你可能經(jīng)常需要查找是哪個make menuconfig編譯選項或者變種定義了某個#ifdef標記,以便理解內(nèi)核中包含的某段代碼。在2.6內(nèi)核中,最快的,查找它們之間關聯(lián)關系的方 法,就是查找分布在內(nèi)核源代碼樹中的kconfig文件中是否定義了相應的符號(每個目錄都有一個這樣的文件)。在2.4內(nèi)核中,你需要查看 Documentation/Configure.help文件。 Quality of Service(QoS)服務質(zhì)量





一文講解sk_buff結構詳解的評論 (共 條)

分享到微博請遵守國家法律
满洲里市| 达拉特旗| 万山特区| 苏尼特右旗| 衡东县| 襄樊市| 榆中县| 宜春市| 屏东县| 炉霍县| 那曲县| 余姚市| 谷城县| 新源县| 图木舒克市| 苍梧县| 桂林市| 桐乡市| 丰原市| 西乌珠穆沁旗| 苗栗县| 延长县| 西盟| 青冈县| 上饶市| 阳新县| 山阳县| 扶风县| 临沧市| 灵台县| 新营市| 资溪县| 古交市| 永登县| 常州市| 正蓝旗| 陇西县| 岳池县| 杨浦区| 淅川县| 云霄县|