日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

簡介

本文的描述了linux網絡棧中的一組補充技術,用于增加多處理器系統(tǒng)的并行性和提高性能。

描述的結束為:

  • RSS: Receive Side Scaling
  • RPS: Receive Packet Steering
  • RFS: Receive Flow Steering
  • Accelerated Receive Flow Steering
  • XPS: Transmit Packet Steering

RSS: Receive Side Scaling

現(xiàn)代NICs支持多個接收和傳輸描述符隊列(多隊列)。在接收報文時,NIC可以通過將不同的報文發(fā)送到不同的隊列的方式來分配多個CPU處理。NIC通過過濾器來分發(fā)報文,過濾器會將報文分配給某條邏輯流。每條流中的報文都被導向不同的接收隊列,然后由不同CPU處理。這個機制稱為“Receive-side Scaling” (RSS)。RSS和其他擴展技術的目的是提升性能。多隊列分發(fā)技術也可以按照優(yōu)先級處理流量,但這不是該技術關注的內容。

RSS中的過濾器通常是一個針對網絡和/或傳輸層首部的哈希函數(shù),如對IP地址的4元組和報文的TCP端口進行哈希。最常見的RSS的硬件實現(xiàn)是使用一個128個表項的間接表,每個表項存儲一個隊列元素。根據(jù)由報文計算出的哈希值的低7位來決定報文的接收隊列(通常是Toeplitz哈希),使用該值作為間接表的索引,然后讀取相應的值。

一些先進的NICs允許根據(jù)編程的過濾器將報文導入隊列。例如,使用TCP 80端口的web服務器的報文可以直接導入其歸屬的接收隊列。可以使用ethtool配置這種n元組過濾器( –config-ntuple )。

RSS配置

對于支持多隊列的NIC,驅動通常會提供一個內核模塊參數(shù)來配置硬件隊列的數(shù)目。例如在bnx2x驅動中,該參數(shù)稱為 num_queues 。一個典型的RSS配置應該給每個CPU分配一個接收隊列(如果驅動支持足夠多隊列的話),或至少給每個內存域分配一個接收隊列(內存域指共享一個特定內存級別(L1, L2, NUMA 節(jié)點等)的一組CPUs)。

RSS設備的間接表(通過掩碼哈希解析隊列)通常是在驅動初始化時進行編程。默認會將隊列平均分布到表中,但也可以在運行時通過ethtool命令進行檢索和修改( –show-rxfh-indir 和 –set-rxfh-indir )。通過修改間接表,可以給不同的隊列分配不同的相對權重。

RSS IRQ 配置

每個接收隊列都會關聯(lián)一個IRQ(中斷請求)。當給定的隊列接收到新的報文后,NIC會觸發(fā)中斷,通知CPU。PCIe設備的信令路徑使用消息信令中斷(MSI-X),可以將每個中斷路由到一個特定的CPU上。可以在 /proc/interrupts 中查看到IRQs的隊列映射。默認情況下,任何CPU都可以處理IRQ。由于報文接收中斷處理中包含一部分不可忽略的處理過程,因此在CPU之間分散處理中斷是有利的(防止新的中斷無法被即時處理)。如果要手動調節(jié)IRQ的親和性,參見 SMP IRQ affinity 。一些系統(tǒng)會運行 irqbalance ,這是一個守護進程,自動分配IRQ,可能會覆蓋手動設置的結果。

建議配置

當關注延遲或當接收中斷處理成為瓶頸后應該啟用RSS。將負載分擔給多個CPU可以有效減小隊列長度。對于低延遲網絡來說,最佳設置是分配與系統(tǒng)中CPU數(shù)量一樣多的隊列。最高效的高速率配置可能是接收隊列數(shù)量最少的配置,這樣不會由于CPU飽和而導致接收隊列溢出,由于在默認模式下啟用了中斷合并,中斷的總數(shù)會隨著每個其他隊列的增長而增加。

