天天看點

使用 netmap 提升 ixgbe 性能

Linux 核心網絡協定棧的性能瓶頸導緻在處理大量資料包時效果不是很好,考慮使用 netmap 結合網卡來收包。

一、使用方法

# cd LINUX

# ./configure --drivers=ixgbe --kernel-sources=/tmp/linux-2.6.32-431.el6

我的作業系統對應的核心源碼在 /tmp 下,将 linux-2.6.32-431.el6 換成你系統核心的源碼位置。

# make

這裡 netmap 會對你的 ixgbe 打 patch,ixgbe 可以用源碼中的,也可以去 intel 的網站上單獨下載下傳其他版本的 ixgbe。

如果打 patch 時沖突了,需要手動解決沖突。

編譯成功後會在 LINUX 目錄下生成 netmap.ko 子產品,以及在 ixgbe 下生成 ixgbe.ko 子產品。

二、加載子產品及運作程式

# rmmod ixgbe

# insmod ./netmap.ko

# insmod ./ixgbe/ixgbe.ko

注意事項:

1、使用 netmap 最好是 root 權限,如果不是 root,運作時會報錯 Open /dev/netmap failed: Permission denied

切換成 root 使用者,或者更改 /dev/netmap 的屬主,使你的使用者可以操作它。

2、設定網卡為混合模式

# ifconfig ethX promisc

3、最好設定網卡中斷的親和性

接下來運作你的程式,或者 netmap 自帶的測試程式看看效果吧。

三、實驗環境

作業系統:RHEL 6.5 x86_64

CPU資訊:Intel(R) Xeon(R) CPU E3-1230 v3 @ 3.30GHz  8核

核心版本:Linux 2.6.32-431

網卡資訊:Intel 82599ES 10-Gigabit

驅動版本:ixgbe - 3.14.5

我用寫的程式測試收包,範圍在 8W ~ 10W pps,這也太低了吧,公司的網卡驅動收包是在 80W pps 左右。當我在上司面前示範網絡驅動性能調優效果的時候,知道有多打臉麼。。。

好吧,那問題究竟出在哪裡,是不是我的用法有問題?

四、問題排查

對比了 netmap 中的一些 demo 程式,确認我的用法沒有問題。這什麼情況?

先 gdb 跟一下,看看各參數傳遞是否正确。

gdb 跟蹤果然發現一些端倪,netmap 的實際 TX 是 8,而 RX 是 1。不應該啊,趕快在系統上驗證下

# cat /proc/interrupts | grep eth1

43: 30273311 139523574 259845624 92355654 43090828 78958804 89480226 49414129 IR-PCI-MSI-edge eth1-TxRx-0

44: 158832 328092 153524 254977 528675 3390308 1294062 305923 IR-PCI-MSI-edge eth1-TxRx-1

45: 1169409 1825198 206061 2535093 650780 144343 684348 191703 IR-PCI-MSI-edge eth1-TxRx-2

46: 114886 110540 3464628 360298 1709290 2050637 412207 47765 IR-PCI-MSI-edge eth1-TxRx-3

47: 87148 883696 913525 2525735 636851 19266 479904 281840 IR-PCI-MSI-edge eth1-TxRx-4

48: 167973 338479 886292 1108967 2178833 3781318 872638 122529 IR-PCI-MSI-edge eth1-TxRx-5

49: 197241 2167612 656826 89847 1687339 221567 942726 75923 IR-PCI-MSI-edge eth1-TxRx-6

50: 301446 176112 3465756 768635 344587 952908 1438564 107423 IR-PCI-MSI-edge eth1-TxRx-7

我在 ixgbe 驅動代碼中也列印日志,的确是 8 個 TX 和 RX,那麼問題肯定是 netmap 将 8 個 RX 改成 1 個了。它為什麼要這麼做?

檢視 netmap 源碼,發現在 netmap_ioctl 中注冊網卡成 netmap 模式的時候,有一個 netmap_update_config 函數。

netmap_ioctl()

  |-- netmap_do_regif()

        |-- netmap_update_config()

              |-- na->nm_config()  // 函數指針,指向 netmap_linux_config 函數

netmap_linux_config()

  |-- nm_os_generic_find_num_desc()    // 設定槽個數

  |-- nm_os_generic_find_num_queues()  // 設定隊列個數

槽個數是沒有問題的,我們來看看設定隊列的這個函數

void nm_os_generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq)
{
#ifdef NETMAP_LINUX_HAVE_SET_CHANNELS
	struct ethtool_channels ch;
	memset(&ch, 0, sizeof(ch));
	if (ifp->ethtool_ops && ifp->ethtool_ops->get_channels) {
		ifp->ethtool_ops->get_channels(ifp, &ch);
		*txq = ch.tx_count ? ch.tx_count : ch.combined_count;
		*rxq = ch.rx_count ? ch.rx_count : ch.combined_count;
	} else
#endif /* HAVE_SET_CHANNELS */
	{
		*txq = ifp->real_num_tx_queues;
#if defined(NETMAP_LINUX_HAVE_REAL_NUM_RX_QUEUES)
		*rxq = ifp->real_num_rx_queues;
#else
		*rxq = 1;
#endif /* HAVE_REAL_NUM_RX_QUEUES */
	}
}
           

咦,是不是不滿足 NETMAP_LINUX_HAVE_SET_CHANNELS 和 NETMAP_LINUX_HAVE_REAL_NUM_RX_QUEUES 這兩個宏啊,是以使用了預設的 1。

檢視源碼,發現這個驅動的版本還真不支援這個宏,試了幾個更高的 ixgbe 版本,裡面有宏定義,然而編譯的時候,有幾個符号未定義,一看要 RHEL 6.6 以上才行。

那好吧,我能不能強制的将 RX 隊列設定為 8 個呢,好,說做就做,開開心心編譯完,插入子產品,運作程式,然後系統 hang 住了。。。。簡單粗暴看來是不行了,乖乖地改回來吧。

好吧,我們整理下,現在網卡實際有 8 TX 和 RX,而 netmap 實際情況是使用了 1 RX,相當于 隻收取了 1/8 的資料,自然資料量很小了。

目前有兩個解決方案。

方案一:能否将流量指定到單一接收隊列上,這樣即使有一個 RX,我也可以接收了

方案二:讓 netmap 可以使用 8 RX 收包。

針對方案一,使用 ethtool 指定固定隊列收包

# ethtool -K eth1 ntuple on

# ethtool -U eth1 flow-type ip4 action 0

這裡 ethtool 不支援設定為 ether,最後測試的實際收包效果是 60W ~ 70W pps,還是沒有公司的高。

五、TODO

針對方案二,更換高版本 ixgbe 驅動,使用 net_device->ethtool_ops->get_channels 擷取隊列後指派。