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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

tcp/ip 协议栈Linux源码分析二 IPv4分片报文重组分析二

發布時間:2025/4/5 linux 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 tcp/ip 协议栈Linux源码分析二 IPv4分片报文重组分析二 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

繼續接著上篇講,之前我們說過,收到分片報文后首先會檢查分片報文所占內存是否過大,如果超過閾值的話就要調用ip_evictor函數去釋放一些舊的分片隊列,關于如何釋放分片隊列資源上一篇已經總結完成,接下來來看下進一步的處理,即如何查找分片隊列的,先看下代碼:

/* Lookup (or create) queue header *//* 這里根據分片五元組(源地址、目的地址、IP ID,protocol, user)去查找分片隊列* ip_find函數查找成功就返回對應的分片隊列,查找失敗就新建一個分片隊列,* 如果分配失敗的話就返回NULL;*/if ((qp = ip_find(net, ip_hdr(skb), user)) != NULL) {int ret;spin_lock(&qp->q.lock);/* 這里是分片隊列排隊的地方,報文的排隊,重組都在這里執行,下面* 再來分析該函數。*/ret = ip_frag_queue(qp, skb);spin_unlock(&qp->q.lock);/* 這是一個包裹函數,減少分片隊列的引用計數,如果沒人引用該* 隊列就調用inet_frag_destroy釋放隊列所占資源。*/ipq_put(qp);return ret;}

首先是調用ip_find()函數根據報文的五元組得到一個hash值去查找hash表找到對應的分片隊列,找到的話返回,找不到并且當前hash桶的深度不超過一定的值的話就新建一個隊列,否則就直接返回NULL。

我們看下ip_find()具體的處理流程:

/* Find the correct entry in the "incomplete datagrams" queue for* this IP datagram, and create new one, if nothing is found.* 從哈希表中找到對應的分片隊列,找不到就新建一個*/ static inline struct ipq *ip_find(struct net *net, struct iphdr *iph, u32 user) {struct inet_frag_queue *q;struct ip4_create_arg arg;unsigned int hash;/* arg包含了分片的五元組,源地址、目的地址、協議 * IP ID以及user(表示調用者,可能是協議棧也可能是netfilter )*/arg.iph = iph;arg.user = user;/* 先持有哈希表的讀鎖,防止更改 */read_lock(&ip4_frags.lock);/* 根據上述五元組到一個hash值,經典的hash函數,可以拿來自用 */hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);/* 根據hash值查找hash表,這里arg的作用是對分片隊列進行匹配,* 因為hash值相等的分片隊列能有很多,在這個函數里,如果找不到* 的話就會去新建一個分片隊列。*/q = inet_frag_find(&net->ipv4.frags, &ip4_frags, &arg, hash);if (IS_ERR_OR_NULL(q)) {inet_frag_maybe_warn_overflow(q, pr_fmt());return NULL;}/* 找到了,返回ipq分片隊列指針,注意區分struct ipq 和* struct inet_frag_queue的關系,兩者是包含關系,前者包含后者*/return container_of(q, struct ipq, q); }

接著看inet_frag_find 分片隊列查找函數的實現:

/* 分片隊列查找函數 */ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,struct inet_frags *f, void *key, unsigned int hash)__releases(&f->lock) {struct inet_frag_queue *q;struct hlist_node *n;int depth = 0;/* 遍歷hash表,即ip4_frags->hash[hash],然后調用match回調函數* 去和報文的五元組進行匹配,找到的話就增加該隊列的引用計數并返回其指針,* 找不到的話增加hash桶的深度,繼續查找下一個。* ip4_frags 注冊的match 回調函數是ip4_frag_match,在ip_fragment.c文件里* 該函數很簡單,就是去比較五元組是否完全一樣。*/hlist_for_each_entry(q, n, &f->hash[hash], list) {if (q->net == nf && f->match(q, key)) {atomic_inc(&q->refcnt);read_unlock(&f->lock);return q;}depth++;}read_unlock(&f->lock);/* 還是沒找到,如果hash桶深不超過限值的話就調用inet_frag_create* 創建一個新的分片隊列,超出的話直接返回錯誤就得了。* 通常收到第一個分片的時候會走到這里。*/if (depth <= INETFRAGS_MAXDEPTH)return inet_frag_create(nf, f, key);elsereturn ERR_PTR(-ENOBUFS); } EXPORT_SYMBOL(inet_frag_find);