可以使用 mpstat 工具查看單CPU的負載,但對于啟用了超線程(HT)的處理器,每個超線程都表示一個單獨的CPU。但對于中斷處理,HT在初始測試中沒有顯示任何好處,因此應該將隊列的數(shù)目限制為系統(tǒng)上的CPU core的數(shù)目。

RSS 是一個網卡特性,其使用的是硬件隊列。

為了確定一個接口支持RSS,可以在 /proc/interrupts 中查看一個接口是否對應了多個中斷請求隊列。如下NIC為 p1p1 接口創(chuàng)建了6個接收隊列(p1p1-0到p1p1-5)。

# egrep 'CPU|p1p1' /proc/interrupts
CPU0    CPU1    CPU2    CPU3    CPU4    CPU5
89:   40187       0       0       0       0       0   IR-PCI-MSI-edge   p1p1-0
90:       0     790       0       0       0       0   IR-PCI-MSI-edge   p1p1-1
91:       0       0     959       0       0       0   IR-PCI-MSI-edge   p1p1-2
92:       0       0       0    3310       0       0   IR-PCI-MSI-edge   p1p1-3
93:       0       0       0       0     622       0   IR-PCI-MSI-edge   p1p1-4
94:       0       0       0       0       0    2475   IR-PCI-MSI-edge   p1p1-5

可以在 /sys/class/net/<dev>/queues 目錄中看到一個接口上現(xiàn)有的隊列,如下面的eth0有兩組隊列:

# ll /sys/class/net/eth0/queues
total 0
drwxr-xr-x 3 root root 0 Aug 19 16:23 rx-0
drwxr-xr-x 3 root root 0 Aug 19 16:23 rx-1
drwxr-xr-x 3 root root 0 Aug 19 16:23 tx-0
drwxr-xr-x 3 root root 0 Aug 19 16:23 tx-1

也可以使用ethtool -l 查看。如下面的eth0最多支持2組隊列,當前啟用了2組(就是上述的兩組),可以使用 ethtool -L eth0 combined 10 修改當前啟用的隊列數(shù),需要注意的的是,目前很多環(huán)境都是云化的虛擬環(huán)境,大部分ethtool操作功能和權限都受到了限制。

# ethtool -l eth0
Channel parameters for eth0:
Pre-set maximums:
RX:             0
TX:             0
Other:          0
Combined:       2
Current hardware settings:
RX:             0
TX:             0
Other:          0
Combined:       2

如上所述,下圖的硬件過濾器就是個根據(jù)4元組或5元組等進行哈希的哈希函數(shù)。可以使用 ethtool -x <dev> 命令查看RSS使用的哈希函數(shù)(但大部分虛擬環(huán)境不支持該命令,可以在/proc/sys/net/core/netdev_rss_key中查看RSS使用的哈希key)。

擴展Linux網絡棧

 

RPS: Receive Packet Steering

Receive Packet Steering (RPS)是RSS的一個軟件邏輯實現(xiàn)。作為一個軟件實現(xiàn),需要在數(shù)據(jù)路徑的后端調用它。鑒于RSS會給流量選擇CPU隊列,因此會觸發(fā)CPU運行硬件中斷處理程序,RPS會在中斷處理程序之上選擇CPU來執(zhí)行協(xié)議處理。整個過程是通過將報文放到期望的CPU backlog隊列中,然后喚醒該CPU進行處理來實現(xiàn)的。RPS相比RSS有一些優(yōu)勢:

  1. 可以使用任何NIC
  2. 可以方便地添加軟件過濾器來哈希新的協(xié)議
  3. 不會增加硬件設備的中斷頻率(雖然它會引入內部處理中斷(IPIs))

在接收中斷處理程序的下半部分會調用RPS(當一個驅動使用 netif_rx() 或 netif_receive_skb() 發(fā)送一個報文到網絡棧時)。這些函數(shù)會調用 get_rps_cpu() 函數(shù), get_rps_cpu() 會選擇一個處理報文的隊列。

