Lagopus performance

26
Lagopusの性能の話 Apr 25, 2015 Masaru OKI @masaru0714

Transcript of Lagopus performance

Page 1: Lagopus performance

Lagopusの性能の話Apr 25, 2015

Masaru OKI @masaru0714

Page 2: Lagopus performance

● OpenFlow対応ソフトウェアスイッチです

● (もちろん)オープンソースです

○ http://lagopus.github.io● よく言われている特徴

○ x86 Linuxで動きます

○ DPDKを使っていて、内部の工夫もあり速いです

○ マルチコア・マルチスレッドで動作します

○ OpenFlowの仕様のカバー範囲が大きいです

Lagopusとは(おさらい)

Page 3: Lagopus performance

● MPLS-VLAN変換をやりつつ● 10万フローエントリを持った状態で● 10GbEでワイヤーレート (14.88Mfps)

○ ショートパケット (64bytes)

Lagopusの性能目標(当時)

ether header MPLSshim header upper layer header and payload

ether header VLAN header upper layer header and payload

Page 4: Lagopus performance

● パケットの書き換えを伴う転送を実行する● 2ポート

想定している通信

MPLS network VLAN networkLagopus

Page 5: Lagopus performance

ざっくり一言でいえば、ユーザスペースでパケット読み書きするライブラリ● コピーを(なるべく)しない● コンテキストスイッチさせない● メモリフォールトを起こさない● 割り込み駆動させない● キャッシュ活用、SSE命令活用● マルチコア活用、NUMAアーキテクチャを意識

予備調査サンプルプログラム example/l2fwd にてショートパケット転送→10GbEワイヤーレート出ました

I/O性能: DPDK

Page 6: Lagopus performance

● ソフトウェアで処理する以上、基本的に○ なるだけメモリアクセスしない○ メモリコピーもなるだけ避ける○ コードも小さく実行ステップ数を少なく○ 余計な処理を削る

● などすれば、それらをしない場合と比較して、速くなる。● もちろん、本当に必要な処理を省いて速くしても意味はない。

OpenFlow処理性能

Page 7: Lagopus performance

● OpenFlowでは特定の通信1本を「フロー」と呼んでいる○ たとえばPC-AがServer-Bに80/tcpの通信をするパケット○ たとえば任意ホストがServer-Cに53/udpの通信をするパケット○ 折り返し(たとえば上記パケットの応答)も別フローという勘定

● OpenFlowスイッチは、パケットヘッダを見てフローを選別し処理する○ 処理: パケットヘッダの書き換え、指定ポートへのパケット送信

● ひとつのフローを選別(match)する設定をフローエントリと呼ぶ○ これらが登録された塊をフローテーブルと呼ぶ

● OpenFlow処理対象のパケットは、一つのフローエントリにのみmatch

フローエントリ・フローテーブル

Page 8: Lagopus performance

● 10万フローエントリ=10万種類のmatch○ 今回の想定では1方向(折り返し方向のパケットは考えない)

10万フローエントリ

entry # 優先順位 match action counter

1 1 マッチ条件1 処理1

2 1 マッチ条件2 処理2

:

100,000 1 マッチ条件100,000 処理100,000

Page 9: Lagopus performance

matchの部分だけ抜粋したもの※実際のOpenFlowプロトコルは下記をバイナリエンコードしている

in_port=1,eth_dst=00:00:00:00:00:00,eth_type=0x8847,mpls_label=0,in_port=1,eth_dst=00:00:00:00:00:00,eth_type=0x8847,mpls_label=1,in_port=1,eth_dst=00:00:00:00:00:00,eth_type=0x8847,mpls_label=2,::in_port=1,eth_dst=00:00:00:00:00:00,eth_type=0x8847,mpls_label=99999,

使用したフローエントリ

MPLSのeth_type

label指定を10万種類

Page 10: Lagopus performance

● 1秒間に1488万パケットを転送● 1パケットあたりの所要時間: 1/14.88M=67.2nsec● 2GHz CPUでは134クロック● 3GHz CPUでは201クロック

14.88Mfps

Page 11: Lagopus performance

● Intel DPDKという速いパケットI/Oライブラリがある● Lookup(match)とactionがどのくらいの速さか測ってみて考える● まず愚直にエントリ1にmatch?→エントリ2に…というものを作る

