サヌドパヌティのラむブラリなしで毎秒数千䞇パケットのLinuxパケットキャプチャ

私の蚘事では、Netmap、PF_RING、DPDKなどのラむブラリを䜿甚せずに、毎秒1,000䞇パケットを受信する方法を説明したす。 通垞のLinuxカヌネルバヌゞョン3.16ず、CおよびC ++のコヌドを䜿甚しおこれを行いたす。







最初に、pcapがどのように機胜するかに぀いおいく぀かの蚀葉を共有したいず思いたす-パケットをキャプチャするためのよく知られた方法 iftop、tcpdump、arpwatchなどの䞀般的なナヌティリティで䜿甚されたす。 さらに、プロセッサの負荷が非垞に高くなりたす。



したがっお、それらのむンタヌフェむスを開いお、通垞のアプロヌチ-bind / recvを䜿甚しお、そこからパッケヌゞを埅機しおいたす。 次に、カヌネルはネットワヌクカヌドからデヌタを受信し、カヌネルスペヌスに保存したす。その埌、ナヌザヌがナヌザヌスペヌスでデヌタを受信したいこずを怜出し、このデヌタを栌玍するバッファヌアドレスをrecvコマンドに匕数で枡したす。 カヌネルはデヌタを忠実にコピヌしたす2回目。 かなり耇雑になりたすが、それがすべおのpcapの問題ではありたせん。



さらに、recvはシステムコヌルであり、むンタヌフェむスに着信するすべおのパケットに察しお呌び出すこずを思い出しおください。通垞、システムコヌルは非垞に高速ですが、最新の10GEむンタヌフェむスの速床1秒あたり最倧1,460䞇回の呌び出しでも非垞に軜い呌び出しになりたす呌び出しの頻床だけのためにシステムのコストがかかりたす。



たた、サヌバヌには通垞2぀以䞊の論理コアがあるこずに泚意しおください。 そしお、デヌタはそれらのどれにでも飛ぶこずができたす たた、pcapを䜿甚しおデヌタを受信するアプリケヌションは、シングルコアを䜿甚したす。 ここでカヌネル偎のロックがオンになり、キャプチャプロセスが倧幅に遅くなりたす。珟圚、メモリのコピヌ/パケットの凊理だけでなく、他のカヌネルが占有しおいるロックの解攟を埅っおいたす。 私を信じお、ロックは倚くの堎合、サヌバヌ党䜓のプロセッサリ゜ヌスの最倧90を占めるこずがありたす。



問題の良いリスト だから、私たちはそれらすべおを英雄的に解決しようずしたす



したがっお、明確にするために、ミラヌポヌトで䜜業するこずを修正したす぀たり、ネットワヌクの倖郚から特定のサヌバヌのすべおのトラフィックのコピヌを取埗するこずを意味したす。 次に、トラフィックを受信したす-14.6 mpps / 7.6GEの速床で最小サむズのSYNフラッドパケット。



SourceForgeのネットワヌクixgbeドラむバヌ、4.1.1、Debian 8 Jessie。 モゞュヌル構成modprobe ixgbe RSS = 8.8これは重芁です。 8぀の論理コアを備えたi7 3820プロセッサヌを䜿甚しおいたす。 したがっお、8コヌド内を含むを䜿甚する堎合は垞に、䜿甚しおいるコアの数を䜿甚する必芁がありたす。



割り蟌みを既存のカヌネルに配垃する



宛先MACアドレスがネットワヌクカヌドのMACアドレスず䞀臎しないパケットがポヌトに到着するこずに泚意しおください。 そうしないず、LinuxスタックがTCP / IP操䜜を開始し、マシンがトラフィックで窒息したす。 この点は非垞に重芁です。他の人のトラフィックのキャプチャに぀いおのみ説明し、このマシン宛おのトラフィックの凊理に぀いおは説明しおいたせんただし、この方法は䜿いやすいです。



次に、すべおのトラフィックのリッスンを開始した堎合に受け入れるこずができるトラフィックの量を確認したしょう。



ネットワヌクカヌドで無差別モヌドをオンにしたす。

ifconfig eth6 promisc
      
      







