Ubuntu でMPTCPを試す
MPTCPの必要性
在宅テレワークが常態化する時代になってきた。インターネット接続の信頼性を向上させるため、インターネットへは複数の接続としKeepalive で冗長構成としているが、VPNのように一度コネクションを張ってしまった後で何らかの理由で接続が切れてしまうと、IPレベルでは冗長構成でもTCP では再接続するということになる。切れないVPNを探していたところにMPTCPの存在を知り、早速試してみた。切れないVPN に使えないものかと参考サイトを頼りに試してみたものの、開発途上の為かそのまま動くというものでもなく、動くまでに苦労してやっとここまで辿り着くことができた。
参考となったサイト : アップストリーム版のMPTCPを試してみた
試験運用の概要
Linux 最新版のkernel は、既にMPTCP の機能を利用することができることから、仮想環境でネットワーク及びホストを構成し、既存アプリからMPTCP が使えるようにSystemTap を使ってソケット生成時に「IPPROTO_MPTCP」を指定するやり方を踏襲した。素晴らしい発想だと感じたところだが、SystemTap がなかなかの曲者で、サラッと書かれているが実際にやってみると、色々と苦労した。まずは、Client, Network, Server を作成してデータのやり取りを確認するためにiperf を使用してみた。
環境構築
仮想環境の中にネットワークとホスト(Client, Network, Server)を構成し、ネットワークをインターネットに見立てて環境を構築する。仮想環境にはVirtual Box を使用した。
ネットワーク構成
Client ホストから3本で接続し、Server ホストへは1本で接続するようにルータを構成する。本来ならClient から2本で良かったが、Virtual Box のネットワークデバイスが4つあるので、最大限使ってみた。後で、この扱いに苦労することになってしまった。最初はシンプルな方が良い。すでに教訓を、、自分で作り出している感もある。まぁ、将来的に携帯端末も接続することを考慮すれば、これも有りかもしれない。これをインターネットに見立てて環境を構築した。ルータはUbuntu で構成したが、ここは特にMPTCP に対応する必用はない。Virtualbox のネットワークインターフェースの各モードについては理解しておく必用がある(便利だが、慣れるまでややこしい)。一応、構築した環境は以下のとおり。
VM(Client, Server)の作成
Virtualbox の構成においては仮想ハードディスク容量を15GB以上にしてUbuntu 21.04 をインストールし、アップデートして最新の状況にしておく。以下によりMPTCP が有効になっていることを確認する。
$ cat /proc/sys/net/mptcp/enabled
この時、”1″ が出力されればMPTCP が使用可能であることが分かる。素晴らしい・・・
SystemTap の導入
SystemTap は、kernel デバッグに使用するためのもので、専用のスクリプト言語を持ち、それを実行しC のソースに変換しコンパイルしてモジュールを作成、kernel に組み込む一連の動作をする。
kernel デバッグ情報のインストール
kernel のheader、デバッグ情報をインストールする。
Systemtap のインストール
apt install すると動かないstap が導入されるので、インストールされているようであればapt remove で削除した後にGit からclone して直接コンパイルする。
$ sudo apt install g++ make git libelf-dev libdw-dev
$ git clone git://sourceware.org/git/systemtap.git
$ cd systemtap/
$ ./configure --disable-nls && make // no errors → nls があるとError で止まる
$ sudo make install
$ sudo stap -e 'probe begin { printf("Hello, World!\n"); exit() }'
[sudo] password for knudfl:
Hello, World!
この段階で動作を確認する。stap -g のguru モードではモジュールコンパイルまではできるが、最後の組み込みの段階でエラー “Invalid module format” になる。modinfo で確認しても問題ないのでプログラムのバグな感じ。以下のオプションを加えるとエラーが出なくなる。
$ sudo stap -B CONFIG_MODVERSIONS=y -g -v hogehoge.stap
スクリプト「mptcp.stap」の作成
参考となったサイトに記述してあるとおり。
#! /usr/bin/env stap
%{
#include <linux/in.h>
#include <linux/ip.h>
%}
function mptcpify () %{
if (CONTEXT->kregs->si == SOCK_STREAM &&
(CONTEXT->kregs->dx == IPPROTO_TCP ||
CONTEXT->kregs->dx == 0)) {
CONTEXT->kregs->dx = IPPROTO_MPTCP;
STAP_RETVALUE = 1;
} else {
STAP_RETVALUE = 0;
}
%}
probe kernel.function("__sys_socket") {
if (mptcpify() == 1) {
printf("command %16s mptcpified\n", execname());
}
}
このスクリプトを実行することで、socket()コール時にIPPROTO_TCP をIPPROTO_MPTCP に入れ替えることができる。やっとここまで辿り着くことができた。難なくここまで持ってこれるのは凄いと思う。暫くハマってた場所・・・。
とりあえず、ここまででMPTCP 試験のための環境の構築ができた。
早速試験…
試験としてClient からServer までのネットワーク・ベンチマークに仕様するipref を使用して一応の動作を確認した。レイアウトの説明は、上段がClient とネットワークの間のトラフィックを示している。3ポートあるので、3つ。右下の窓はServer に流れてきたトラフィックを表している。
まずはTCP モードで
左上からトラフィックが発生しているのが分かる。
次にMPTCPを試す
stap でMPTCP が使用出来る状態にして同じiperf でベンチマークを実行する。
Client 側でServer までのトラフィックが分散されているのが分かる。ここで、上段右2つのポートは、subflow に指定し、それぞれポリシー・ルーティングの設定をしている。ここのトラフィックはtcpdump でもモニターしており、mptcp であることを確認している。
まとめ
最初はどうなるかと思っていたが、何とかMPTCP のSubflow の状況まで可視化することができた。ネットには大変参考になる内容も多く、これを元に更に応用にチャレンジしたい。
教訓
- 最初はシンプルな構成から
- 手強くても、最後まで諦めない。世界ではどこかで自分と同じハマリを経験した人がいる・・・はず
- 最後に行くに従い、手抜き感じがプンプンしている・・。教訓でもないけど、もう少し丁寧に記述しよう(反省)。
すごい成果ですね。「まとめ」と「教訓」は素晴らしい。僕も新しい何かに挑戦するときは、グーグル先生に頼りながら、諦めないでなんとかしようと思っています。おっしゃる通り、「世界ではどこかで自分と同じハマりをしている人が必ずいます」ね。
池田さん、
コメントありがとうございます。
この成果をどこに活かすか、その性能評価をして意味がある成果につながるか・・・、
と色々な疑問はありますが、まずはやってみることですね。
実は、これがなかなか難しい。
でもコメント、励みになりますね。
ありがとうございました。