RPS的第一步是通過對一條流中的報文的地址或端口(2元組或4元組,具體取決于協(xié)議)進行哈希來確定目標CPU。哈希操作會涉及相關流中的所有報文。可以通過硬件或棧來支持對報文的哈希。支持報文哈希的硬件會在接收的報文描述符中傳入哈希值,通常與RSS使用的哈希相同(如Toeplitz 哈希)。哈希值會保存在skb->hash中,并且可以在棧的其他位置用作報文流的哈希值。

每個接收硬件隊列都有相關的CPU列表,RPS會將報文入隊列并進行處理。對于每個接收到的報文,會根據(jù)流哈希以列表大小為模來計算列表的索引。索引到的CPU就是處理報文的CPU,且報文會放到CPU backlog隊列的末尾。在下半部分的例程處理結束之后,會給有報文進入backlog隊列的CPU發(fā)送IPIs。IPI會喚醒遠端CPU對backlog的處理,后續(xù)隊列中的報文會在網絡棧中進行處理。

RPS配置

RPS需要在內核編譯時啟用CONFIG_RPS 選項(SMP上默認啟用,可以使用 cat /boot/config-$(uname -r)|grep CONFIG_RPS 命令查看)。但即使在編譯時指定了該功能,后續(xù)也需要通過明確配置才能啟用該功能。可以通過 sys 文件系統(tǒng)中的文件來配置RPS可以為接收隊列轉發(fā)流量的CPU列表。

/sys/class/net/<dev>/queues/rx-<n>/rps_cpus

該文件實現(xiàn)了CPU位圖。當上述值為0時(默認為0),不會啟用RPS,這種情況下,報文將在中斷的CPU上進行處理。 SMP IRQ affinity 解釋了如何將CPU分配給位圖。

建議配置

對于一個 單隊列 設備,典型的RPS配置會將 rps_cpus 設置為與中斷CPU相同的內存域中的CPUs。如果NUMA的本地性不是問題,則也可以設置為系統(tǒng)上的所有CPUs。在高中斷率的情況下,最好從位圖中排除該CPU(因為該CPU已經足夠繁忙)。

對于一個 多隊列 系統(tǒng),如果配置了RSS,則硬件接收隊列會映射到每個CPU上,此時RPS可能會冗余。但如果硬件隊列的數(shù)目少于CPU,那么,如果 rps_cpus 為每個隊列指定的CPU與中斷該隊列的CPU共享相同的內存域時,則RPS可能是有用的。

RPS使用 /sys/class/net/<dev>/queues/rx-<n>/rps_cpus 來設置某個接收隊列使用的CPU。如果要使用CPU 1~3,則位圖為0 0 0 0 0 1 1 1,即0x7,將7 寫入rps_cpus即可,后續(xù) rx-0 將會使用CPU 1~3來接收報文。

# echo 7 > /sys/class/net/eth0/queues/rx-0/rps_cpus

在驅動將報文封裝到sk_buff之后,將會經過 netif_rx_internal() 或 netif_receive_skb_internal() ,然后調用 get_rps_cpu() 將哈希值映射到rps_map中的某個表項,即CPU id。在獲取到CPU id之后, enqueue_to_backlog() 會將sk_buff 放到指定的CPU隊列中(后續(xù)處理)。為每個CPU分配的隊列是一個per-cpu變量, softnet_data 。

擴展Linux網絡棧

 

如果已經啟用了RSS,則可以不啟用RPS。但如果系統(tǒng)上CPU的數(shù)目大于隊列的數(shù)目時,可以啟用RPS,給隊列關聯(lián)更多的CPU,這樣一個隊列的報文就可以在多個CPU上處理。

RPS流限制

RPS擴展了內核跨CPU接收處理的能力,而不會引入重排。如果報文的速率不同,則將同一流上的所有報文發(fā)送到同一CPU會導致CPU負載失衡。在極端情況下,單條流會主導流量。特別是在存在很多并行連接的通用服務器上,這類行為可能表現(xiàn)為配置錯誤或欺騙源拒絕服務攻擊。