その埌、htopに非垞に䞍快な画像が衚瀺されたす-コアの1぀の完党なオヌバヌロヌド



 1 [||||||||||||||||||||||||||||||||||||||||||||||||||| |||||||||||| 100.0]     
 2 [0.0]     
 3 [0.0]     
 4 [0.0]     
 5 [0.0]
 6 [0.0]
 7 [0.0]
 8 [0.0]




むンタヌフェむスの速床を決定するには、特別なpps.shスクリプトを䜿甚したす gist.github.com/pavel-odintsov/bc287860335e872db9a5



むンタヌフェむスの速床はかなり小さく、1秒あたり400䞇パケットです。

bash /root/pps.sh eth6

 TX eth60 pkts / s RX eth63882721 pkts / s
 TX eth60 pkts / s RX eth63745027 pkts / s




この問題を解決し、すべおの論理コア8぀ありたすに負荷を分散するには、次のスクリプトを実行する必芁がありたす。



すごい、速床はすぐに最倧12mppsになりたしたただし、これはキャプチャではありたせん。これは、ネットワヌクからこの速床でトラフィックを読み取るこずができるこずを瀺しおいたす。

  bash /root/pps.sh eth6
 TX eth60 pkts / s RX eth612528942 pkts / s
 TX eth60 pkts / s RX eth612491898 pkts / s
 TX eth60 pkts / s RX eth612554312 pkts / s




そしお、コアの負荷が安定したした

 1 [|||||  7.4]     
 2 [||||||||  9.7]     
 3 [||||||  8.9]    
 4 [||  2.8]     
 5 [|||  4.1]
 6 [|||  3.9]
 7 [|||  4.1]
 8 [|||||  7.8]




テキストで2぀のコヌドサンプルが䜿甚されるこずにすぐに泚目したす。

AF_PACKET、AF_PACKET + FANOUT gist.github.com/pavel-odintsov/c2154f7799325aed46ae

AF_PACKET RX_RING、AF_PACKET + RX_RING + FANOUT gist.github.com/pavel-odintsov/15b7435e484134650f20



これらは、最倧レベルの最適化を備えた完党なアプリケヌションです。 䞭間明らかに遅いバヌゞョンのコヌドは提䟛したせんが、すべおの最適化を管理するためのすべおのフラグが匷調衚瀺され、boolずしおコヌドで宣蚀されたす-自宅で簡単にパスを繰り返すこずができたす。



最適化なしでAF_PACKETキャプチャを実行する最初の詊み



そのため、AF_PACKETを䜿甚しおトラフィックをキャプチャするアプリケヌションを起動したす。

凊理222048 pps
凊理186315 pps




そしお倩井の負荷

 1 [||||||||||||||||||||||||||||||||||||||||||||||||||| |||||||||  86.1]     
 2 [|||||||||||||||||||||||||||||||||||||||||||||||||||| ||||||  84.1]     
 3 | | ||||  79.8]     
 4 [||||||||||||||||||||||||||||||||||||||||||||||||||| ||||||||||  88.3]     
 5 [||||||||||||||||||||||||||||||||||||||||||||||||||| |||||||  83.7]
 6 [||||||||||||||||||||||||||||||||||||||||||||||||||| ||||||||||  86.7]
 7 | | |||||||||||  89.8]
 8 [|||||||||||||||||||||||||||||||||||||||||||||||||||| ||||||||||||| 90.9]




カヌネルがロックでdrれた理由は、すべおのプロセッサヌ時間を消費したす。

サンプルむベント 'cpu-clock'の303K、むベントカりント玄53015222600
   59.57[カヌネル] [k] _raw_spin_lock
    9.13[カヌネル] [k] packet_rcv
    7.23[ixgbe] [k] ixgbe_clean_rx_irq
    3.35[カヌネル] [k] pvclock_clocksource_read
    2.76[カヌネル] [k] __netif_receive_skb_core
    2.00[カヌネル] [k] dev_gro_receive
    1.98[カヌネル] [k] consumer_skb
    1.94[カヌネル] [k] build_skb
    1.42[カヌネル] [k] kmem_cache_alloc
    1.39[カヌネル] [k] kmem_cache_free
    0.93[カヌネル] [k] inet_gro_receive
    0.89[カヌネル] [k] __netdev_alloc_frag
    0.79[カヌネル] [k] tcp_gro_receive




FANOUTでAF_PACKETキャプチャを最適化する



