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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

linux 3.10 gro的理解和改进

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

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

所以將最近看的gro內容總結一下,作為記錄。

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

先看關鍵的數據結構,然后分析流程:

為了在skb中記錄相關的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字節的cb字段,被用完了。

所有的packet 級別的gro的類型,放在一個公共鏈表頭 offload_base 變量中管理,我測試的系統中的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回調,都存儲在inet_offloads 數組中,根據當前加載的模塊,本機器對應支持的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的調用查找過程如下:

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

在offload_base這個鏈表頭找到對應的type,然后獲取對應的callback.gro_receive 函數。

找到了對應的inet_gro_receive,就進入了packet層,那么根據iph->protocol,就在net_offload 數組中,找到對應協議類型的gro結構,比如找到的是tcpv4_offload。

那么針對tcp的gro,其i40e驅動的調用順序就是:

i40e_napi_poll--->|i40e_clean_tx_irq

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

對應的堆棧如下:

[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進行比較,看能否合并,當然合并的前提是同一個flow的,

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

那這個gro_list最大多長呢?

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

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

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

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

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

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

3.修改合并條件,比如對于tcp的ack來說,目前不帶數據的ack無法合并,因為才54個字節,而以太網發出的時候會填充,導致不滿足如下條件:

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

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

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

所以需要一個導出到/proc文件系統的間隔字段來控制。

5.對于低速發送碼率的服務器來說,可以關閉gro,對于lvs服務器來說,應該關閉gro。

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

總結

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

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