流限制是RPS的一個可選特性,在CPU競爭期間,通過提前一點丟棄大流量的報文來為小流量騰出處理的機會。 只有當RPS或RFS目標CPU達到飽和時 ,才會激活此功能。一旦一個CPU的輸入報文隊列超過最大隊列長度(即, net.core.netdev_max_backlog )的一半,內核會從最近的256個報文開始按流計數(shù),如果接收到一個新的報文,且此時這條流的報文數(shù)超過了設置的比率(默認為一半,即超過了256/2個),則會丟棄新報文。其他流的報文只有在輸入報文隊列達到 netdev_max_backlog 時才會丟棄報文。如果報文隊列長度低于閾值,則不會丟棄報文,因此流量限制不會完全切斷連接:即使是大流量也可以保持連接。

如果因為 CPU backlog 不夠或者 flow limit 不夠,被丟棄的報文會將丟包信息計入 /proc/net/softnet_stat

接口

流控制功能默認會編譯到內核中(CONFIG_NET_FLOW_LIMIT),但不會啟用。它是為每個CPU獨立實現(xiàn)的(以避免鎖和緩存競爭),并通過在 sysctl net.core.flow_limit_cpu_bitmap 中設置相關位來切換CPU,它的CPU位圖接口與 rps_cpus 相同。

/proc/sys/net/core/flow_limit_cpu_bitmap

通過將每個報文散列到一個哈希表bucket中,并增加每個bucket計數(shù)器來計算每條流的速率。哈希函數(shù)與RPS選擇CPU時使用的相同,但由于bucket的數(shù)目要遠大于CPU的數(shù)目,因此流控制可更精細地識別大流量,并減少誤報。默認的表大小為4096個bucket,可以通過sysctl工具修改:

net.core.flow_limit_table_len

只有在分配新表時才會查詢該值。修改該值不會更新現(xiàn)有的表。

建議配置

流控制在系統(tǒng)上有很多并行流時有用,如果單個連接占用了CPU的50%,則表明存在問題。這種環(huán)境下,可以為所有的CPU啟用流控制特性,來處理網絡rx中斷( /proc/irq/N/smp_affinity 可以設置中斷親和性)。

該特性依賴于輸入報文隊列長度超過流限制閾值(50%)+流歷史長度(256)。在實驗中將 net.core.netdev_max_backlog 設置為1000或10000效果很好。

RPS/RFS主要是針對單隊列網卡多CPU環(huán)境。而 /proc/irq/{IRQ}/smp_affinity 和 /proc/irq/{IRQ}/smp_affinity_list 指定了哪些CPU能夠關聯(lián)到一個給定的IRQ源。RPS只是單純把數(shù)據(jù)包均衡到不同的cpu,這個時候如果應用程序所在的cpu和軟中斷處理的cpu不是同一個,此時對cpu cache的影響會很大。目前大多數(shù)SMP系統(tǒng)會使用smp_affinity功能,默認不啟用RPS。

RFS: Receive Flow Steering

雖然基于哈希的RPS可以很好地分配處理報文時的負載,但沒有考慮到應用所在的位置。Receive Flow Steering (RFS)擴展了這一點。RFS的目的是通過將報文的處理引導到正在消耗報文的應用程序線程所在的CPU上來提高數(shù)據(jù)緩存命中率。RFS依賴與RPS相同的機制來將入隊列的報文導向另外一個CPU的backlog隊列,并喚醒該CPU。

在RFS中,報文不會根據(jù)哈希結果進行轉發(fā),哈希結果會作為流查詢表的索引。該表會將流映射到正在處理這些流的CPU上。流哈希(見RPS)用于計算該表的索引。記錄在表項中的CPU就是上次處理該條流的CPUs。如果一個表項中不包含有效的CPU,則映射到該表項的報文將會完全使用RPS。多個表項可能映射到相同的CPU上(存在很多條流,但僅有很少的CPU,且一個應用可能會使用很多流哈希來處理流)。