match對調函數,處理很簡單,就是對報文的五元組和分片隊列進行比較;

static int ip4_frag_match(struct inet_frag_queue *q, void *a) {struct ipq *qp;struct ip4_create_arg *arg = a;qp = container_of(q, struct ipq, q);return qp->id == arg->iph->id &&qp->saddr == arg->iph->saddr &&qp->daddr == arg->iph->daddr &&qp->protocol == arg->iph->protocol &&qp->user == arg->user; }

這里重點關注下?inet_frag_create 函數:

/* 創建分片隊列 */ static struct inet_frag_queue *inet_frag_create(struct netns_frags *nf,struct inet_frags *f, void *arg) {struct inet_frag_queue *q;/* 創建并初始化分片隊列 */q = inet_frag_alloc(nf, f, arg);if (q == NULL)return NULL;/* 將分片隊列插入到分片哈希表中和lru鏈表尾部 */return inet_frag_intern(nf, q, f, arg); }

inet_frag_alloc就是創建一個分片隊列緩存然后初始化:

static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf,struct inet_frags *f, void *arg) {struct inet_frag_queue *q;/* qsize指的是分片隊列的固定大小,等于sizeof(struct ipq) */q = kzalloc(f->qsize, GFP_ATOMIC);if (q == NULL)return NULL;/* 初始化分片隊列,將五元組賦值給分片隊列,* constructor是初始化回調函數是,ip4_frag_init(), 在ipfrag_init()里設置。*/f->constructor(q, arg);/* 增加分片所占用的內存大小 */atomic_add(f->qsize, &nf->mem);/* 初始化該分片隊列的定時器,并設置該定時器的回調處理函數 * 回調處理函數是在系統初始化的時候設置的,ip4的分片定時器* 回調處理函數是ip_expire(), 該定時器的主要作用是重組超時后* 釋放該分片隊列所占資源,防止大量分片長時間占用內存,定時器* 的時間也是可以通過proc文件系統去配置的等。*/setup_timer(&q->timer, f->frag_expire, (unsigned long)q);spin_lock_init(&q->lock);/* 初始化引用計數為1 */atomic_set(&q->refcnt, 1);q->net = nf;return q; }

上面分片隊列創建完成之后,還要調用inet_frag_intern()函數將分片隊列插入到hash數組中,看下這個函數的處理:

/* 分片隊列插入函數 */ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,struct inet_frag_queue *qp_in, struct inet_frags *f,void *arg) {struct inet_frag_queue *qp; #ifdef CONFIG_SMPstruct hlist_node *n; #endifunsigned int hash;/* 因為是修改分片hash表,這里要求寫鎖 */write_lock(&f->lock);/** While we stayed w/o the lock other CPU could update* the rnd seed, so we need to re-calculate the hash* chain. Fortunatelly the qp_in can be used to get one.*//** hashfn函數指針在ipfrag_init()里初始化為ip4_hashfn(),* 就是一個hash函數*/hash = f->hashfn(qp_in); #ifdef CONFIG_SMP/* With SMP race we have to recheck hash table, because* such entry could be created on other cpu, while we* promoted read lock to write lock.* * 在多核處理情況下有可能其它CPU也收到同一路報文然后創建 了* 分片隊列,如果出現這種情況就將我們新創建的分片隊列釋放掉,* 即設置last_in標志位,然后調用inet_frag_put()做釋放處理,* 這時候把先創建的分片隊列qp返回就好了。*/hlist_for_each_entry(qp, n, &f->hash[hash], list) {if (qp->net == nf && f->match(qp, arg)) {atomic_inc(&qp->refcnt);write_unlock(&f->lock);qp_in->last_in |= INET_FRAG_COMPLETE;inet_frag_put(qp_in, f);return qp;}} #endifqp = qp_in;/* 重新初始化分片隊列超時時間 */if (!mod_timer(&qp->timer, jiffies + nf->timeout))atomic_inc(&qp->refcnt);atomic_inc(&qp->refcnt);/* 插入到分片hash表的頭部 */hlist_add_head(&qp->list, &f->hash[hash]);/* 插入到lru鏈表的尾部,當分片所占空用過大的時候,* 內核會從lru的首部順序釋放分片隊列,因為排在前面的* 都是舊的分片,新的都掛在lru尾部*/list_add_tail(&qp->lru_list, &nf->lru_list);/* 增加分片隊列個數 */nf->nqueues++;/* 插入結束,釋放寫鎖 */write_unlock(&f->lock);return qp; }

在多核處理情況下可能會重復創建分片隊列,這時候后創建的分片隊列對調用inet_frag_put() 函數進行釋放,這是個靜態內聯函數,原型在inet_frag.h里

static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f) {/* 當分片隊列引用計數為0的時候,釋放分片隊列 */if (atomic_dec_and_test(&q->refcnt))inet_frag_destroy(q, f, NULL); }