○ 末尾のエントリでは遅くなるという予想は簡単にできる● 1コアで、受信-OpenFlow処理-送信を連続実行(1スレッド)

Lagopusプロトタイプ1st

受信 match action 送信コア1

10万エントリをリニアサーチする

Page 12: Lagopus performance

● 測ってみないとどのくらい理想と現実に差があるかわからない● 測ってみた (Xeon 2.2GHz)● 先頭のエントリにmatchするトラフィックのみ: 14.88Mfps● 末尾のエントリにmatchするトラフィックのみ: 22Kbps (42fps)

笑えるくらいひどい数字を見た。

● 末尾エントリに当たる場合、ほとんど流れないに等しい。● 末尾エントリに当たるパケットで速くする必要がある。

Lagopusプロトタイプ1st測定

Page 13: Lagopus performance

● Lookup アルゴリズム○ さすがに愚直に10万エントリをリニアサーチするのはないだろう○ どうにかリニアサーチせずに済ませられないかのアイデア出し

● 対象エントリをどれだけ絞り込めるか?○ リニアサーチでいえば、エントリ数が半分ならかかる時間も半分○ Lookupにかかるメモリアクセス量が少ないほど速くなる

● データ構造○ サーチに適したデータ構造をとることで速度向上できるか?

● 複数コアの利用○ 複数コアで並列処理させればその分速くなる○ 処理をパイプライン化させればコアごとの処理が局所化できる

速度向上案

Page 14: Lagopus performance

● https://www.openmp.org/● 繰り返し処理が記述されたプログラムを並列化する● C言語では#pragmaディレクティブを埋め込むだけ● 例

#pragma omp parallel forfor (i = 0; i < max_entry; i++) {

並列化したい処理;}

● どのコアを使うなどの細かい制御は要求されず自動的に処理される● 探索対象フローエントリを等分してそれぞれのコアで処理● 処理済みのエントリを持ち寄って、もっともpriorityの高いエントリを採用

OpenMPを使ってみた

Page 15: Lagopus performance

● 試作して動かしてみた● かえって遅くなった● なぜか

○ 10コアでばらしても1コアあたり1万エントリの探索○ コアごとの選出エントリが出揃わないと比較できない○ 比較して最終的に選ぶときには1コアでの処理○ 1パケットごとにスレッドをバラして止めてを繰り返しすぎる○ DPDKのコア・スレッド管理との相性も良くない

● OpenMPによる高速化の試みは失敗。● 書いた試作コードは非公開のまま闇に消えていただいた

OpenMPを使ってみた: 結果

Page 16: Lagopus performance

● ルーティングテーブルではPatricia Treeが使われる● OpenFlowでは単純にPatricia Treeを適用することができない● OpenFlowのmatchは複雑

○ パケットヘッダの特定のフィールド40種類 (OpenFlow 1.3)■ eth_src, eth_dst, eth_type, vlan_id, ip_src, ip_dst, ip_proto,...

○ 任意のフィールド複数をAND指定できる○ 省いたフィールドはワイルドカード○ 値の比較の際にビットマスクを指定できる○ エントリにpriorityがあり、順序に基づきmatch結果が決まる

● OpenFlow仕様を逸脱する実装は行わない● option指定となっている機能も実装を省かない前提

Lookupの難しさ

Page 17: Lagopus performance

ip_srcをキーにして高速探索するコードを作っても結果が誤りとなる例

一筋縄ではいかない例

フロー# priority ip_src ip_dst

1 32 192.168.0.1 -

2 31 - 10.0.0.1

3 30 192.168.0.2 -

4 29 192.168.0.3 -

priority順に探索する

フロー2が正解

ip_srcで探索すると

フロー3となるが、誤り

eth IPv4 src:192.168.0.2 dst: 10.0.0.1 Payload

Page 18: Lagopus performance

● いくつかのフィールドにてexact matchと無指定のテーブルを用意する● exact matchは、配列やhash table, patricia treeなどで高速探索● 探索した先は、別のフィールド用の2つのテーブル● 無指定のテーブルは、別のフィールド用の2つのテーブル● exact matchを続けた結果のエントリと無指定のエントリのpriorityを比較● 優先度の高い方を選択 * テーブル段数でエントリを特定する● flow_mod(フローエントリ登録)にも利用し、高速化できた

