高速パケット処理のために (e)BPF を介して Linux カーネルの XDP フックに接続し、基本的なレイヤー 3/4 転送を実行するプログラム。このプログラムは、接続を処理するために IPTables や NFTables と同様のソース ポート マッピングを実行します。既存の接続は、接続のナノ秒あたりのパケット数に基づいて優先順位が付けられます。これは、ポートが枯渇すると、ナノ秒あたりのパケット数が最も少ない接続が置き換えられることを意味します。ナノ秒あたりのパケット数が多い接続はより敏感になるため、これが最善であると考えています。
さらに、ホストのネットワーク構成またはネットワーク インターフェイス カード (NIC) が XDP DRV フック (別名ネイティブ、SKB の作成前に発生) をサポートしていない場合、プログラムは XDP SKB フック (別名、ジェネリック、SKB の作成後に発生) への接続を試みます。これは、IPTable と NFTable がnetfilter
カーネル モジュールを介して処理される場所です)。コマンドラインからオーバーライドを使用して、SKB モードまたはオフロード モードを強制することができます。
そうは言っても、ホストのネットワーク構成が XDP の DRV フックをサポートしていない理由は次の可能性があります。
このプロジェクトが、XDP の利用に興味のある既存のネットワーク エンジニア/プログラマー、またはそれらの分野に興味のある人にとって役立つことを願っています。高性能ルーター/パケット転送と (D)DoS 緩和/防止はサイバー セキュリティの非常に重要な部分であり、低中レベルのネットワーキングとパケット フローの概念を理解することは、この分野でキャリアを追求している人にとって間違いなく役立ちます。
警告- このプロジェクトにはまだやらなければならないことがたくさんありますが、現時点では IPv4 のみをサポートしています。 IPv6 サポートは正式リリース前に追加される予定です。現時点では、プログラムにはバグが含まれている可能性があり、転送機能はまだ利用できません。
バインド アドレスごとに使用できるデフォルトの最大送信元ポートは21で、ここで設定されます (必要に応じてこれらを調整できます)。デフォルトではポート範囲500 ~ 520を使用しますが、これは構成可能です。
最初は、利用可能なほとんどのポート (1 ~ 65534) を使用しようとしていました。ただし、BPF 検証ツールの制限により、Linux カーネル内でいくつかの定数を生成し、カーネルを再コンパイルする必要がありました。これらのパッチを作成し、すべてをここに文書化しました。作成したパッチを使用して構築したカスタム カーネルでは、バインド アドレスあたり 65534 の最大ポートでプログラムを問題なく実行できます。ただし、使用可能なソース ポートが多いほど、使用可能なポートを確認するときに XDP プログラムが実行する必要がある処理が増えることに注意してください。
これを運用環境で使用する予定がある場合は、上記の定数を使用して独自のカーネルをコンパイルすることを強くお勧めします。バインド アドレスあたりの送信元ポートの最大数が 21 というのはそれほど多くはありませんが、残念ながら、デフォルトの BPF ベリファイアの制限により、現時点ではこれ以上のことはできません。
これらの制限を引き起こす主なコードはここにあり、新しい接続に使用する最適な送信元ポートを見つけようとしているときに発生します。私の理解では、すべての送信元ポートをループし、ナノ秒あたりのパケット数の値を確認する必要があるため (BPF マップはキーで検索)、私たちが理解している柔軟性で利用可能な最適な送信元ポートを確認する方法は他にありません。
これらのパッケージを使用してプロジェクトをビルドするため、 make
、 clang
、 libelf
、およびllvm
必要になります。さらに、構成ファイルを解析するにはlibconfig
( libconfig-dev
Ubuntu/Debian システムのパッケージです) も必要です。
Ubuntu/Debian の場合は、次のように機能するはずです。
apt install build-essential make clang libelf-dev llvm libconfig-dev
パッケージ名は他の Linux ディストリビューションでも似ていると思います。
XDP プログラムは BPF マップを/sys/fs/bpf/xdpfwd
に固定するため、 xdpfwd-add
およびxdpfwd-del
使用するには、BPF ファイル システムをマウントする必要があります。これはiproute2
または同様のものによってすでに行われている可能性が高くなりますが、そうでない場合は、次のコマンドを使用できます。
mount -t bpf bpf /sys/fs/bpf/
基本的なコマンドラインの使用法には次のものがあります。
-o --offload => Attempt to load XDP program with HW/offload mode. If fails, will try DRV and SKB mode in that order.
-s --skb => Force program to load in SKB/generic mode.
-t --time => The amount of time in seconds to run the program for. Unset or 0 = infinite.
-c --config => Location to XDP Forward config (default is /etc/xdpfwd/xdpfwd.conf).
-l --list => List all forwarding rules.
-h --help => Print out command line usage.
XDP/BPF プログラムをシステムの NIC にオフロードすると、NIC がそのハードウェアでパケットを処理/転送するため、最速のパケット処理が可能になります。ただし、この機能をサポートしている NIC メーカーは多くなく、 NIC のメモリ/処理が制限されます (たとえば、BPF マップ サイズが非常に制限されます)。さらに、通常、オフロードされた BPF プログラムにはより厳しい BPF 検証ツールの制限がありますが、NIC のメーカーに連絡して、これらの制限を引き上げた特別バージョンの NIC ドライバーを提供してくれるかどうかを確認してみるとよいでしょう (これは私があるメーカーで行ったことです)使っていました)。
現時点では、BPF の複雑さとループ要件のため、このツールを NIC に完全にオフロードできる NIC メーカーを私は知りません。正直に言うと、現在のネットワーク時代では、オフロードされたプログラムは BPF マップ ルックアップと最小限のパケット インスペクションに任せるのが最善であると私は考えています。たとえば、単純な BPF レイヤ 2 ルート テーブル マップの検索と、パケットのTX をNIC から送り返します。ただし、XDP はまだ非常に新しいため、今後数年間でこれらの制限が緩和または解除されると思います。これが、このプログラムにオフロード モードのサポートを追加した理由です。
インストール時に/usr/bin
経由で$PATH
に追加されるxdpfwd-add
実行可能ファイルは、次の引数を受け入れます。
-b --baddr => The address to bind/look for.
-B --bport => The port to bind/look for.
-d --daddr => The destination address.
-D --dport => The destination port.
-p --protocol => The protocol (either "tcp", "udp", "icmp", or unset for all).
-a --save => Save rule to config file.
これにより、XDP プログラムの実行中に転送ルールが追加されます。
インストール時に/usr/bin
経由で$PATH
に追加されるxdpfwd-del
実行可能ファイルは、次の引数を受け入れます。
-b --baddr => The address to bind/look for.
-B --bport => The port to bind/look for.
-p --protocol => The protocol (either "tcp", "udp", "icmp", or unset for all).
-a --save => Remove rule from config file.
これにより、XDP プログラムの実行中に転送ルールが削除されます。
デフォルトの構成ファイルは/etc/xdpfwd/xdpfwd.conf
にあり、 libconfig
構文を使用します。現在の機能をすべて使用した構成例を次に示します。
interface = "ens18"; // The interface the XDP program attaches to.
// Forwarding rules array.
forwarding = (
{
bind = "10.50.0.3", // The bind address which incoming packets must match.
bindport = 80, // The bind port which incoming packets must match.
protocol = "tcp", // The protocol (as of right now "udp", "tcp", and "icmp" are supported). Right now, you must specify a protocol. However, in the future I will be implementing functionality so you don't have to and it'll do full layer-3 forwarding.
dest = "10.50.0.4", // The address we're forwarding to.
destport = 8080 // The port we're forwarding to (if not set, will use the bind port).
},
...
);
必要なパッケージをすべてダウンロードしたと仮定すると、このプロジェクトのビルドは簡単です。次のシェルおよび Bash コマンドを使用できます。
# Clone respository and its sub-modules such as LibBPF.
git clone --recursive https://github.com/gamemann/XDP-Forwarding
# Change directory.
cd XDP-Forwarding
# Make project using all cores.
make -j $( nproc )
# Install binaries to PATH as root so you may use 'xdpfwd', 'xdpfwd-add', 'xdpfwd-del'.
sudo make install