inet_frag_destroy()函數上篇博客已介紹,這里不再重復。

ip_find()函數返回后就已經得到了該報文所對應的分片隊列,這時候再調用ip_frag_queue()進行進一步處理,當然,ip_find也有可能返回失敗,這個時候就只能釋放該報文skb緩存。

ip_frag_queue函數主要進行分片報文的排隊、重組處理,這里需要處理多種異常情況,函數比較長,今晚就先不講了,放在下篇講。

?

總結

以上是生活随笔為你收集整理的tcp/ip 协议栈Linux源码分析二 IPv4分片报文重组分析二的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 伊人av一区| www青青草| 天堂在线国产 | 日韩三级网| 亚洲图片自拍偷拍区 | 在线91观看 | 国产在线观看a | 欧美成人综合网站 | 最新中文字幕在线播放 | 日本大尺度吃奶做爰久久久绯色 | 久久久久久中文字幕 | 日本bdsm视频 | 少妇紧身牛仔裤裤啪啪 | 羞羞免费视频 | 91社区视频| 国产一区二区三区黄片 | 国产aⅴ爽av久久久久成人 | 亚洲第一视频在线 | 亚洲国产日韩欧美在线观看 | 69影院在线观看 | 超碰干 | 天天综合天天添夜夜添狠狠添 | 玖玖在线精品 | 超碰97国产 | 337p粉嫩大胆噜噜噜亚瑟影院 | 国产精品无码自拍 | 精品一区二区三区日韩 | 欧美 唯美 清纯 偷拍 | 中文字幕亚洲一区二区三区 | 日本黄网在线观看 | 国产激情视频在线播放 | 免费人成在线观看网站 | 青青视频免费看 | 99爱爱视频| 国产成人无码久久久精品天美传媒 | 操女人免费视频 | 欧美日韩精品区别 | 丁香花激情网 | 噜噜噜亚洲色成人网站 | 91黄色影视 | 麻豆午夜视频 | 人人搞人人 | 国产精品美女毛片真酒店 | 爱情岛亚洲论坛入口福利 | 免费av中文字幕 | 欧美日韩精品一区二区在线观看 | 老司机深夜免费福利 | 亚洲精品国产精品国自产观看浪潮 | 欧美日韩一区二区在线观看 | 国产不卡视频在线播放 | 国产原创91| 日韩精品一区二区三区av | 亚洲精品一区二区三区中文字幕 | 黄色片www | 免费毛片在线播放 | 依人在线 | 黄色一级一片免费播放 | 欧美三级欧美一级 | 国内精品视频在线 | 国产成人久久777777 | 新婚夫妇白天啪啪自拍 | 亚洲自拍偷拍一区二区 | 老司机成人免费视频 | 日韩男女视频 | 美女色诱男人激情视频 | 18黄暴禁片在线观看 | 熟女俱乐部五十路六十路av | 中文字幕乱视频 | 国产小视频一区 | 一卡二卡在线 | 91久久精品一区二区别 | 精品乱子伦一区二区三区 | 根深蒂固在线观看 | 国产亚洲精品久久久久久777 | 久久久噜噜噜久久久 | jizz中文字幕 | 国产精品一区二区黑人巨大 | 欧美午夜网 | 拍国产真实乱人偷精品 | 91成人免费在线视频 | 深夜福利网址 | 国产精品99久久久久久久久久久久 | 成人av网站在线观看 | 国产精品久久久久久影视 | 国产精品欧美在线 | 少妇被躁爽到高潮无码人狍大战 | 老太脱裤让老头玩ⅹxxxx | 热久久精品 | 欧洲激情网 | 四虎精品视频 | 久久久久免费看 | 少妇被躁爽到高潮无码人狍大战 | 久久国产柳州莫菁门 | 日本免费一区二区在线 | 欧美xxxxx精品 | 国产精品国产成人国产三级 | 丁香啪啪综合成人亚洲 | 三上悠亚亚洲一区 | 九九一级片 |