rps_sock_flow_table 是一個 全局 的流表,包含流期望的CPUs:處理當前在用戶空間中使用的流的CPU。每個表的值都對應一個CPU索引,并在執(zhí)行 recvmsg 和 sendmsg (準確地講是 inet_recvmsg() , inet_sendmsg() , inet_sendpage() 和 tcp_splice_read() )時更新。

當調度器將一個線程轉移到一個新的CPU,但它在舊CPU上有未處理的接收報文時,收到的報文可能會亂序。為了防止發(fā)生這種情況,RFS使用一個秒流表來跟蹤每個流中未處理的報文: rps_dev_flow_table 是針對每個設備的每個硬件接收隊列的表。每個表中的值都保存了一個CPU索引和一個計數(shù)器。CPU索引表示入隊列(cpu的backlog隊列)流報文的當前CPU,后續(xù)由內核處理。理想情況下,內核和用戶空間的處理會發(fā)生在相同的CPU上,此時兩個表( rps_sock_flow_table 和 rps_dev_flow_table )中的CPU索引是相同的。但如果調度器最近轉移了用戶線程,而報文的入隊列和處理仍舊發(fā)生在老的CPU上,此時就會發(fā)生CPU不一致的情況。

當CPU處理的流有新報文入隊列時, rps_dev_flow_table 中的計數(shù)器會記錄當前CPU的backlog的長度。每個backlog隊列都有一個頭計數(shù)器,在報文出隊列時增加。尾計數(shù)器的計算方式為:頭計數(shù)器+隊列長度。即 rps_dev_flow[i] 中的計數(shù)器記錄了流i中的最后一個元素,該元素入隊列到為流i分配的CPU中(當然,表項i實際上是通過哈希選擇的,多條流可能會哈希到同一表項i)。

現(xiàn)在,避免出現(xiàn)亂序數(shù)據(jù)包的技巧是:當選擇處理報文的CPU時(通過 get_rps_cpu() ),會比較接收到數(shù)據(jù)包的隊列的 rps_sock_flow 表和 rps_dev_flow 表。如果流的 rps_sock_flow 表中期望的CPU與 rps_dev_flow 表中記錄的當前CPU匹配的話,報文會進入該CPU的backlog隊列。如果不同,當下面任一條成立時,會更新CPU,使其與期望的CPU匹配:

rps_dev_flow[i]

在上述檢查之后,報文會發(fā)送(可能會更新CPU)到當前CPU。上述規(guī)則用于保證只有當老CPU上不存在未處理的報文時才會將一個流轉移到一個新的CPU上(因為未處理的報文可能晚于將要在新CPU上處理的報文)。

RFS 配置

只有啟用了內核參數(shù)CONFIG_RPS (SMP默認會啟用)之后才能使用RFS。該功能只有在明確配置之后才能使用。可以通過如下參數(shù)設置全局流表 rps_sock_flow_table 的表項數(shù):

/proc/sys/net/core/rps_sock_flow_entries

每個隊列的 rps_dev_flow_table 流表中的表項數(shù)可以通過如下參數(shù)設置:

/sys/class/net/<dev>/queues/rx-<n>/rps_flow_cnt

建議配置

上述配置都需要在為接收隊列啟用RFS前完成配置。兩者的值會四舍五入到最接近的2的冪。建議的流數(shù)應該取決于任意時間活動的連接數(shù),這可能大大少于打開的連接數(shù)。我們發(fā)現(xiàn) rps_sock_flow_entries 的值32768在中等負載的服務器上可以很好地工作。

對于一個單隊列設備,單隊列的 rps_flow_cnt 的值通常設置為與 rps_sock_flow_entries 相同的值。對于多隊列設備,每個隊列的 rps_flow_cnt 的值可以配置為與 rps_sock_flow_entries/N ,N表示隊列的數(shù)目。例如,如果 rps_sock_flow_entries 為32768,且配置了16個接收隊列,每個隊列的 rps_flow_cnt 為2048。