リニアサーチよりは速いが、これがベストかは疑問。他の探索アルゴリズムやテーブル構造についても調査・検討中。

現在のLookup table実装

Page 19: Lagopus performance

● 他の要素(VLAN IDやMPLS labelなど)を省いて簡略化した例● eth_typeは配列、ip_src, ip_dstはマスク別のpatricia tree● priorityの高いほうの結果(フローエントリ)を選択する

Lookup table例

Top

0x0000 0x0800 0xffff無指定

無指定 ip_src

無指定 ip_dst無指定 ip_dst

...eth_type

ip_src

ip_dst

Page 20: Lagopus performance

● 1コアでやるから遅い● 複数コアで並列に処理すればその分速くなる

○ ただしX個にすればX倍、とはいかない● 共有リソースアクセスに対するロックが問題となる→バルク処理● 命令キャッシュのヒット率を高めるためコアごとに処理内容を分ける

複数コアの利用

受信OpenFlow処理

送信OpenFlow処理OpenFlow処理OpenFlow処理

受信 送信

Lock n個処理 Unlkn個受信 n個送信

read lock同士は干渉しない

locklessのring buffer

Page 21: Lagopus performance

● テーブル探索で速くなったが8コア、12コアでも14.88Mfpsに届かず● 8Mfps程度● Linuxに用意されているperfコマンドを用いて遅い個所を調査● Lagopusを動かしておき、別ターミナルでsudo perf topを実行● 実行時間の長いfunctionが上位に表示される

○ 処理が軽くても空回り(busy loop)しているfunctionは上位に表示● 調査結果、まだまだLookupが遅いことが判明

まだ遅い。

Page 22: Lagopus performance

1. 最初のパケットは通常のマッチ処理を行う2. マッチ完了→パケットヘッダの情報とフローエントリが関連付けられる3. 関連付けをキャッシュテーブルに登録する4. 次のパケットはパケットヘッダの情報でキャッシュを引く5. 見つかればフローエントリは確定しているのでマッチ処理完了6. 見つからなければ通常マッチ処理してキャッシュ登録

これにより12コアを使ってMPLS-VLAN転送14.88Mfpsを達成。(2014年3月)

Lookup軽量化: flow cache

Page 23: Lagopus performance

● OpenFlow処理スレッドでは、1パケットをmatch-action完了まで実行する● 毎回やる必要のない処理があれば、省くことで速くなる● たとえば、特定処理の時のみ使われる変数の初期化

○ OpenFlowのactionには、2種類がある■ 即時実行するapply-action■ 書き溜めておき、最後に実行するwrite-actions

○ write-actions用変数の初期化は毎回必要とはならないことが多い○ これを必要な時のみ実行するよう変更

もっと速く

Page 24: Lagopus performance

● OpenFlow処理スレッドでは、1パケットをmatch-action完了まで実行する● 細かく見ると、パケットヘッダの情報収集、match、actionにわけられる● パケットヘッダの情報収集をn個まとめて処理するよう変更● 命令キャッシュの利用効率が向上● Intel Performance Counter Monitor (Intel PCM)で調査できる

○ CPUが持つカウンタを参照するのでXeonが必要● 2015年4月現在、前出と同ハードにて、4コアを使って13Mfpsの性能

○ 開発版○ 近日リリース予定とのことです

もっともっと速く

Page 25: Lagopus performance

アイデア段階のものがいくつかある。● matchとactionをスレッド(コア)分離させる● matchをバルク処理させる● action処理を見直す● RSSである程度処理を分散させ、一部の探索を省く● ポートごとに独立した処理とし、ポート数が増えても速度を維持させる● Intel NICのflow director機能を使い、ハードウェアflow cacheを実現● flow cacheに使っているhash tableを高性能なものに置き換える● バルク処理パケット数の調整(レイテンシ・揺らぎが増える)● フローテーブルの内容によりダイナミックに探索テーブル生成

● and, more! 提案、実装、大歓迎!

さらなる性能向上に向けて

Page 26: Lagopus performance

Lagopus

http://lagopus.github.io

ONF (OpenFlowの総本山)

http://www.opennetworking.org/

Lagopus User Community

http://www.lagopus.community/cms/

DPDK

http://dpdk.org/

Reference