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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

linux 3.10 gro的理解和改进

發(fā)布時間:2023/12/25 综合教程 38 生活家
生活随笔 收集整理的這篇文章主要介紹了 linux 3.10 gro的理解和改进 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

gro,將同一個flow的一定時間范圍之內(nèi)的skb進(jìn)行合并,減少協(xié)議棧的消耗,用于收包性能提升。gro網(wǎng)上的資料很多,但是都很少談到gro的改進(jìn),剛好身邊有個同事也想改這塊的內(nèi)容,

所以將最近看的gro內(nèi)容總結(jié)一下,作為記錄。

gro的層次,很少有資料提到,可能是大牛們覺得太簡單,但我還是記錄一下,畢竟我基礎(chǔ)不好。

先看關(guān)鍵的數(shù)據(jù)結(jié)構(gòu),然后分析流程:

為了在skb中記錄相關(guān)的gro信息,使用了skb的cb字段。

crash>  napi_gro_cb
struct napi_gro_cb {
    void *frag0;
    unsigned int frag0_len;
    int data_offset;
    u16 flush;
    u16 flush_id;
    u16 count;
    u16 gro_remcsum_start;
    unsigned long age;
    u16 proto;
    u8 encap_mark : 1;
    u8 csum_valid : 1;
    u8 csum_cnt : 3;
    u8 is_ipv6 : 1;
    u8 free : 2;
    u8 same_flow : 1;
    u8 recursion_counter : 4;
    u8 is_atomic : 1;
    __wsum csum;
    struct sk_buff *last;
}
SIZE: 48

48字節(jié)的cb字段,被用完了。

所有的packet 級別的gro的類型,放在一個公共鏈表頭 offload_base 變量中管理,我測試的系統(tǒng)中的packet級別的gro類型有:

crash> list packet_offload.list  -H offload_base -s packet_offload
ffffffff81b41bc0
struct packet_offload {
  type = 8,
  priority = 0,
  callbacks = {
    gso_segment = 0xffffffff816155b0 <inet_gso_segment>,
    gro_receive = 0xffffffff816159a0 <inet_gro_receive>,
    gro_complete = 0xffffffff816148c0 <inet_gro_complete>
  },
  list = {
    next = 0xffffffff81b43b40 <ipv6_packet_offload+32>,
    prev = 0xffffffff81b3f0e0 <offload_base>
  }
}
ffffffff81b43b20
struct packet_offload {
  type = 56710,
  priority = 0,
  callbacks = {
    gso_segment = 0xffffffff8168c670 <ipv6_gso_segment>,
    gro_receive = 0xffffffff8168c300 <ipv6_gro_receive>,
    gro_complete = 0xffffffff8168c120 <ipv6_gro_complete>
  },
  list = {
    next = 0xffffffff81b3f7c0 <eth_packet_offload+32>,
    prev = 0xffffffff81b41be0 <ip_packet_offload+32>
  }
}
ffffffff81b3f7a0
struct packet_offload {
  type = 22629,
  priority = 10,
  callbacks = {
    gso_segment = 0x0,
    gro_receive = 0xffffffff815bbd60 <eth_gro_receive>,
    gro_complete = 0xffffffff815bbbe0 <eth_gro_complete>
  },
  list = {
    next = 0xffffffff81b3f0e0 <offload_base>,
    prev = 0xffffffff81b43b40 <ipv6_packet_offload+32>
  }
}

所有的inet層的gro回調(diào),都存儲在inet_offloads 數(shù)組中,根據(jù)當(dāng)前加載的模塊,本機(jī)器對應(yīng)支持的gro就有:

p inet_offloads
inet_offloads = $48 =
 {0x0, 0x0, 0x0, 0x0, 0xffffffff8176fd80 <ipip_offload>, 0x0, 0xffffffff8176f220 <tcpv4_offload>, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff8176f560 <udpv4_offload>, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff81777680 <sit_offload>, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffff81770be0 <gre_offload>, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
。。。。
 0x0, 0x0, 0x0}

gro的調(diào)用查找過程如下:

從dev層,根據(jù)到來的skb,可以根據(jù)skb->protocol 作為type的類型,比如type是.type = cpu_to_be16(ETH_P_IP),然后才會進(jìn)入ip_packet_offload 這個層次,

在offload_base這個鏈表頭找到對應(yīng)的type,然后獲取對應(yīng)的callback.gro_receive 函數(shù)。

找到了對應(yīng)的inet_gro_receive,就進(jìn)入了packet層,那么根據(jù)iph->protocol,就在net_offload 數(shù)組中,找到對應(yīng)協(xié)議類型的gro結(jié)構(gòu),比如找到的是tcpv4_offload。