rps_sock_flow_table 的結構如下:

struct rps_sock_flow_table {
 u32 mask;
 u32 ents[0];
};

mask 用于將哈希值映射到表的索引。由于表大小會四舍五入為2的冪,因此 mask 設為 table_size - 1 ,并且很容易通過 hash & scok_table->mask 索引到一個 sk_buff 。

表項通過 rps_cpu_mask 分為流id和CPU id。低位為CPU id,高位為流id。當應用在socket上進行操作 (inet_recvmsg(), inet_sendmsg(), inet_sendpage(), tcp_splice_read())時,會調用sock_rps_record_flow() 更新 rps_sock_flow_table 表。

當接收到一個報文時,會調用 get_rps_cpu() 來決定報文發(fā)到哪個CPU隊列,下面是其計算方式:

ident = sock_flow_table->ents[hash & sock_flow_table->mask];
if ((ident ^ hash) & ~rps_cpu_mask)
  goto try_rps;
next_cpu = ident & rps_cpu_mask;

get_rps_cpu() 使用流表的 mask 字段來獲取表項的索引,然后檢查匹配到的表項是否存在高比特位,如果存在,則使用表項中的CPU,并將其分配給該報文。否則使用RPS映射。

RFS使用pre-queue的 rps_dev_flow_table 來跟蹤未處理的報文,解決在CPU切換之后,應用可能接收到亂序報文的問題。 rps_dev_flow_table 的結構如下:

struct rps_dev_flow {
 u16 cpu;
 u16 filter; /* For aRFS */
 unsigned int last_qtail;
};

struct rps_dev_flow_table {
 unsigned int mask;
 struct rcu_head rcu;
 struct rps_dev_flow flows[0];
};

與sock流表一樣, rps_dev_flow_table 也使用 table_size-1 作為掩碼,而表大小也必須四舍五入為2的冪。當一個報文入隊列后, last_qtail 更新 為CPU隊列的末尾。如果應用遷移到一個新的CPU,則sock流表會反應這種變化,且 get_rps_cpu() 會為流選擇新的CPU。在設置新CPU之前, get_rps_cpu() 會檢查當前隊列的首部是否 經過 了last_qtail,如果是,則表示隊列中沒有未處理的報文,可以安全地切換CPU,否則 get_rps_cpu() 會使用 rps_dev_flow->cpu 中記錄的老CPU。

擴展Linux網絡棧

 

上圖展示了RFS是如何工作的。內核獲取一個藍色的報文,屬于藍色的流。 per-queue流表 ( rps_dev_flow_table )檢測到藍色的報文屬于CPU2(老的CPU),而此時socket將sock流表更新為使用CPU1,即新的CPU。 get_rps_cpu() 會對兩個表進行檢查,發(fā)現(xiàn)CPU發(fā)生了遷移,因此會更新 per-queue流表(假設此時在CPU2上沒有未處理的報文) ,并將CPU1分配給藍色的報文。

加速(Accelerated )RFS

加速RFS 對RFS來說,就像RSS對RPS:它是一個硬件加速負載均衡機制,基于消耗流報文的應用所運行的位置來使用軟狀態(tài)進行導流。加速RFS的性能要比RFS好,因為報文會直接發(fā)送到消耗該報文的線程所在的CPU上。目標CPU可能是應用運行的CPU,或在緩存結構中接近應用線程所在的CPU的CPU。

為了啟用加速RFS,網絡棧會帶調用 ndo_rx_flow_steer 驅動函數(shù)來與期望(匹配特定流)的硬件隊列進行交互。網絡棧會在 rps_dev_flow_table 中的流表項更新之后調用該函數(shù)。驅動會使用一個設備特定的方法來編程NIC,使其引導報文。

