発端:Vultrとの通信帯域が細い&応答が悪い
拙宅のインターネット環境は「マンション共有無料ベストエフォート(最大1Gbps)IPoE IPv4 over IPv6接続」です。
(詳しい回線構成は下記)
この回線、入居当初はPPPoEだったんで特定の時間帯に非常に低速だったんですが、いつの間にかIPoEに変化していて(IPアドレスは変わってないのが凄く謎)、調子の良い時は230Mbpsぐらい出ます。
ただし、降ってくるIPアドレスが尽くInternetからUnReachableだけどな!!!!
というわけで、先日独自ドメインのメールサーバーを構築する必要性に迫られ、容量を気にしなくて良いローカル側に仮想マシンを置きたかったけどInternetからReachableなIPv6アドレスを仮想マシンに直接割り当てる必要性から、自宅サーバーのフロントとしてさくらのVPSとは別にVultrを契約して運用を始めました。
この時、Vultrとは直接、SoftEtherによるIPv6でのVPNを張っていました。VultrのIPアドレス帯は米国のものだけど実在地は大阪リージョンになっていて、VultrのVMからSpeedTestをした限りでは、大変ぶっ飛んだ速度で通信ができていたから、自宅との疎通も高速だろう、と踏んでいたからです。
が、メールサーバー構築後にライフワークと化しているPHPウェブシステムの開発過程で、6GBにもなる大量の写真を開発環境のフロントになっているVPS(Vultrではない)に何度もPOSTしてたら速度制限を喰らった(残当)ため、IPv6だけVultrを経由してローカルに居る仮想マシンのリバースプロキシへ流れる様にネットワークを変更したところ、60Mbps程度しか出ませんでした。
従前環境では100Mbpsの帯域をフルに使い切っていたのに、より高速なはずのVultrでこの程度しか出ない。つまり経路のどこかにボトルネックがある訳です。
という訳でtracerouteとpingを駆使して経路を調べてみました。その結果、どうも
Vultrとの通信はIPv4/IPv6ともに米国っぽいルートを回ってVultrの大阪リージョンに到達し、同じ経路を辿って戻ってきている様です。
そりゃ遅いに決まっとるがね。
この辺り、マンション共有インターネットのプロバイダが利用しているJPNE/JPIXの経路情報が変なのかVultrの経路情報が変なのかは不明ですが、取り敢えずVultrとの間に敷かれたルートが非常に遠いということで状況は把握しました。
ぶっちゃけテザリングで東京を経由して大阪に到達するルートでPingした方がレイテンシ低かったです。つらい。
対処法の模索と挫折
さて状況が判明したところで、対策を考えねばなりません。
マンション共有インターネット回線のプロバイダを変えるのは不可能ですから、新たにインターネット回線を引いて、Vultrとの疎通が遠回りではないプロバイダを選択すれば状況は改善する筈です。
「そういや最近この近辺では新しい光ファイバー敷設工事をしてたし、ワンチャン我が家にも1Gbps以上の回線引けるかな!?」と問い合わせた所……
「この物件はVDSLしか通らないですね。100Mbpsです(コールセンターの人談)」
という無慈悲な回答が。
一応光配線タイプの工事とか出来ないか食い下がってみたものの、無理なものは無理ですぜ旦那ァ!(意訳)とのことで。約束された100Mbps(最大速度)の為に1Gbpsと同じ値段の利用料を払うという決断はちょっと出来ないですね……。
であれば最近流行りのホームルーターを検討することになる訳ですが、
「利用場所が高くなればなるほど電波は弱くなりますから速度も出ないですね(コールセンターの人談)」
とのことで。そのリスクを負ってまで高いホームルーター買って、更に月3480〜4100円ぐらいかぁ……と思うとこれも二の足を踏むことに。ところでその理屈だと我が家のiPhoneSE3ちゃんがアンテナ4本で速度も200Mbps以上出てるのは一体何なのという話なんですが
コールセンターの人は「テレワーク(意訳)でアップロード帯域が必要とのことですので、100MbpsでもVDSLを引かれた方が良いかと思いますが……」とガイダンスしてくれました。うん、私もそう思う。思うけど、100Mbps以上の回線が欲しいんだよ私は……
そしてマルチクラウドへ
取り敢えずVultrとルーターとの間に敷かれたVPN区間だけでも、なるべく安価に高速化出来ないかしら……と色々机上検討した結果、
先日Akamaiに買収されたLinodeであれば、ちょうど大阪リージョンが開設されたことだし、Akamaiだから変な経路情報が設定されていることはないのでは!?
と思い、Vultrと自宅ルーターとの間にLinodeを挟んでVPN区間をショートカットすることを思いつきました。
転送量が1TB/月なのは気になるけど、現状Vultrの転送量も使い切れてないから取り敢えず気にしなくて良いだろう、と判断してアカウント開設を試みます。
が、メインメールアドレスであるGmailを使ったのがダメだったのか、スパム判定されてまさかの開設NG。一応救済措置としてサポートに異議申し立てが出来るメールフォームのアドレスが送られて来ましたが、そちらから拙い英語で抗議しても梨の礫でした。つらい。
では他に大阪リージョンがあって変な経路になってなさそうなクラウドサービスはないかしら……と思いながら途中区間をさくらのVPS(大阪リージョン)にしたらレイテンシだけはかなり改善して草生えました。でも帯域は100Mbpsなんですよね。つらい。
そう思いながらふと思い出しました。
「そういや天下のOracleのクラウドって大阪リージョンなかったっけ?」 と。
というわけでLinodeアカウント開設に失敗した翌々日、今度はOracle Cloud Infrastructureのアカウント開設に挑みました。各種SNSでも言及がある様に、アカウント開設の難易度が非常に高かったですが、最終的にはトランザクションエラーから遷移できるメールフォームからサポートを依頼してアカウント開設に成功しました。この辺り、サポートが非常に手厚くて感心しました。この場を借りて、対応してくださったサポートスタッフの方には心からの感謝御礼を申し上げます。
そんな訳でOCI大阪リージョンに枠を確保して、VCNを作成し、AMD/1oCPU/1GBのインスタンスを作成してIPv6アドレスを割り当てて、自宅からOCI、OCIからVultrまでの経路情報とPing値を調べます。
自宅 <-> Vultr : 130ms以内
自宅 <-> OCI : 10ms以内
OCI <-> Vultr : 3ms以内
いや天下のOracleだから変な経路にはなってないとは思ってたけど、想像以上にレイテンシ小さいな!?
インターネットへのアウトバウンド転送量10TB/月、但し1VMあたり最大50Mbpsの帯域制限があるはず(と仕様書に書いてある)なのに何故か上り下り共に480Mbps出るのにワクワクテカテカしながら、OCIに作成したインスタンスにSoftEtherをインストールしてセットアップし、「 Vultr <-> OCI <-> 自宅 」という風にVultrとの間にOCIを挟む形にVPNの通信経路を変更します。
結果、最大スループットは兎も角としてレイテンシが大きく改善しました。特にVPNでVultrとの間のレイテンシが大きく削減されたのが、レスポンス向上に大きく役立っています。
また、Vultr <-> 自宅ルーター間のVPN区間内のスループットについては、OCIを挟むことで、iperf3が50〜60Mbpsだったのが80〜110Mbpsに改善しました。
しかし、回線のポテンシャルからするともっと速度が出ても良いはずです。SoftEtherの限界説も無くはないのですが(実際UDP高速化機能を切ったらそこそこ改善した)、各VMのCPU使用率からするとまだまだ余裕があります。
しかし私の力では具体的に何処がボトルネックなのか突き止めることが叶いませんでした(叶わなかったからと言って、対処法が思いつかなかったとは言っていない)
楽天モバイル回線の追加とMPTCP
はい、ここでやっと表題の「MPTCP」 ーー Multi Path TCP という単語が出てきます。
要は1つの通信対象に対し、2つ以上の経路を経由してアクセスしてスループット・冗長性を向上させようという試みです。iOS/iPadOSではOSのアップデートをダウンロードする際にモバイル回線「も」利用するかどうか訊いてくることがありますが、あれが正にMPTCPです。
当たり前ですが、MPTCPの利用には2つ以上の経路が必要です。
偶々、iPad(7th)のバッテリーがそろそろ怪しくなって来たので買い換えようとしていて、ついでに5G回線にしたかったので今までのMVNOのSIMを解約しようとしていた矢先、今回のおうちクラウド改善計画が発生したので、VDSL回線引くよりか、このSIM使ってMPTCP検証する方が安く済むんじゃね? と余計なことを思いついたのでした。
図にするとこんな感じです。
常識的な構成のNTT系VDSL回線だと、VDSL装置に接続されている光ファイバー(大抵1Gbps)を全戸で分け合う可能性があります。つまり100Mbpsも出ない場合があります。
拙宅の回線状況を見るに、VDSL装置に引き込まれている光ファイバーをマンション共有インターネット回線と共有している可能性もあります。なので変にVDSLの回線を引いても上流の光ファイバーで帯域を取り合う可能性もありました。
そういったことを勘案して、取り敢えず敷設が楽な5G SIMでのMPTCPによるスループット向上の検証を思いついたのでした。
と言う訳で(どう言う訳だ)、何故か手元に楽天5GデータSIMと、au/UQ系モバイルルーター「X11(NAR01)」がクレードル付きで湧きました。不思議なこともあるものです。IYH!
NAR01を設定する前に、OCIのインスタンスにIPv6アドレスをもう一つ付与しておきます。
この時、初期設定のNetplanを複製した上で、次のように編集しておくのを忘れないでください。
network:
ethernets:
ens3:
dhcp4: true
dhcp6: true # <-追加
match:
macaddress: xx:xx:xx:xx:xx:xx
set-name: ens3
version: 2
購入したNAR01を徐にSIMを入れて初期化し、スマホに入れた設定アプリから設定画面を開いてAPN設定を行い(この手順は先行例が多数ありますので割愛します)、プラスエリアモードではなくスタンダードモードに設定して(何故かプラスエリアモードだとインターネット接続が不定期になくなり再起動するしかなくなるため) 、クレードルに挿してクレードルと仮想化基盤サーバーの空きNICポートをLANケーブルで結びます。
仮想化基盤サーバーの空きNICポートを仮想化基盤の仮想スイッチにブリッジし、仮想スイッチを仮想ルーターに繋ぎ込みます。
Netplanは取り敢えず、
ethY: # <-追加されたインターフェイス名
accept-ra: true
dhcp4: false
dhcp6: false
みたいな感じに設定します。
するとRAでIPアドレスとデフォルトゲートウェイの情報が追加されたインターフェイスに付与されますので、
ip -6 route
とルーターで打てば、
::1 dev lo proto kernel metric 256 pref medium
default via fe80::xxxx:xxxx:xxxx:xxxx dev ethX proto ra metric 100 expires 1797sec mtu 1500 pref medium
default via fe80::yyyy:yyyy:yyyy:yyyy dev ethY proto ra metric 1024 expires 296sec mtu 1440 pref medium
みたいな感じで対向する回線のゲートウェイのアドレス(常識的な回線であればリンクローカルアドレスかつ概ね不変)が取得出来ます。
この値を控えておいてください。
この記事を読んでいる方にとっては当然の暗黙の了解だと思いますが、追加した回線についてはあらかじめファイアウォールを適切に設定しておいてください。
もう一度Netplanの編集に戻って、次のように編集します。
network:
ethernets:
ethX:
accept-ra: true
dhcp4: true
dhcp6: true
optional: true
routes:
- to: xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
via: fe80::xxxx:xxxx:xxxx:xxxx
ethY:
accept-ra: true
dhcp4: false
dhcp6: false
optional: true
routes:
- to: yyyy:yyyy:yyyy:yyyy:yyyy:yyyy:yyyy:yyyy
via: fe80::yyyy:yyyy:yyyy:yyyy
編集したら sudo netplan try で書式が間違っていないことを確認の上で適用し、ルーターを再起動します。再起動完了後、ルーターにログインして ip -6 route でIPv6のルートを調べます。
xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx via fe80::xxxx:xxxx:xxxx:xxxx dev ethX proto static metric 1024 onlink pref medium
yyyy:yyyy:yyyy:yyyy:yyyy:yyyy:yyyy:yyyy via fe80::yyyy:yyyy:yyyy:yyyy dev ethY proto static metric 1024 onlink pref medium
このように設定されていて、IP確認くん(安全)などで自分がアクセスしている回線がデフォルト通常は固定回線を利用していることだけ確認できればOKです(多分)。
さて、次にSoftEtherをMPTCP対応にする作業を行います。
が。その前に注意点を書いておきます。
通常のやり方でSoftEtherをMPTCP対応にするとSoftEtherのプロセス(セッション)が無限増殖してCPUを食い潰し、VPNの接続先もまとめてダウンさせます(実体験)。
これから行う作業は飽く迄も筆者の環境に於いて、SoftEtherを暴走させずにMPTCP化が出来たというおま環案件なのであって、この手順通りに行なっても暴走したとしても、筆者は何ら責任を負えませんのでご注意ください。
SoftEtherをMPTCP対応にする
SoftEtherは多種多様なVPN接続方式に対応していますが、今回は通常のSoftEtherVPN接続方式(通常は5555,40000-44999/tcpを使用)をMPTCPに対応させたく思います。
SoftEtherは複数のインターフェイスで待ち受けることが出来ますが、逆に発呼して相手方に接続するインターフェイスを任意に選択することが出来ません(通常は一番メトリック値の低いデフォルトゲートウェイが使用されます)。
そのため、MPTCPの肝である「A宛には1番のインターフェイス、B宛には2番のインターフェイスを使用」みたいなことをするには、先ほどの様にスタティック・ルートを設定する必要があります。
そして複数経路を経由するVPNを張ったとしても、OS的には比較的最近のディストリビューションであれば対応していますが、そのままではMPTCPで通信してくれません。MPTCP通信はOSレベルでのサポートが必要であると同時に、ソフトウェアの側でも対応している必要があるからです。
↓が、幸いなことにLinuxにはソフトウェアをMPTCP化するソフトウェアが存在します↓
↓先行適用例↓
Ubuntuだと「 sudo apt install mptcpize 」でインストール出来るかと思います。
紹介した先行例ですと「 sudo mptcpize enable (サービス名) 」でMPTCP化していますが、
この方法でSoftEtherをMPTCP化するとプロセスが無限増殖してVPNの相手方も巻き込んでダウンします(実体験)。
少なくとも私の環境ではローカルとVultr、両方とも中間のOCIを巻き込んで死にました_:(´ཀ`」 ∠):
ちなみに暴走自体は「 sudo systemctl status softether-vpnserver 」で状態確認を行い、子プロセスが3つ以上起動していて時間経過と共に増えているかどうかで検知することが出来ます。
もし暴走している場合は、次の様に対処します。
sudo systemctl disable softether-vpnserver
sudo systemctl stop softether-vpnserver
sudo psgrep vpnserver | sudo xargs kill
これで取り敢えずSoftEther無限増殖は止まるはずです。きっと。メイビー。
もちろんVPN越しにSSH等で接続していた場合は漏れなく操作不能になりますので、VNCコンソールなりなんなりの別の操作手段を確保していることを強く推奨します。
これを「正しく」mptcptizeするには、まずSoftEtherの側であらかじめ
「Vultr <-> OCI間」、「ローカル <-> OCI間」、「Vultr <-> (OCIとの中に通したVPNの中を経由) <-> ローカル間」、の3つのVPN接続の設定を完了していて
かつ各VPN接続(カスケード接続)がオフラインになっていて
かつVPNの両端(この場合はVultrとローカルのルーター)にブリッジインターフェイスが設定されており、ブリッジインターフェイスに固定IPが設定されている
必要があります。
SoftEtherのサービスファイルで設定している場合は、仮にですがこんな設定が含まれている感じでしょうか。
ExecStart=/usr/libexec/softether/vpnserver/vpnserver start
ExecStartPost=/usr/sbin/ip addr add 192.168.X1.1/24 dev tap_vultr01 # <-追加
ExecStartPost=/usr/sbin/ip link set dev tap_vultr01 promisc on # <-追加
ExecStartPost=/usr/sbin/ip addr add 192.168.X2.1/24 dev tap_vultr02 # <-追加
ExecStartPost=/usr/sbin/ip link set dev tap_vultr02 promisc on # <-追加
ExecStartPost=/usr/sbin/ip addr add 192.168.X3.1/24 dev tap_vultr03 # <-追加
ExecStartPost=/usr/sbin/ip link set dev tap_vultr03 promisc on # <-追加
ExecStop=/usr/libexec/softether/vpnserver/vpnserver stop
ではこれをmptcpizeするのですが、先述したように素直に「mptcpize enable」でやるとプロセスが大増殖してバグるので、コマンド「mptcpize run」を使います。
# ExecStart=/usr/libexec/softether/vpnserver/vpnserver start # <-コメントアウト
ExecStart=/usr/bin/mptcpize run /usr/libexec/softether/vpnserver/vpnserver start
ExecStartPost=/usr/sbin/ip addr add 192.168.X1.1/24 dev tap_vultr01
ExecStartPost=/usr/sbin/ip link set dev tap_vultr01 promisc on
ExecStartPost=/usr/sbin/ip addr add 192.168.X2.1/24 dev tap_vultr02
ExecStartPost=/usr/sbin/ip link set dev tap_vultr02 promisc on
ExecStartPost=/usr/sbin/ip addr add 192.168.X3.1/24 dev tap_vultr03
ExecStartPost=/usr/sbin/ip link set dev tap_vultr03 promisc on
ExecStartPost=/usr/sbin/ip mptcp limits set subflow 2 add_addr_accepted 2 # <-追加
ExecStartPost=/usr/sbin/ip mptcp endpoint del 192.168.X1.1 id 3 dev tap_vultr01 # <-追加
ExecStartPost=/usr/sbin/ip mptcp endpoint del 192.168.X2.1 id 4 dev tap_vultr02 # <-追加
ExecStartPost=/usr/sbin/ip mptcp endpoint del 192.168.X3.1 id 5 dev tap_vultr03 # <-追加
ExecStartPost=/usr/sbin/ip mptcp endpoint add 192.168.X1.1 dev tap_vultr02 signal # <-追加
ExecStartPost=/usr/sbin/ip mptcp endpoint add 192.168.X2.1 dev tap_vultr01 signal # <-追加
# ExecStop=/usr/libexec/softether/vpnserver/vpnserver stop # <-コメントアウト
ExecStop=/usr/sbin/ip mptcp endpoint del 192.168.X1.1 dev tap_vultr01 signal # <-追加
ExecStop=/usr/sbin/ip mptcp endpiint del 192.168.X2.1 dev tap_vultr02 signal # <-追加
ExecStop=/usr/sbin/ip mptcp endpiint del 192.168.X3.1 dev tap_vultr03 signal # <-追加
ExecStop=/usr/bin/pgrep mptcpize | /usr/bin/sudo /usr/bin/xargs kill # <-追加
ExecStop=/usr/bin/pgrep vpnserver | /usr/bin/sudo /usr/bin/xargs kill # <-追加
上掲は飽く迄も例示ですので、インターフェイス名やIPアドレス帯は適当に読み替えてください。
また、mptcp endpoint addするのは「自身が持つインターフェイスのIPアドレス」+「ペアになるIPを持っているインターフェイス」であって、「対向するエンドポイントのIPアドレス「ではない」」のでご注意ください。
(上掲の場合だと「ip mptcp endpoint add 192.168.X1.1 dev tap_vultr02 signal」が、「192.168.X1.1というIP(を持つインターフェイスtap_vultr01)のペアになるIPを持つインターフェイスはtap_vultr02である」という意味になります)
3経路以上の回線をお持ちの逸般の誤家庭の場合は、「ip mptcp limits set subflow 2 add_addr_accepted 2」の数字を3以上に置き換えてください。
これをVPNの両端で行います。Killの仕方が雑やな
設定が完了したら、「sudo systemctl start softether-vpnserver」します。
まずそのまましばらく待機して、vpnserverが無限増殖しないのを「systemctl status softether-vpnserver」で確認してください。
次に、SoftEtherのカスケード接続を仮想HUB毎にオンラインにしていきます。
オンラインになり、ネットワークがループしていないことと、各接続セッションが別経路を通っていることを確認してください(接続元IPで識別してください)。
次に、互いに対向するIPアドレスに向けてpingを打ってください。応答が返ってきていればOKです。応答が確認できたら、
sudo ip mptcp monitor
と入力します。正常にMPTCPでSoftEtherが接続されている場合、次のような表示がずらずらと並ぶはずです(画像は一部をマスクしてあります)。
この表示が出た場合はMPTCP通信が成立しています。
「iftop -i (インターフェイス名)」などでMPTCP通信に使用しているインターフェイスの通信量をモニタリングしながら、iperf3などの通信負荷をmptpcpizeせずにmptcpizeしたSoftEtherで接続しているトンネルに対してかけてみましょう。
おそらく同時に通信量が増えていくのが観察できることと思います。
各インターフェイスで通信量が同時に増えるのが確認できたら、今度はエンドポイントを双方または片方再起動してみて、再起動後もSoftEtherの子プロセスが無限増殖せず、「ip mptcp monitor」でコネクションが正常に再生していれば成功です。
お疲れ様でした!
設定のハマり所
インターフェイスに複数IPを付与している場合は、最初に設定されているIP(メトリック値が最小)のものがエンドポイントになります。
セカンダリIPをエンドポイントに指定してもMPTCP通信が疎通しないことがあります。
(※IPv6アドレスの場合は同じプレフィックスのアドレス同士か、または固定したリンクローカルアドレスで対向しているのが望ましいと思われます)
MPTCP通信が成立したからと言って、レイテンシやスループットがリニアに向上する訳ではありません。
レイテンシについては速度差のある経路同士でMPTCP通信している場合は遅延が増大する場合があります。
通信は必ずしも意図した方(高速・低コストな方)へ偏るわけではありません。
稀にSoftEtherがハングすることがあります。
筆者の場合は何故かmptcpizeしていない途中経路のOCIのSoftEtherがハングしました。
(そりゃ非公式な対応なんだから仕方がない)
モバイル回線を使用してMPTCP通信を試みる場合は、必ず定額使い放題かホームルーターのプランを契約してください。
筆者はSpeedTestしたりiperf3したりして3日で18GB使いました(白目)。
パケ死しても筆者はどうにもできません。
総括
SoftEtherVPNをMPTCPに対応させることは可能である(簡単とは言っていない)。
2経路のVPNの中をMPTCP通信が通っていくことを確認できた(帯域が増強されたとは言っていない)。
MPTCPネットワークを構成するための知見を得られた。
MPTCP通信でスループットを得るにはまだ調査・調整が必要と思われる。今後の課題。
MPTCP通信を安定させるにはまだ調査・調整が必要と思われる。今後の課題。
MPTCP通信が成立したからといって、素直にスループットが増強されるわけではない。
(補足:筆者の環境の場合は時間帯により上下が激しく、また結局スループットは良い時間帯で130Mbps程度にしかならなかった。悪い時間帯だと30Mbpsなので、むしろ悪化している)
参考情報(再掲含む)