那么針對tcp的gro,其i40e驅(qū)動的調(diào)用順序就是:

i40e_napi_poll--->|i40e_clean_tx_irq

--->|i40e_clean_rx_irq-->napi_gro_receive-->dev_gro_receive-->inet_gro_receive-->tcp4_gro_receive

對應(yīng)的堆棧如下:

[root@localhost caq]# stap -d i40e netif_rx.stp
System Call Monitoring Started (10 seconds)...
WARNING: DWARF expression stack underflow in CFI
 0xffffffff816041a0 : tcp4_gro_receive+0x0/0x1b0 [kernel]
 0xffffffff81615be9 : inet_gro_receive+0x249/0x290 [kernel]
 0xffffffff815951b0 : dev_gro_receive+0x2b0/0x3e0 [kernel]
 0xffffffff815955d8 : napi_gro_receive+0x38/0x130 [kernel]-------------gro處理開始
 0xffffffffc01f4bde : i40e_clean_rx_irq+0x3fe/0x990 [i40e]
 0xffffffffc01f5440 : i40e_napi_poll+0x2d0/0x710 [i40e]
 0xffffffff81594cf3 : net_rx_action+0x173/0x380 [kernel]
 0xffffffff8109404d : __do_softirq+0xfd/0x290 [kernel]
 0xffffffff816c8afc : call_softirq+0x1c/0x30 [kernel]
 0xffffffff8102d435 : do_softirq+0x65/0xa0 [kernel]
 0xffffffff81094495 : irq_exit+0x175/0x180 [kernel]
 0xffffffff816c9da6 : __irqentry_text_start+0x56/0xf0 [kernel]
 0xffffffff816bc362 : ret_from_intr+0x0/0x15 [kernel]

理清楚了大的流程,我們再來看目前的gro小的流程。在收到一個skb的時候,我們把它和napi_struct中的gro_list的skb進(jìn)行比較,看能否合并,當(dāng)然合并的前提是同一個flow的,

除此之外,除了滿足同一個flow,還有很多要求。

那這個gro_list最大多長呢?

/* Instead of increasing this, you should create a hash table. */
#define MAX_GRO_SKBS 8

才8個,這8個skb跟新進(jìn)來的skb是flow相同的概率其實真不高,比如在tcp4_gro_receive中,我想跟蹤它接著調(diào)用的 skb_gro_receive,無奈由于合并的幾率太低而無法跟到,

畢竟還有一個在gro_list中停留的時間限制,為一個jiffies。后來修改了jiffies并且修改了合并的條件才能抓到。

當(dāng)然,根據(jù)作者的注釋,與其將這8改大,不如改成一個hash表,不同的skb先哈希到一個flow鏈,然后在鏈中比較看能否合并,這樣對于gro流程需要改動為:

1.創(chuàng)建flow的hash表,讓skb中看到flow,然后在flow的沖突鏈中找對應(yīng)的gro_list,然后看能否合并。

2.percpu模式,不適用napi_struct來管理gro_list.

3.修改合并條件,比如對于tcp的ack來說,目前不帶數(shù)據(jù)的ack無法合并,因為才54個字節(jié),而以太網(wǎng)發(fā)出的時候會填充,導(dǎo)致不滿足如下條件:

flush = (u16)((ntohl(*(__be32 *)iph) ^ skb_gro_len(skb)) | (id & ~IP_DF));

但對于流媒體服務(wù)器來說,純ack占入向的比例很高,需要將條件改動,由于ack還涉及到快發(fā)流程的進(jìn)入和退出,所以ack合并還是有一些工作要做的。

4.修改間隔,目前限制死了是一個jiffies,比如服務(wù)器8M左右的發(fā)送碼率,收到的ack間隔可以釋放放大,不然合并幾率也比較低,當(dāng)然這個是以tcp的send_buf中的數(shù)據(jù)占用更多內(nèi)存為前提的。

所以需要一個導(dǎo)出到/proc文件系統(tǒng)的間隔字段來控制。

5.對于低速發(fā)送碼率的服務(wù)器來說,可以關(guān)閉gro,對于lvs服務(wù)器來說,應(yīng)該關(guān)閉gro。

水平有限,如果有錯誤,請幫忙提醒我。如果您覺得本文對您有幫助,可以點擊下面的 推薦 支持一下我。版權(quán)所有,需要轉(zhuǎn)發(fā)請帶上本文源地址,博客一直在更新,歡迎 關(guān)注 。

總結(jié)

以上是生活随笔為你收集整理的linux 3.10 gro的理解和改进的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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