日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

Linux 内核网络协议栈 ------sk_buff 结构体 以及 完全解释 (2.6.16)

發(fā)布時(shí)間:2023/11/30 linux 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux 内核网络协议栈 ------sk_buff 结构体 以及 完全解释 (2.6.16) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在2.6.24之后這個(gè)結(jié)構(gòu)體有了較大的變化,此處先說(shuō)一說(shuō)2.6.16版本的sk_buff,以及解釋一些問(wèn)題。


一、

先直觀的看一下這個(gè)結(jié)構(gòu)體~~~~~~~~~~~~~~~~~~~~~~在下面解釋每個(gè)字段的意義~~~~~~~~~~~

[cpp]?view plain?copy?print?
  • struct?sk_buff?{??
  • ?????????/*?These?two?members?must?be?first.?*/??
  • ?????????struct?sk_buff??????????*next;??
  • ?????????struct?sk_buff??????????*prev;??
  • ???
  • ?????????struct?sock?????????????*sk;??
  • ?????????struct?skb_timeval??????tstamp;??
  • ?????????struct?net_device???????*dev;??
  • ?????????struct?net_device???????*input_dev;??
  • ???
  • ?????????union?{??
  • ?????????????????struct?tcphdr???*th;??
  • ?????????????????struct?udphdr???*uh;??
  • ?????????????????struct?icmphdr??*icmph;??
  • ?????????????????struct?igmphdr??*igmph;??
  • ?????????????????struct?iphdr????*ipiph;??
  • ?????????????????struct?ipv6hdr??*ipv6h;??
  • ?????????????????unsigned?char???*raw;??
  • ?????????}?h;??
  • ???
  • ?????????union?{??
  • ?????????????????struct?iphdr????*iph;??
  • ?????????????????struct?ipv6hdr??*ipv6h;??
  • ?????????????????struct?arphdr???*arph;??
  • ?????????????????unsigned?char???*raw;??
  • ?????????}?nh;??
  • ???
  • ?????????union?{??
  • ?????????????????unsigned?char???*raw;??
  • ?????????}?mac;??
  • ???
  • ?????????struct??dst_entry???????*dst;??
  • ?????????struct??sec_path????????*sp;??
  • ???
  • ?????????/*?
  • ??????????*?This?is?the?control?buffer.?It?is?free?to?use?for?every?
  • ??????????*?layer.?Please?put?your?private?variables?there.?If?you?
  • ??????????*?want?to?keep?them?across?layers?you?have?to?do?a?skb_clone()?
  • ??????????*?first.?This?is?owned?by?whoever?has?the?skb?queued?ATM.?
  • ??????????*/??
  • ?????????char????????????????????cb[48];??
  • ???
  • ?????????unsigned?int????????????len,??
  • ?????????????????????????????????data_len,??
  • ?????????????????????????????????mac_len,??
  • ?????????????????????????????????csum;??
  • ?????????__u32???????????????????priority;??
  • ?????????__u8????????????????????local_df:1,??
  • ?????????????????????????????????cloned:1,??
  • ?????????????????????????????????ip_summed:2,??
  • ?????????????????????????????????nohdr:1,??
  • ?????????????????????????????????nfctinfo:3;??
  • ?????????__u8????????????????????pkt_type:3,??
  • ?????????????????????????????????fclone:2,??
  • ?????????????????????????????????ipvs_property:1;??
  • ?????????__be16??????????????????protocol;??
  • ???
  • ?????????void????????????????????(*destructor)(struct?sk_buff?*skb);??
  • #ifdef?CONFIG_NETFILTER??
  • ?????????__u32???????????????????nfmark;??
  • ?????????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??
  • #endif?/*?CONFIG_NETFILTER?*/??
  • #ifdef?CONFIG_NET_SCHED??
  • ?????????__u16???????????????????tc_index;???????/*?traffic?control?index?*/??
  • #ifdef?CONFIG_NET_CLS_ACT??
  • ?????????__u16???????????????????tc_verd;????????/*?traffic?control?verdict?*/??
  • #endif??
  • #endif??
  • ???
  • ???
  • ?????????/*?These?elements?must?be?at?the?end,?see?alloc_skb()?for?details.??*/??
  • ?????????unsigned?int????????????truesize;??
  • ?????????atomic_t????????????????users;??
  • ?????????unsigned?char???????????*head,??
  • ?????????????????????????????????*data,??
  • ?????????????????????????????????*tail,??
  • ?????????????????????????????????*end;??
  • };??

  • > : next和prev,這兩個(gè)域是用來(lái)連接相關(guān)的skb的(例如如果有分片,將這些分片連接在一起可以)

    > : sk,指向報(bào)文所屬的套接字指針

    > : tstamp,記錄接收或者傳輸報(bào)文的時(shí)間戳

    > : dev和input_dev,記錄接收或者發(fā)送的設(shè)備

    >: union u,對(duì)于一個(gè)層次,例如tcp層,可能有很多不同的協(xié)議,他們的協(xié)議頭不一樣,那么這個(gè)聯(lián)合體就是記錄這些協(xié)議頭的。

    ? ? ?此處u就是代表傳輸層

    > : union nh,代表網(wǎng)絡(luò)層頭

    > : union mac,代表鏈路層頭

    > : dst,指向des_entry結(jié)構(gòu),記錄了到達(dá)目的地的路由信息,以及其他的一些網(wǎng)絡(luò)特征信息。

    > : sp:安全路徑,用于xfrm

    > : cb[],保存與協(xié)議相關(guān)的控制信息,每個(gè)協(xié)議可能獨(dú)立使用這些信息。

    > :?重要的字段 len 和 data_len:

    ? ? ? len代: 表整個(gè)數(shù)據(jù)區(qū)域的長(zhǎng)度!這里要提前解釋幾個(gè)定義,skb的組成是有sk_buff控制 + 線性數(shù)據(jù) + 非線性數(shù)據(jù)?

    ? ? ? (skb_shared_info)?組成!

    ? ? ?后面會(huì)具體解釋是什么意思!在sk_buff這個(gè)里面沒(méi)有實(shí)際的數(shù)據(jù),這里僅僅是控制信息,數(shù)據(jù)是通過(guò)后面的data指針指向其他內(nèi)

    ? ? ?存塊的!那個(gè)內(nèi)存塊中是線性數(shù)據(jù)和

    ? ? ?非線性數(shù)據(jù)!那么len就是length(線性數(shù)據(jù)) + length(非線性數(shù)據(jù))!!!

    ? ? ?data_len: 指的是length(非線性數(shù)據(jù))!!!那么可以知道:length(線性數(shù)據(jù)) = ?skb->len - skb->data_len

    > : mac_len,指的是mac頭長(zhǎng)度

    > : csum,某時(shí)刻協(xié)議的校驗(yàn)和

    > : priority,報(bào)文排隊(duì)優(yōu)先級(jí),取決于ip中的tos域

    > : local_df,允許在本地分配

    > : cloned,保存當(dāng)前的skb_buff是克隆的還是原始數(shù)據(jù)

    > : ip_summed,是否計(jì)算ip校驗(yàn)和

    > : nohdr,僅僅引用數(shù)據(jù)區(qū)域

    > :?pkt_type,報(bào)文類型,例如廣播,多播,回環(huán),本機(jī),傳出...

    > : fclone,skb_buff克隆狀態(tài)

    > :?ipvs_property,skb_buff是否屬于ipvs

    > : protocal,協(xié)議信息

    > :?nfmark,用于鉤子之間通信

    > :?nfct_reasm,netfilter的跟蹤連接重新組裝指針

    > :?nf_bridge,保存橋接信息

    > : tc_index: Traffic control index,tc_verd: traffic control verdict

    > : truesize,該緩沖區(qū)分配的所有總的內(nèi)存,包括:skb_buff + 所有數(shù)據(jù)大小

    > : users,保存引用skb_buff的數(shù)量

    > : 重要數(shù)據(jù)字段:head,data,tail,end!!!

    ? ? head:指向分配給的線性數(shù)據(jù)內(nèi)存首地址( 建立起一個(gè)觀念:并不是分配這么多內(nèi)存,就都能被使用作為數(shù)據(jù)存儲(chǔ),可能沒(méi)這么多

    ? ? 數(shù)據(jù)也有可能!但是也不要認(rèn)為分配這么多 就足夠了,也不一定(非線性數(shù)據(jù)就是例子) )

    ? ? data:指向保存數(shù)據(jù)內(nèi)容的首地址!我們由head可以知道,head和data不一定就是指在同一個(gè)位置!!!

    ? ? tail:指向數(shù)據(jù)的結(jié)尾!

    ? ? end:指向分配的內(nèi)存塊的結(jié)尾! ( 由上面我們知道數(shù)據(jù)結(jié)尾 != 分配的內(nèi)存塊的結(jié)尾 )

    ? ? 下面還會(huì)具體分析!!!!!!!!!!!


    二、

    我覺(jué)得需要先了解一些對(duì)于一個(gè)數(shù)據(jù)skb到底有什么,或者說(shuō)由哪些元素組成!這就需要知道所謂的 “線性數(shù)據(jù)” 和 “非線性數(shù)據(jù)”。

    基本的組成如下:

    > : sk_buff : 這是一個(gè)sk_buff的控制結(jié)構(gòu)

    > : 線性數(shù)據(jù)區(qū)域

    > : 非線性數(shù)據(jù)區(qū)域( 由skb_shared_info結(jié)構(gòu)體管理 )


    那么下面通過(guò)一個(gè)圖來(lái)看看這個(gè)skb結(jié)構(gòu)到底是怎么樣的!看(圖一)


    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????(圖一)

    借助圖一,我們先來(lái)分析兩個(gè)重要字段:len和data_len

    之前說(shuō)過(guò)len代表的是整個(gè)數(shù)據(jù)的長(zhǎng)度,data_len代表的是非線性數(shù)據(jù)長(zhǎng)度。我們由圖一可以看到線性數(shù)據(jù)長(zhǎng)度為l1,再看看非線性數(shù)據(jù),其實(shí)就是看frags[]和frag_list

    ok...那么我們可以知道非線性數(shù)據(jù)長(zhǎng)度為( l2 + ... + ln ) + ( l(n+1) + ... + lm )

    即:len = l1 +?( l2 + ... + ln ) + ( l(n+1) + ... + lm )

    ? ? ? ? data_len =?( l2 + ... + ln ) + ( l(n+1) + ... + lm )


    ok...


    現(xiàn)在從分配內(nèi)存開(kāi)始解釋這個(gè)圖的由來(lái):

    我們使用skb_alloc給skb分配空間,那么剛剛分配結(jié)束返回時(shí)候,是什么樣的情況呢?看下圖(圖二):

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? (圖二)


    剛剛開(kāi)始初始化的時(shí)候,預(yù)分配一個(gè)一塊線性數(shù)據(jù)區(qū)域,這個(gè)區(qū)域一般放入的是各個(gè)協(xié)議層次的不同的頭,還有一些實(shí)際數(shù)據(jù),下面的非線性區(qū)域是為了彌補(bǔ)當(dāng)數(shù)據(jù)真的很多的時(shí)候,作為數(shù)據(jù)區(qū)域的擴(kuò)展!關(guān)于skb_shared_info具體意思下面會(huì)繼續(xù)說(shuō)!注意在初始化的時(shí)候,head,data和tail都指向內(nèi)存的開(kāi)始位置,head在這個(gè)位置始終不變,它表示的是分配的內(nèi)存的開(kāi)始位置。end的位置也是不變的,表示的是分配的內(nèi)存的結(jié)束位置。data和tail會(huì)隨著數(shù)據(jù)的加入和減少變化,總之表示的是放入數(shù)據(jù)的內(nèi)存區(qū)域(由圖一)可知。


    現(xiàn)在需要解釋一下skb_shared_info這個(gè)結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體真的是很很有特色!主要是其中的兩個(gè)字段frags和frag_list,下面繼續(xù)解釋:

    [cpp]?view plain?copy?print?
  • struct?skb_shared_info?{??
  • ?????????atomic_t????????dataref;????????//?對(duì)象被引用次數(shù)??
  • ?????????unsigned?short??nr_frags;???????//?分頁(yè)段數(shù)目,即frags數(shù)組元素個(gè)數(shù)??
  • ?????????unsigned?short??tso_size;?????????
  • ?????????unsigned?short??tso_segs;??
  • ?????????unsigned?short??ufo_size;??
  • ?????????unsigned?int????ip6_frag_id;??
  • ?????????struct?sk_buff??*frag_list;????//?一般用于分段(還沒(méi)有非常清楚的理解)??
  • ?????????skb_frag_t??????frags[MAX_SKB_FRAGS];?//?保存分頁(yè)數(shù)據(jù)(skb->data_len=所有的數(shù)組數(shù)據(jù)長(zhǎng)度之和)??
  • };??

  • 關(guān)于frags和frag_list沒(méi)有必然的聯(lián)系!


    > : 對(duì)于frags[]一般用在,當(dāng)數(shù)據(jù)真的很多,而且在線性數(shù)據(jù)區(qū)域裝不下的時(shí)候,需要使用這個(gè),skb_frag_t中是一頁(yè)一頁(yè)的數(shù)據(jù),先看看結(jié)構(gòu)體:

    [cpp]?view plain?copy?print?
  • struct?skb_frag_struct?{??
  • ?????????struct?page?*page;????//?代表一頁(yè)數(shù)據(jù)??
  • ?????????__u16?page_offset;????//?代表相對(duì)開(kāi)始位置的頁(yè)偏移量??
  • ?????????__u16?size;???????????//?page中數(shù)據(jù)長(zhǎng)度??
  • };??

  • 需要注意的是:只有在DMA支持物理分散頁(yè)的Scatter/Gather(SG,分散/聚集)操作時(shí)候才可以使用frags[]來(lái)保存剩下的數(shù)據(jù),否則,只能擴(kuò)展線性數(shù)據(jù)區(qū)域進(jìn)行保存!!!

    這些頁(yè)其實(shí)是其實(shí)就是虛擬頁(yè)映射到物理頁(yè)的結(jié)構(gòu),看下圖(圖三):


    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? (圖三)


    > : 對(duì)于frag_list來(lái)說(shuō),一般我們?cè)诜制臅r(shí)候里面裝入每個(gè)片的信息,注意,每個(gè)片最終也都是被封裝成一個(gè)小的skb,這個(gè)必須

    ? ? ?的!

    ? ? ?注意:具體怎么分片的看上一篇博文:數(shù)據(jù)分片?( ?看其中的ip_fragment函數(shù)??)

    ? ? ?那么看一下其基本結(jié)構(gòu)如圖四:

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? (圖四)


    三、

    最重要的是需要理解對(duì)于這個(gè)skb是怎么操作的,在操作的過(guò)程中,每一塊的內(nèi)存分配是怎么變化的,這才更重要!

    看下面的函數(shù)們:


    > : alloc_skb()函數(shù)

    [cpp]?view plain?copy?print?
  • static?inline?struct?sk_buff?*alloc_skb(unsigned?int?size,??
  • ?????????????????????????????????????????gfp_t?priority)??
  • {??
  • ?????????return?__alloc_skb(size,?priority,?0);??
  • }??

  • 其實(shí)看__alloc_skb函數(shù):

    [cpp]?view plain?copy?print?
  • struct?sk_buff?*__alloc_skb(unsigned?int?size,?gfp_t?gfp_mask,??
  • ?????????????????????????????int?fclone)??
  • {??
  • ?????????kmem_cache_t?*cache;??
  • ?????????struct?skb_shared_info?*shinfo;??
  • ?????????struct?sk_buff?*skb;??
  • ?????????u8?*data;??
  • ???
  • ?????????cache?=?fclone???skbuff_fclone_cache?:?skbuff_head_cache;????//?根據(jù)克隆狀態(tài)來(lái)判斷在哪一個(gè)緩沖區(qū)進(jìn)行分配cache??
  • ???
  • ?????????/*?Get?the?HEAD?*/??
  • ?????????skb?=?kmem_cache_alloc(cache,?gfp_mask?&?~__GFP_DMA);????????//?得到skb,注意這里沒(méi)有包含數(shù)據(jù),僅僅是skb_buff這個(gè)結(jié)構(gòu)體??
  • ?????????if?(!skb)??
  • ?????????????????goto?out;??
  • ???
  • ?????????/*?Get?the?DATA.?Size?must?match?skb_add_mtu().?*/??
  • ?????????size?=?SKB_DATA_ALIGN(size);?????????????????????????????????????//?獲得線性數(shù)據(jù)分片長(zhǎng)度(注意對(duì)齊)??
  • ?????????data?=?kmalloc(size?+?sizeof(struct?skb_shared_info),?gfp_mask);?//?注意分配的是什么,是size?+?skb_shared_info!!!!!??
  • ?????????if?(!data)??
  • ?????????????????goto?nodata;??
  • ???
  • ?????????memset(skb,?0,?offsetof(struct?sk_buff,?truesize));??????????//?初始化??
  • ?????????skb->truesize?=?size?+?sizeof(struct?sk_buff);???????????????//?實(shí)際大小等于sk_buff?+?size,剛剛開(kāi)始還沒(méi)有非線性數(shù)據(jù)??
  • ?????????atomic_set(&skb->users,?1);????????????????????????????????????
  • ?????????skb->head?=?data;????????????????????????????????????????????//?注意指針,這個(gè)結(jié)合上面的圖一清二楚??
  • ?????????skb->data?=?data;??
  • ?????????skb->tail?=?data;??
  • ?????????skb->end??=?data?+?size;??
  • ?????????/*?make?sure?we?initialize?shinfo?sequentially?*/??
  • ?????????shinfo?=?skb_shinfo(skb);??
  • ?????????atomic_set(&shinfo->dataref,?1);??
  • ?????????shinfo->nr_frags??=?0;??
  • ?????????shinfo->tso_size?=?0;??
  • ?????????shinfo->tso_segs?=?0;??
  • ?????????shinfo->ufo_size?=?0;??
  • ?????????shinfo->ip6_frag_id?=?0;??
  • ?????????shinfo->frag_list?=?NULL;??
  • ???
  • ?????????if?(fclone)?{??
  • ?????????????????struct?sk_buff?*child?=?skb?+?1;??
  • ?????????????????atomic_t?*fclone_ref?=?(atomic_t?*)?(child?+?1);??
  • ???
  • ?????????????????skb->fclone?=?SKB_FCLONE_ORIG;??
  • ?????????????????atomic_set(fclone_ref,?1);??
  • ???
  • ?????????????????child->fclone?=?SKB_FCLONE_UNAVAILABLE;??
  • ?????????}??
  • out:??
  • ?????????return?skb;??
  • nodata:??
  • ?????????kmem_cache_free(cache,?skb);??
  • ?????????skb?=?NULL;??
  • ?????????goto?out;??
  • }??

  • 那么alloc之后的圖就是(圖五):

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ?(圖五)

    其實(shí)和圖二是一樣的!我們可以看到,現(xiàn)在僅僅是分配了線束數(shù)據(jù)區(qū)域,但是現(xiàn)在還沒(méi)有數(shù)據(jù)!一定要注意!所以前面三個(gè)指針指在一起!因?yàn)闆](méi)有數(shù)據(jù),那么len和data_len的值就是0 !


    > : skb_reserve函數(shù)

    [cpp]?view plain?copy?print?
  • static?inline?void?skb_reserve(struct?sk_buff?*skb,?int?len)??
  • {??
  • ?????????skb->data?+=?len;??
  • ?????????skb->tail?+=?len;??
  • ?}??

  • 代碼其實(shí)很easy、就是移動(dòng)兩個(gè)指針而已~


    這個(gè)函數(shù)很重要,是為“協(xié)議頭”預(yù)留空間!而且是盡最大的空間預(yù)留,因?yàn)楹芏囝^都會(huì)有可選項(xiàng),那么我們不知道可選項(xiàng)是多大,所以只能是按照最大的分配,那么也說(shuō)明了一點(diǎn),預(yù)留的空間headroom也就是不一定都能使用完的!可能還有剩余的,由上面的圖也可以看出來(lái)!這也是為什么需要這么多指針的問(wèn)題!那么這個(gè)函數(shù)直接導(dǎo)致head指針和tail、data指針?lè)蛛x,入下面圖六所示:

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? (圖六)


    注意headroom就是用來(lái)存儲(chǔ)各個(gè)協(xié)議頭的足夠大的空間,tailroom就可以認(rèn)為是存儲(chǔ)其他線性數(shù)據(jù)的空間。( 這里不要曲解協(xié)議頭不是線性數(shù)據(jù),其實(shí)協(xié)議頭也是!!!所以當(dāng)增加頭的時(shí)候,data指針向上移動(dòng),當(dāng)增加其他數(shù)據(jù)的時(shí)候,tail指針向下移動(dòng) )。現(xiàn)在data和tail指向一起,那么還是說(shuō)明數(shù)據(jù)沒(méi)有!!!


    > : skb_put函數(shù) ----> 用于操作線性數(shù)據(jù)區(qū)域(tailroom區(qū)域)的用戶數(shù)據(jù)

    [cpp]?view plain?copy?print?
  • static?inline?unsigned?char?*skb_put(struct?sk_buff?*skb,?unsigned?int?len)??
  • {??
  • ?????????unsigned?char?*tmp?=?skb->tail;??
  • ?????????SKB_LINEAR_ASSERT(skb);????????????
  • ?????????skb->tail?+=?len;?????????????????//?移動(dòng)指針??
  • ?????????skb->len??+=?len;?????????????????//?數(shù)據(jù)空間增大len??
  • ?????????if?(unlikely(skb->tail>skb->end))?//?如果tail指針超過(guò)end指針了,那么處理錯(cuò)誤~??
  • ?????????????????skb_over_panic(skb,?len,?current_text_addr());??
  • ?????????return?tmp;??
  • }??


  • 這函數(shù)其實(shí)就是從tailroom預(yù)留空間,相當(dāng)于是移動(dòng)tail指針,這樣如果從上圖(圖六)開(kāi)始看,也就是tail開(kāi)始向下移動(dòng),和data分離了。。。一般來(lái)說(shuō),這樣做都是為了用戶數(shù)據(jù)再次處理,或者說(shuō)為TCP/IP的負(fù)載預(yù)留空間!

    看圖七,當(dāng)使用skb_put時(shí)候,由圖六---->圖七

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ?(圖七)

    我們可以看到指針的移動(dòng)data還是在headroom的下面,中間的是用戶數(shù)據(jù)預(yù)留的部分,由skb_put得到,tail表示數(shù)據(jù)結(jié)尾!再看一下sk_buff中的len,變成了數(shù)據(jù)長(zhǎng)度ld!!


    > : skb_push函數(shù):----------> 用于操作headroom區(qū)域的協(xié)議頭

    [cpp]?view plain?copy?print?
  • static?inline?unsigned?char?*skb_push(struct?sk_buff?*skb,?unsigned?int?len)??
  • {??
  • ?????????skb->data?-=?len;??????//?向上移動(dòng)指針??
  • ?????????skb->len??+=?len;??????//?數(shù)據(jù)長(zhǎng)度增加??
  • ?????????if?(unlikely(skb->data<skb->head))??//?data指針超過(guò)head那么就是處理錯(cuò)誤~??
  • ?????????????????skb_under_panic(skb,?len,?current_text_addr());??
  • ?????????return?skb->data;??
  • }??

  • 和skb_put對(duì)應(yīng),上面試操作用戶數(shù)據(jù)的,這里是操作協(xié)議頭的!其實(shí)就是data指針向上移動(dòng)而已~注意len增大了哦~前面說(shuō)了協(xié)議頭也是屬于數(shù)據(jù)!

    如下面圖所示,由圖七---->圖八

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ?(圖八)


    我們可以知道,data向上移動(dòng)了,同時(shí)注意len變成ld+lp了,其中l(wèi)p是這個(gè)增加的協(xié)議頭的長(zhǎng)度!


    > : skb_pull函數(shù):-----------> 其實(shí)這個(gè)函數(shù)才是與skb_push函數(shù)對(duì)應(yīng)的函數(shù)!因?yàn)檫@是去頭函數(shù),而skb_push是增頭函數(shù)!所以這個(gè)函數(shù)一般用在解包的時(shí)候!

    [cpp]?view plain?copy?print?
  • static?inline?unsigned?char?*skb_pull(struct?sk_buff?*skb,?unsigned?int?len)??
  • {??
  • ?????????return?unlikely(len?>?skb->len)???NULL?:?__skb_pull(skb,?len);??
  • }??
  • ???
  • ???
  • static?inline?unsigned?char?*__pskb_pull(struct?sk_buff?*skb,?unsigned?int?len)??
  • {??
  • ?????????if?(len?>?skb_headlen(skb)?&&??
  • ?????????????!__pskb_pull_tail(skb,?len-skb_headlen(skb)))??
  • ?????????????????return?NULL;??
  • ?????????skb->len?-=?len;??????????????????????????????//?長(zhǎng)度減小??
  • ?????????return?skb->data?+=?len;??????????????????????//?移動(dòng)指針??
  • }??

  • 其實(shí)就是data指針向下移動(dòng),當(dāng)前一個(gè)協(xié)議頭被去掉,headroom剩余的空間增大了!看下圖:

    由圖八---->圖九:

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??(圖九)


    虛線是data之前的指針位置,現(xiàn)在移動(dòng)到下面實(shí)線!!需注意:len的長(zhǎng)度減小,減小的大小是剝?nèi)サ念^的大小!!


    四、

    最后我們從兩條線整體分析一下:

    1:從應(yīng)用層用戶數(shù)據(jù)開(kāi)始,直到物理層發(fā)送出去

    ? ? ? > 初始化的什么就不多說(shuō)了,和前面的差不多,現(xiàn)在也加入用戶數(shù)據(jù)已經(jīng)在了,如圖七所示一樣!那么到了TCP層,需要增加

    ? ? ? ? ?TCP層的頭:

    ? ? ? ? ?如圖10所示:

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ? ?(圖10)


    ? ? ? ??? ? 需要注意的是這里是傳輸層,那么傳輸層的結(jié)構(gòu)u中的th代表的是tcp的頭,那么tcp指向tcp頭OK!同時(shí)注意 len長(zhǎng)度+=l1 哦~~~

    ? ? ? ? > 再看到了IP層:如圖11

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???(圖11)


    ??? ? ? ? ? ? ? 至于需要解釋什么就沒(méi)什么了,都是一樣的~

    ? ? ? ? ? ? ?> 到鏈路層了:如圖12

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? (圖12)


    ??OK!


    2:第二個(gè)過(guò)程其實(shí)是第一個(gè)逆過(guò)程,都差不多,所以不多說(shuō)了~


    五、

    最后看一下操作skb的兩個(gè)函數(shù)pskb_copy和skb_copy

    前者僅僅是將sk_buff的結(jié)構(gòu)體和線性數(shù)據(jù)copy過(guò)來(lái),對(duì)于非線性數(shù)據(jù),是引用原始的skb的數(shù)據(jù)的!而后者是不僅將sk_buff和線性數(shù)據(jù)拷貝,同時(shí)將非線性數(shù)據(jù)也copy了一份,看下面就明白了!這就在效率上就差了很多!所以如果不想修改數(shù)據(jù),那么還是使用pskb_copy更好!


    對(duì)于pskb_copy:



    對(duì)于skb_copy:



    OK ?我覺(jué)得差不多了~~~~~結(jié)束~~~~~~~~~~~~~?

    總結(jié)

    以上是生活随笔為你收集整理的Linux 内核网络协议栈 ------sk_buff 结构体 以及 完全解释 (2.6.16)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。