それではどうしたすか 少し考えるず:)耇数のプロセッサが1぀のリ゜ヌスを䜿甚しようずするずロックが発生したす。 私たちの堎合、これは、1぀の゜ケットがあり、1぀のアプリケヌションによっお凊理されるずいう事実によるものです。これにより、残りの8぀の論理プロセッサが垞に期埅される状態になりたす。



ここでは、優れた機胜が私たちの助けになりたす-FANOUT、そしおロシア語の堎合-分岐。 AF_PACKETの堎合、耇数を実行できたすもちろん、このケヌスで最も最適なのは、論理コアの数に等しいプロセスの数です。 さらに、これらの゜ケットを介しおデヌタを配垃するアルゎリズムを指定できたす。 PACKET_FANOUT_CPUモヌドを遞択したした。私の堎合、デヌタはネットワヌクカヌドキュヌ間で非垞に均等に分散されおおり、これはリ゜ヌス集䞭型のバランシングオプションずしおは最小だず思いたす保蚌はできたせんが、カヌネルコヌドを確認するこずをお勧めしたす。



サンプルコヌドでは、bool use_multiple_fanout_processes = true;を修正したす。



そしお再びアプリケヌションを起動したす。



奇跡 10倍の加速

凊理2250709 pps
凊理2234301 pps
凊理2266138 pps


もちろん、プロセッサはただ完党にロヌドされおいたす

 1 [||||||||||||||||||||||||||||||||||||||||||||||||||| ||||||||||||| 92.6]     
 2 [|||||||||||||||||||||||||||||||||||||||||||||||||||| ||||||||||||| 93.1]     
 3 [||||||||||||||||||||||||||||||||||||||||||||||||||| ||||||||||||| 93.2]     
 4 [||||||||||||||||||||||||||||||||||||||||||||||||||| ||||||||||||| 93.3]     
 5 [||||||||||||||||||||||||||||||||||||||||||||||||||| ||||||||||||| 93.1]
 6 [||||||||||||||||||||||||||||||||||||||||||||||||||| ||||||||||||| 93.7]
 7 [||||||||||||||||||||||||||||||||||||||||||||||||||| ||||||||||||| 93.7]
 8 [|||||||||||||||||||||||||||||||||||||||||||||||||||| ||||||||||||| 93.2]




しかし、perfのトップマップは完党に異なっお芋えたす-もうロックはありたせん

サンプル1Mのむベント「cpu-clock」、むベントカりント玄110166379815
   17.22[ixgbe] [k] ixgbe_clean_rx_irq      
    7.07[カヌネル] [k] pvclock_clocksource_read          
    6.04[カヌネル] [k] __netif_receive_skb_core    
    4.88[カヌネル] [k] build_skb     
    4.76[カヌネル] [k] dev_gro_receive    
    4.28[カヌネル] [k] kmem_cache_free 
    3.95[カヌネル] [k] kmem_cache_alloc 
    3.04[カヌネル] [k] packet_rcv 
    2.47[カヌネル] [k] __netdev_alloc_frag 
    2.39[カヌネル] [k] inet_gro_receive
    2.29[カヌネル] [k] copy_user_generic_string
    2.11[カヌネル] [k] tcp_gro_receive
    2.03[カヌネル] [k] _raw_spin_unlock_irqrestore




さらに、゜ケットAF_PACKETに぀いおはわかりたせんがに受信バッファヌSO_RCVBUFを蚭定する機胜がありたすが、テストスタンドで結果が埗られたせんでした。



RX_RINGリングバッファヌを䜿甚しおAF_PACKETキャプチャを最適化する



䜕をすべきか、それでもなぜ遅いのですか 答えはbuild_skb関数にありたす。これは、カヌネル内でメモリの2぀のコピヌがただ䜜成されおいるこずを意味したす



ここで、RX_RINGを䜿甚しおメモリの割り圓おを把握しおみたしょう。



そしお4 MPPSのトップが也杯

凊理3582498 pps
凊理3757254 pps
凊理3669876 pps
凊理3757254 pps
凊理3815506 pps
凊理3873758 pps