流的硬件隊列是從 rps_dev_flow_table 中記錄的CPU派生的。網絡棧會查詢CPU到硬件隊列的映射,該映射由NIC驅動程序維護,它是自動生成( /proc/interrupts 中展示)的IRQ親和表的反向映射。驅動可以使用內核庫 cpu_rmap (“CPU affinity reverse map”)來生成映射。對于每個CPU,映射中相應的隊列設置為最接近緩存位置的CPU的隊列。

加速RFS 配置

只有在內核編譯時啟用了CONFIG_RFS_ACCEL且NIC設備和驅動同時支持的情況下才能使用加速RFS功能。同時它還要求通過ethtool啟用ntuple過濾功能。驅動程序會為每個接收隊列配置的IRQ親和性自動推導CPU到隊列的映射,不需要額外的配置。

建議配置

如果希望使用RFS且NIC支持硬件加速,就可以啟用該技術。

為了啟用aRFS,需要一張帶有可編程ntupter過濾器的網卡,和驅動程序的支持。可以使用如下方式啟用ntuple過濾器:

# ethtool -K eth0 ntuple on

對于支持aRFS的驅動,需要實現(xiàn) ndo_rx_flow_steer 來幫助 set_rps_cpu() 配置硬件過濾器。當 get_rps_cpu() 決定為一條流分配CPU時,它會調用 set_rps_cpu() 。 set_rps_cpu() 首先會檢查網卡是否支持ntuple過濾器,如果支持,它會請求 rx_cpu_rmap 來為流找一個合適的RX隊列。 rx_cpu_rmap 是一個由驅動維護的 特殊的映射 ,該映射用來為CPU查找一個合適的RX隊列,找到的隊列可是與給定CPU直接關聯(lián)的隊列,也可能是臨近的緩存位置上的隊列。在獲取到RX隊列索后, set_rps_cpu() 會調用 ndo_rx_flow_steer() 來通知驅動為給定的流創(chuàng)建一個新的過濾器。 ndo_rx_flow_steer() 會返回過濾器id,過濾器id會被保存到per-queue流表中。

除了實現(xiàn) ndo_rx_flow_steer() ,驅動還需要周期性地調用 rps_may_expire_flow() 檢查過濾器是否有效,并移除過期的過濾器。

擴展Linux網絡棧

 

XPS: Transmit Packet Steering

Transmit Packet Steering是一種在多隊列設備上傳輸報文時,為報文智能選擇傳輸隊列的機制。可以通過記錄兩種映射來實現(xiàn),即將CPU映射到硬件隊列或將接收隊列映射到傳輸隊列。

  1. XPS使用CPU映射該映射的目的是隊列專門分配給 CPU 的一個子集,在此隊列上的CPU會完成這些隊列的報文傳輸。這種方式提供了兩種好處:首先,由于競爭同一個隊列的cpu更少,因此大大降低了設備隊列的鎖競爭(當每個CPU完成自己的傳輸隊列時會釋放鎖);其次,降低了傳輸競爭導致的緩存miss率,特別是對那些保存了sk_buff結構的數(shù)據(jù)緩存行。
  2. XPS使用接收隊列映射該映射用于基于管理員設置的接收隊列映射選擇傳輸隊列。一組接收隊列可以映射到一組傳輸隊列(多對多,但通常會使用1:1映射)。這將允許在相同的隊列上下文(如CPU和緩存等)中對報文進行傳輸和接收。這種方式可以用于繁忙的輪詢多線程工作負載,在這些工作負載中,很難將特定的CPU與特定的應用程序線程關聯(lián)起來。應用線程不會固定運行在某些CPU上,且每個線程會基于一個單獨的隊列接收報文。socket會緩存接收隊列的數(shù)目。在這種模型下,將傳輸隊列與相關的接收隊列關聯(lián)起來,可以有效降低CPU開銷。此時傳輸工作會鎖定到給定應用執(zhí)行輪詢的上下文中,避免觸發(fā)其他CPU造成的開銷。當應用程序在繁忙的輪詢期間清理報文時,可能會在與應用相同的線程上下文中完成傳輸,從而減少延遲。