この速床の向䞊は、ネットワヌクカヌドバッファからのメモリのコピヌが1回のみ行われるようになったこずにより保蚌されたした。 たた、カヌネル空間からナヌザヌ空間に転送する堎合、繰り返しコピヌは実行されたせん。 これは、カヌネルに割り圓おられ、ナヌザヌ空間でスキップされる共有バッファヌによっお保蚌されたす。



動䜜するアプロヌチも倉化しおいたす-パケットが到着したずきにハングしおリッスンできなくなりたしたこれはオヌバヌヘッドです、今床はポヌリング呌び出しで、ブロック党䜓がいっぱいになったずきにシグナルを期埅できたす そしお、凊理を開始したす。



FANOUTによるRX_RINGを䜿甚したAF_PACKETキャプチャの最適化



それでも、ロックには問題がありたす それらを打ち負かすには 叀い方法は、FANOUTを有効にしお、各ハンドラスレッドにメモリブロックを割り圓おるこずです

サンプル778Kのむベント「cpu-clock」、むベントカりント玄87039903833
   74.26[カヌネル] [k] _raw_spin_lock
    4.55[ixgbe] [k] ixgbe_clean_rx_irq
    3.18[カヌネル] [k] tpacket_rcv
    2.50[カヌネル] [k] pvclock_clocksource_read
    1.78[カヌネル] [k] __netif_receive_skb_core
    1.55[カヌネル] [k] sock_def_readable
    1.20[カヌネル] [k] build_skb
    1.19[カヌネル] [k] dev_gro_receive
    0.95[カヌネル] [k] kmem_cache_free
    0.93[カヌネル] [k] kmem_cache_alloc
    0.60[カヌネル] [k] inet_gro_receive
    0.57[カヌネル] [k] kfree_skb
    0.52[カヌネル] [k] tcp_gro_receive
    0.52[カヌネル] [k] __netdev_alloc_frag




そこで、RX_RINGバヌゞョンのFANOUTモヌドを接続したす



ほら 蚘録!!! 9 MPPS !!!

凊理9611580 pps
凊理8912556 pps
凊理8941682 pps
凊理8854304 pps
凊理8912556 pps
凊理8941682 pps
凊理8883430 pps
凊理8825178 pps




パフォヌマンストップ

サンプル224Kのむベント「cpu-clock」、むベントカりント玄42501395417
   21.79[ixgbe] [k] ixgbe_clean_rx_irq
    9.96[カヌネル] [k] tpacket_rcv
    6.58[カヌネル] [k] pvclock_clocksource_read
    5.88[カヌネル] [k] __netif_receive_skb_core
    4.99[カヌネル] [k] memcpy
    4.91[カヌネル] [k] dev_gro_receive
    4.55[カヌネル] [k] build_skb
    3.10[カヌネル] [k] kmem_cache_alloc
    3.09[カヌネル] [k] kmem_cache_free
    2.63[カヌネル] [k] prb_fill_curr_block.isra.57




ちなみに、公平のために、カヌネル4.0.0ブランチを曎新しおも、それほど高速化されたせんでした。 速床は同じ制限内に維持されたした。 しかし、コアの負荷は倧幅に䜎䞋したした

 1 | |  55.1]     
 2 [||||||||||||||||||||||||||||||||||||||  52.5]     
 3 [|||||||||||||||||||||||||||||||||||||||||||||||||||  62.5]     
 4 [|||||||||||||||||||||||||||||||||||||||||||||||||||  62.5]     
 5 [|||||||||||||||||||||||||||||||||||||||||||||  57.7]
 6 [|||||||||||||||||||||||||||||||||||||  47.7]
 7 [|||||||||||||||||||||||||||||||||||||||||||||  55.9]
 8 [|||||||||||||||||||||||||||||||||||||||||||||||||  61.4]




結論ずしお、Linuxは、特殊なカヌネルモゞュヌルを構築できない環境でも、トラフィック分析のための単玔な玠晎らしいプラットフォヌムであるず付け加えたす。 ずおも幞せです。 カヌネルの次のバヌゞョンでは、1800メガヘルツプロセッサを䜿甚しお、1460侇/秒のパケットのフルワむダスピヌドで10GEを凊理できるこずが期埅されおいたす:)



掚奚資料

www.kernel.org/doc/Documentation/networking/packet_mmap.txt

man7.org/linux/man-pages/man7/packet.7.html



All Articles