可以通過設置一個CPUs/接收隊列位圖來為每個傳輸隊列配置XPS。每個網絡設備會計算并維護從CPUs到傳輸隊列或從接收隊列到傳輸隊列的反向映射。當在一條流中傳輸首個報文時,會調用 get_xps_queue() 選擇一個隊列。該函數(shù)會為每個socket連接使用的接收隊列的ID來匹配"接收隊列到傳輸隊列"的查詢表。另外,該函數(shù)也可以使用運行的CPU ID作為key來匹配"CPU到隊列"的查詢表。如果這個ID匹配到一個隊列,則使用該隊列傳輸報文。如果匹配到多個隊列,則通過流哈希計算出的索引來選擇一個隊列。當基于接收隊列映射選擇傳輸隊列時,傳輸設備不會針對接收設備進行驗證,因為這需要在數(shù)據(jù)路徑中進行代價高昂的查找操作。

為特定傳輸流選擇的隊列會保存在對應的流(如TCP)socket結構體中。該傳輸隊列會用于這條流上的后續(xù)報文的傳輸,方式發(fā)送亂序(ooo)報文。這種方式還分攤了流中所有報文調用 get_xps_queues() 的開銷。為了防止亂序報文,只有設置了流報文的skb->ooo_okay字段,才能變更這條流使用的隊列。這個標志位標識這條流中沒有未處理的報文,這樣就可以切換傳輸隊列,而不用擔心生成亂序報文的風險。傳輸層會負責正確處理亂序報文。如TCP,當確認一個連接上的所有數(shù)據(jù)后就會設置該標志。

XPS配置

只有在內核啟用了CONFIG_XPS 符號時才能使用XPS功能。如果內核編譯了該功能,由 驅動 決定是否以及如何在設備初始化時配置XPS。使用sfsfs來檢查和配置CPUs/接收隊列到傳輸隊列的映射。

對于基于CPUs的映射:

xps_cpus的意義與rx- /rps_cpus類似,確定隊列使用的CPU。

/sys/class/net/<dev>/queues/tx-<n>/xps_cpus

對于基于接收隊列的映射:

/sys/class/net/<dev>/queues/tx-<n>/xps_rxqs

建議配置

對于一個只有一條傳輸隊列的網絡設備,由于這種情況下無法選擇傳輸對,此時XPS是不起作用的。在多隊列系統(tǒng)中,建議配置XPS,這樣每個CPU會映射到一個傳輸隊列。如果系統(tǒng)中傳輸隊列的數(shù)目等于CPUs的數(shù)目,則每個隊列仍然會映射到一個CPU,此時不會產生多隊列競爭CPU的情況。如果隊列的數(shù)目少于CPUs的數(shù)目,那么,共享給特定隊列的最佳CPU可能是與處理該隊列的傳輸完成(傳輸中斷)的CPU共享高速緩存的CPU。

對于基于接收隊列選擇的傳輸隊列,XPS需要明確配置接收隊列到傳輸隊列的映射關系。如果用戶配置的接受隊列映射沒有生效,則會使用基于CPU映射來選擇傳輸隊列。

單傳輸隊列速率限制

這是由硬件實現(xiàn)的速率限制機制,當前支持設置最大速率熟悉,使用如下值設置一個Mbps值:

/sys/class/net/<dev>/queues/tx-<n>/tx_maxrate

0值表示不啟用,默認為0.

更多信息

RPS 和RFS是內核2.6.35引入的,XPS是2.6.38引入的。

加速RFS是2.6.35引入的。

參考:

  • Queues, RSS, interrupts and cores
  • Linux Network Scaling: Receiving Packets
  • Linux 網絡協(xié)議棧收消息過程-Per CPU Backlog

分享到:
標簽:網絡 Linux
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定