Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go Conference 2025: Goで体感するMultipath TCP ― Go 1...

Go Conference 2025: Goで体感するMultipath TCP ― Go 1.24 時代の MPTCP Listener を理解する

Go Conference 2025 「Goで体感するMultipath TCP ― Go 1.24 時代の MPTCP Listener を理解する」の公開用スライドです。
イベントに関しては詳しくはこちらをご覧ください。
https://gocon.jp/2025/talks/958952/

参加者特典のお土産はこちらからどうぞ
https://github.com/takehaya/mptcp_playground

Avatar for Takeru Hayasaka

Takeru Hayasaka

September 28, 2025
Tweet

More Decks by Takeru Hayasaka

Other Decks in Programming

Transcript

  1. 目的 - MPTCP の仕組みとポイントを押さえて、MPTCPの活用法を知る - アプリ側から: Go で MPTCP を活用する方法を知る

    - カーネル側から: Linux で MPTCP を活用する方法を知る 背景と目的 背景 - Go 1.24 からは、TCP Listen すると自動的にMPTCPとして動作する - そもそも MPTCP とは何か、Go1.24で何が変わるのかを知る必要がある
  2. - サーバ側: OS が対応していれば 自動で MPTCP Listen - (OSが MPTCP

    非対応なら自動で TCP フォールバック) - クライアント側: 何も変わらない。TCPでDialする場合はTCP接続 明示的にMPTCPを有効化した場合にはMPTCP 接続が可能 - 困る場合: 以下の様なケースだと、無効化しておく判断も必要 - MPTCPが非対応の特定のSocketOption依存 - 無効化方法:コードでoff ListenConfig.SetMultipathTCP(false) または環境変数でoff GODEBUG=multipathtcp=0 TL;DR(Go 1.24 で何が変わる?)
  3. • 早坂 彪流 (Hayasaka Takeru|@takemioIO) • 社会人5年目 • さくらインターネット に所属

    現在は、BBSakura Networksへ出向中 モバイルコアや仮想化基盤の開発・運用を担当 ◦ 前職はゲーム会社でゲーム機のファームを書いていた • 大学院生: JAIST M2 ◦ 長期履修制度でM3までいる予定になっています ...😇 • 好きなgo pkg ◦ cilium/ebpf: ebpfが好き ◦ kelseyhightower/envconfig: ディフォルト値が便利で好き(何もしなくていい) 自己紹介
  4. - Multipath TCP(MPTCP)とは、TCPのマルチパス化技術のことを指す - アプリ側は従来のTCPの使い勝手のまま、下層で複数のTCPコネクション (subflow)を束ねる仕組みを持っている。 - 例えば、複数のNetwork Interfaceを持つクライアントのTCPコネクション を束ねて通信の帯域を拡張し、冗長性を高めることができる

    - 詳しくはこちらを参照 - MPTCP v0: RFC6824 (2013年にRFC化) - MPTCP v1: RFC8684 (2020年にRFC化) - v0は実質的には廃止されて、v1でsubflowの追加の拒否等の状態を示すFlagが 追加されたり、ハンドシェイクが変わってるので何も考えずv1を読むのが良い Multipath TCP(MPTCP)とは
  5. 実際どの様なモノが対応してるのか? - MPTCPv1の開発してるグループの 公式サイトにはLinuxで動くMPTCP対応 してるアプリが載っている - ネットワーク検証ツール: curlやiperf3 - Web

    プロキシ / サーバー: HAProxy, Apache server,Envoy - 仮想化ソフトウェア: QEMU - e.g. Livemigrationなどで使える - KVストア: Valkey - e.g. レプリケーションとかで使える cf. https://www.mptcp.dev/apps.html
  6. TCPとMPTCPの具体的な違いは? TCP - 単一のコネクション、1つのsubflowとも言える - 4Tuple:<local IP, port, remote IP,

    port>で定義 subflow A subflow B subflow C … MPTCP subflowを動的に 追加するシーケンスが必要? MPTCP - 複数のTCPコネクション(subflow)を束ねる - アプリからは1つの TCP socketに見える - TCPと強いコンパチビリティを持つ 疑問 - どの様にコンパチビリティを保ったままネゴシエーションするか? - 既存のsubflowコネクションとしてどの様に紐付けて集約するのか?
  7. step1: init subflow作成(subflow作成&鍵交換) my_key = β your_key = α MPTCPは(互換性のある形で)TCPの3Way

    Handshakeを拡張する ※SYN->SYN+ACK->ACKの形式で基本行なっている my_key = α your_key = β SYN+MP_CAPABLE[flags,keyβ] SYN+ACK+MP_CAPABLE[flags,keyα] ACK+MP_CAPABLE[flags,keyβ,keyα]
  8. step1: init subflow作成(subflow作成&鍵交換) my_key = β your_key = α MPTCPの有効化ネゴシエーションをTryするために、

    MP_CAPABLEというTCP Optionを与えて試行する その時、お互いのNodeたちは鍵生成と交換を行い、最初のsubflowが出来る ※TCP Optionなので、ダメならプレーンTCPにフォールバック my_key = α your_key = β SYN+MP_CAPABLE[flags,keyβ] SYN+ACK+MP_CAPABLE[flags,keyα] ACK+MP_CAPABLE[flags,keyβ,keyα]
  9. step2: token生成をする my_key = β your_key = α mytoken =

    token(β) yourtoken = token(α) my_key = α your_key = β mytoken = token(α) yourtoken = token(β) 鍵交換したものからtokenを生成する。 これが実質的なセッション IDとして使われる。 ※お互いの鍵からtokenは生成可能なのでtokenの交換はしなくて良い ※token(x) := MSB32(sha256(x))
  10. step3: HMACを作りMP_JOINしてsubflowを作る SYN+MP_JOIN[token(α), NonceB] SYN+ACK+MP_JOIN[HMACβ,NonceA] ACK+MP_JOIN[HMACα] my_key = β your_key

    = α mytoken = token(β) yourtoken = token(α) my_key = α your_key = β mytoken = token(α) yourtoken = token(β) 追加のsubflowをMP_JOINを利用して作成する。 MP_CAPABLEと同様にTCP Option上で実現してるので、 互換性のある形でTCPの3Way Handshakeを拡張してる ※HMAC(Secret, Message) = HMAC-SHA256(Secret, Message)
  11. step3: HMACを作りMP_JOINしてsubflowを作る my_key = β your_key = α mytoken =

    token(β) yourtoken = token(α) my_key = α your_key = β mytoken = token(α) yourtoken = token(β) MP_JOINは新しいsubflowを既存のと紐づけるために、Tokenを指定しつつ、 最初に交換したKeyとNonceを材料にHMACを作って提示する。 相手も同じ計算で照合するので、正しい相手でなければJOINは成立しない ※Tokenは偽造しやすいので、HMACで正しいkeyの所持を証明してる ※HMAC(Secret, Message) = HMAC-SHA256(Secret, Message) SYN+MP_JOIN[token(α), NonceB] SYN+ACK+MP_JOIN[HMACβ,NonceA] ACK+MP_JOIN[HMACα]
  12. 2つのsubflowをもつMPTCPの接続が完成! my_key = β your_key = α mytoken = token(β)

    yourtoken = token(α) my_key = α your_key = β mytoken = token(α) yourtoken = token(β) SYN+MP_CAPABLE[flags,keyβ] SYN+ACK+MP_CAPABLE[flags,keyα] ACK+MP_CAPABLE[flags,keyβ,keyα] SYN+MP_JOIN[token(α), NonceB] SYN+ACK+MP_JOIN[HMACβ,NonceA] ACK+MP_JOIN[HMACα]
  13. - MPTCPはTCPと強い互換性をもつプロトコル! - Appleを始めとした会社がモビリティの安定や帯域の集約のために使ってる - MPTCPがsubflowを追加するときはTCPと互換性のある形で拡張して行う - 1. 最初のネゴシエーションで作られるsubflowはどうやってできるのか? =>

    MP_CAPABLEというTCP Optionを加えて実施し、subflowを作る - 2. 2つ目以降のsubflowはどの様に追加されるのか? =>MP_JOINを使って、既存subflowが存在してるセッションに紐づける ここまでのサマリー
  14. - 先ほどのパターンは、以下の図のケースであれば実現可能 - HostAが持つ2つのAddress(A1,A2)を利用 - HostBのInitで接続したAddress(B1)に対して接続を行う - {A1->B1, A2->B1}のsubflow作成は初回の接続情報でTry可能 -

    課題: HostAがHostBの別アドレスに接続したい場合の方法 - e.g. A1->B1へのTupleを作りたい - そもそもホストBが持ってるAddressを HostAは知らないので教える必要がある - では別のIfaceにあるAddressB2に対して subflowを作ることを考えてみよう サーバーが持つ別のAddrを使うには? cf. https://datatracker.ietf.org/doc/html/rfc8684
  15. step4: ADD_ADDRで別のアドレスを通知する ADD_ADDR[Addr=B2,echo=0,HMACβ] my_key = β your_key = α mytoken

    = token(β) yourtoken = token(α) my_key = α your_key = β mytoken = token(α) yourtoken = token(β) ADD_ADDRは、自分が持っているaddressに関して通知をする仕組み サーバーがB2というAddrについて通知をクライアントに行う この時Ackとして受信したADD_ADDRをechoする ※受け取り側だけが正しく検証できれば問題ないので、中身はecho=1にするだけでecho replyする ちなみに同様にREMOVE_ADDRというモノもあります。 自分が持てなくなったアドレスがあるときに教えてあげましょう:) newAddr=B2 ADD_ADDR[Addr=B2,echo=1,HMACβ]
  16. step5: Addr=B2に対してsubflowを作成する my_key = β your_key = α mytoken =

    token(β) yourtoken = token(α) my_key = α your_key = β mytoken = token(α) yourtoken = token(β) 再びMP_JOINすればsubflowが無事作られて、 3つのTCPセッションを実質束ねてる状態になった! newAddr=B2 SYN+MP_JOIN[token(α), NonceB] SYN+ACK+MP_JOIN[HMACβ,NonceA] ACK+MP_JOIN[HMACα]
  17. MPTCP と Middlebox の相性問題 - FWやLB,NATなどは一般にMiddleBoxと呼ばれている - 伝送ポリシーを強制的に適用するためのNetwork装置 - Middleboxが

    MPTCP Optionを理解できず恩恵が得れないパターンも多い - FW (Firewall) - TCP Option を削除 -> MPTCP の制御情報が消える(TCPフォールバックされる) - NAT (Network Address Translation) - NATセッションが切れてしまう場合 add_addrなどでコントロールする必要がある - LB (Load Balancer) - 多くの L4LB はステートレスに動作(特にクラウド環境など...) - Consistent Hash で Per-Flow にサーバーへ振り分ける - MPTCPが分からない装置から見たら普通のTCPなので、別々の通信Flowと見做してしまう - 高確率でMP_JOIN を別のサーバーに送ってしまうので、2本以上のsubflowは持てない😇
  18. LBとMPTCP相性問題のワークアラウンド - cf. draft-duchene-mptcp-load-balancing-01 - 1. LB経由でServerに繋ぎに行く - 2. ServerはMP_CAPABLEをClientと交換し、

    ネゴシエーションを成功させる - 3. ADD_ADDRで持ってるAddressをclientに通知 - 条件: 通知したアドレスはClientから直接到達可能 - 4. clientはそのAddressに対して新規接続を行う - Clientは通知してきたアドレスのみに対してSubflowを 作る戦略にしてあげる(LBを2回以上通せないため) cf. MultipathTCP + 分散型ロードバランサー(2) · hrntknr's blogの図を改訂して利用 Client Server LB subflow init subflow 203.0.113.1 (VIP) 10.0.0.100 203.0.113.2
  19. - Go 1.21(2023): MPTCP サポートが入った。明示的な有効化のみ使用OK - cf. https://github.com/golang/go/issues/56539 - 明示的な有効化方法は2つで、「環境変数

    or コード(後述)」の書き換え - 環境変数: GODEBUG=multipathtcp=<n> - "0": 全体オフ - "1": Dial+Listen Enable - "2": Listen のみEnable - "3": DialのみEnable - cf.https://github.com/golang/go/blob/d7a38adf4c81f0fa83203e37844192182b2268 0a/doc/godebug.md?plain=1#L215 Goでのサポートタイムライン: 1/2
  20. - Go 1.24(2025): TCP ListenのディフォルトがMPTCPのListenになった - GODEBUG=multipathtcp の既定値が 2(ListenのみOnに) -

    ※Go 1.23ではmultipathtcp=1を設定しても正しく動いてない問題があった が、無事修正済み - (バックポートはされない方針なので1.24以降を使う必要がある) - cf.https://github.com/golang/go/commit/97ae1817fb22913f0bbfa0be2b8181e806c 26853 Goでのサポートタイムライン: 2/2
  21. x86のレジスタのマッピング例 呼び出し規約に合致していることがわかる // Server側 func (*ListenConfig) SetMultipathTCP(enabled bool) func (*ListenConfig)

    MultipathTCP() bool // Client側 func (*Dialer) SetMultipathTCP(enabled bool) func (*Dialer) MultipathTCP() bool MPTCPの有効・無効は上記の様な コードを利用して制御することも可能 32
  22. x86のレジスタのマッピング例 呼び出し規約に合致していることがわかる // Client側 d := &net.Dialer{} d.SetMultipathTCP(true) c, err

    := d.Dial("tcp", "host:port") // Server側 lc := &net.ListenConfig{} lc.SetMultipathTCP(true) ln, err := lc.Listen(context.Background(), "tcp", ":8080") 有効化の利用例 33
  23. - MPTCPはだいたいの主要なSocketOptionの実装を満たしているが、、、 一部足りてない機能も存在している - その場合、set_sockoptをした時にENOPROTOOPTを返すケースがある - 実際TCP_MD5 Optionが動かなくて GoBGP というBGPdが動かなくて困った

    ケースがあり、GoBGP側でSetMultipathTCP(false)する対応が入った - このパターンのケースはLinux側にサポートが入らない限り有効化することができない - cf. https://github.com/multipath-tcp/mptcp_net-next/issues/575 - 他のサービスでも動かなくなったと言う報告もある ただし、Socket Optionで特殊なモノは要注意 cf.https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8981 cf.https://github.com/golang/go/issues/74643
  24. x86のレジスタのマッピング例 呼び出し規約に合致していることがわかる static bool mptcp_supported_sockopt(int level, int optname) { if

    (level == SOL_IP) {/* 中略 (Multicast関連等なので基本的に問題にならなさそう ) */} if (level == SOL_IPV6) {/* 中略 (Multicast関連等なので基本的に問題にならなさそう ) */} if (level == SOL_TCP) { /* TCP_MD5SIG, TCP_MD5SIG_EXT are not supported, MD5 is not compatible with MPTCP */ /* TCP_REPAIR, TCP_REPAIR_QUEUE, TCP_QUEUE_SEQ, TCP_REPAIR_OPTIONS, * TCP_REPAIR_WINDOW are not supported, better avoid this mess */ ... } } ちなみにsockoptで問題になるかどうかはlinux kernelの mptcp_supported_sockoptを眺めると対応状況がわかって便利 最新kernelのコメント的には(TCP Optにおいて) CRIUとBGPd関連のアプリを使う時のみ影響が出そう。 37 cf. https://github.com/torvalds/linux/blob/cec1e6e5d1ab33403b809f79cd20d6aff124ccfe/net/mptcp/sockopt.c#L434
  25. - MPTCP socketを利用することで動作可能になる - socket(AF_INET(6), SOCK_STREAM, IPPROTO_MPTCP); - つまり基本的にsocketが使えるならどれでも動く -

    cf. https://github.com/mptcp-apps/mptcp-hello - c, elixir,erlang,python,perl,rustこの辺りの例が載っている。 - ちなみにmacosでも動作するため、objc, swiftなどでも動く - let connection = NWConnection(to: server, using: { let p = NWParameters.tcp; p.multipathServiceType = .handover; return p }()) - macos環境だとベースのKernelがOSSになってるのでMPTCPの実装が見れる - sysctl -a | grep mptcp - cf. http://github.com/apple-oss-distributions/xnu 他のプログラミング言語でのMPTCP利用
  26. - 既存のソフトウェアのTCP Socketを強制的にMPTCP Socketに書き換えて、 動作させる仕組みがある。これでrebuildせずともMPTCPの恩恵が得れる。 - mptcpize: LD_PRELOAD を使って、libcがもつ socket()

    や connect() の 標準のlib関数を横取りして、MPTCP化させることができる - mptcpize run <command> - cf.https://github.com/multipath-tcp/mptcpd/blob/c1951db79f1c7103874061df6b220fb00 a669d62/src/mptcpize.c#L3 - mptcpify: Linux v6.6~で使える, eBPFを使って強制的にMPTCP化させる Androidの様な環境設定やアプリ起動方法を変えづらい環境とかであっても使える 様に改善したモノ - python ./mptcpify.py -t <command> - BPF_CGROUP_INET_SOCK_CREATE でhookして、書き換えている - cf. https://github.com/multipath-tcp/mptcp_net-next/issues/79 - cf. https://github.com/iovisor/bcc/pull/5274 任意のソフトウェアのMPTCP対応
  27. - Linux v5.6 から MPTCPv1がサポートされてる - それ以前はv0(v3.4~)のサポートがされている - 公式ページを見ると、どのLinux Distributionで

    いつぐらいに対応してるのかが分かる - Ubuntuでは22.04, RaspberryPiなら231004 と基本サポートはどのDistributionでも行われて いることが分かる - ※v5.6以降それぞれのマイナーバージョンごとに色々と 機能が追加されてるので厳密なサポートはKernel バージョンごとに異なる - sysctl -w net.mptcp.enabled=1 で MPTCP Socketが作れる様になる LinuxにおけるMPTCP サポート cf. https://www.mptcp.dev/apps.html
  28. - パスマネージャ: subflowの接続の増減を決定する - e.g. initのネゴシエーション終了時に、ADD_ADDRで追加のアドレスを通知することが できるが、これはパスマネージャーの働きで可能になっている - また、MP_JOINする対象をどの様に決めるかのストラテジーをコントロールするのも パスマネージャーのお仕事

    - パケットスケジューラ: どのsubflowを介して送信されるかを決定する - 複数存在するsubflowに対してどれくらいパケットを流し込むかを決めている - 実質的に通信性能を出すための話なので、輻輳制御アルゴリズムの話なども関わります - cf. MPTCPのスケジューラーをeBPFで書けるようになった話 - BBSakura Networks Blog - eBPFで改造可能になった話を以前書いたので興味あればぜひ MPTCPを成り立たせるための機能
  29. パスマネージャーを使ったsubflowの追加方法 - 手動でsubflowを増やす - 自動でMP_JOINを行う例 - sudo ip mptcp limits

    set subflow 2 add_addr_accepted 2 - 自分から作れる subflow は 3 本まで(= init1 + subflow2 = 最大3本の同時フロー) - 相手から受け入れる追加アドレスは 2 個まで - subflow: 1セッションで最大何本までsubflowを作るか - add_addr_accepted: 1セッションのピア受け入れるADD_ADDRの数 - MP_JOINする例(手動でインタフェースをsubflowとして追加できる) - sudo ip mptcp endpoint add 198.51.100.20 dev wlan0 subflow - サーバが受け入れ可能 (add_addr_accepted > 0) ならsubflowが追加される - アドレスの通知をする - ADD_ADDRの例(追加のアドレスを通知する) - sudo ip mptcp endpoint add 192.0.2.10 dev eth1 signal - signalではなくbackupにすると予備のパスとして広告しないで待機させてくれる 例えばメインのsubflowが死んだ時に切り替えてくれる
  30. LBとMPTCP相性問題のワークアラウンド - cf. draft-duchene-mptcp-load-balancing-01 - 1. LB経由でServerに繋ぎに行く - 2. ServerはMP_CAPABLEをClientと交換し、

    ネゴシエーションを成功させる - 3. ADD_ADDRで持ってるAddressをclientに通知 - 条件: 通知したアドレスはClientから直接到達可能 - 4. clientはそのAddressに対して新規接続を行う - Clientは通知してきたアドレスのみに対してSubflowを 作る戦略にしてあげる(LBを2回以上通せないため) cf. MultipathTCP + 分散型ロードバランサー(2) · hrntknr's blogの図を改訂して利用 Client Server LB subflow init subflow 203.0.113.1 (VIP) 10.0.0.100 203.0.113.2 再掲
  31. MPTCPをLBに対応させる例 - 初回の宛先はLBのVIPなので、そこに別のsubflowを流そうとするとMP_JOIN が失敗する。そこでLBを通るVIPに新規subflowを作らないことにする. そこで、Serverで以下のことを実現したい - 1. 初回Subflowを行ったpathにはMP_JOINをさせない要求設定を渡す - 2.

    Clientから直接到達可能な自サーバのaddrをADD_ADDRで渡す 1. sysctl -w net.mptcp.allow_join_initial_addr_port=0 2. ip mptcp endpoint add <SERVER_IP> dev <IF> signal 公式でも同様の紹介がなされている ※公式では、LB配下にサーバーを並べれるように変更されていて、 その代わりにLB->Server間にはStaticなPortForwardの様なことを 入れれるLB実装の前提で書いている。どちらも肝はclientから Serverに対して確実に疎通できるaddr:portの組み必要なのがわかる cf. https://www.mptcp.dev/load-balancer.html Client Server LB subflow init subflow 203.0.113.1 (VIP) 10.0.0.100 203.0.113.2
  32. Appendix-B: MPTCP自体をさらに知りたい人向け - SIGCOMM’20 Tutorial Multipath Transport Protocols - MPTCPのLinux版実装を作ってるUCLouvainの人たちがSIGCOMMでやってたtutorial

    Workshopの資料。網羅的で神。 - https://mptcp-apps.github.io/mptcp-doc/index.html - ユースケースからどういう思想なのかがざっくりまとまってるMPTCPの開発者向けの チュートリアルドキュメント - FOSDEM 23: MPTCP Upstream - Linuxを中心に実装において最近どんな感じなのか書いてる。過去の歴史パートが面白い。 - https://github.com/multipath-tcp/mptcp_net-next/wiki - 開発者ドキュメントwiki, ChangeLogにv5.6~からどういうものがupdateされてるのかが 載ってる。例えばスケジューラーのeBPFのサポートとか最近になったことが窺える。 - ちなみに最新の開発の進行具合はProjectBoardを見るのがおすすめ
  33. MPTCP Option Format - RFC8684 - MPTCP はTCP Option として表現されている

    - MPTCPの制御情報を送る仕組み - Kind: 30(MPTCP) - Subtype: MP_CAPABLE みたい なOptionが入る 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+-----------------------+ | Kind | Length |Subtype| | +---------------+---------------+-------+ | | Subtype-specific data | | (variable length) | +---------------------------------------------------------------+
  34. Multipath Capable (MP_CAPABLE) Option - Kind: MPTCP(30) - Length -

    Subtype: MP_CAPABLE - Version: v1 - flags - A: Csum required - B: Extensibilityは0 - C: Do not attempt to establish new subflows to the source address. - D-G: Unassigned - H: HMAC-SHA256 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+-------+---------------+ | Kind | Length |Subtype|Version|A|B|C|D|E|F|G|H| +---------------+---------------+-------+-------+---------------+ | Option Sender's Key (64 bits) | | (if option Length > 4) | | | +---------------------------------------------------------------+ | Option Receiver's Key (64 bits) | | (if option Length > 12) | | | +-------------------------------+-------------------------------+ | Data-Level Length (16 bits) | Checksum (16 bits, optional) | +-------------------------------+-------------------------------+
  35. Join Connection (MP_JOIN) Option (for Initial SYN) - Kind: MPTCP(30)

    - Length: 12 - Subtype: MP_JOIN - flags - B: バックアップパスにす るかどうか(1 or 0) - AddressID: NATでアドレスが変 わってもわかる様にするID - Recv TokenID - Send Rand(Nance) 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+-----+-+---------------+ | Kind | Length = 12 |Subtype|(rsv)|B| Address ID | +---------------+---------------+-------+-----+-+---------------+ | Receiver's Token (32 bits) | +---------------------------------------------------------------+ | Sender's Random Number (32 bits) | +---------------------------------------------------------------+
  36. Join Connection (MP_JOIN) Option (for Responding SYN/ACK) - Kind: MPTCP(30)

    - Length: 16(長さで区別する) - Subtype: MP_JOIN - flags - B: バックアップパスにす るかどうか(1 or 0) - AddressID: NATでアドレスが変 わってもわかる様にするID - Sender HMAC - Send Rand(Nance) 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+-----+-+---------------+ | Kind | Length = 16 |Subtype|(rsv)|B| Address ID | +---------------+---------------+-------+-----+-+---------------+ | | | Sender's Truncated HMAC (64 bits) | | | +---------------------------------------------------------------+ | Sender's Random Number (32 bits) | +---------------------------------------------------------------+
  37. Join Connection (MP_JOIN) Option (for Initiator's First ACK) - Kind:

    MPTCP(30) - Length: 24(長さで区別する) - Subtype: MP_JOIN - Sender HMAC(160bit) 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+-----------------------+ | Kind | Length = 24 |Subtype| (reserved) | +---------------+---------------+-------+-----------------------+ | | | | | Sender's Truncated HMAC (160 bits) | | | | | +---------------------------------------------------------------+
  38. Add Address (ADD_ADDR) Option - Kind: MPTCP(30) - Length -

    Subtype: ADD_ADDR - flags - E: echo flag(replyで1) - Address (v4:4oct or v6:16 oct) - Port(2oct) - HMAC 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+-------+---------------+ | Kind | Length |Subtype|(rsv)|E| Address ID | +---------------+---------------+-------+-------+---------------+ | Address (IPv4: 4 octets / IPv6: 16 octets) | +-------------------------------+-------------------------------+ | Port (2 octets, optional) | | +-------------------------------+ | | Truncated HMAC (8 octets, if E=0) | | +-------------------------------+   | |   +-------------------------------+
  39. Data Sequence Signal (DSS) Option - Kind: MPTCP(30) - Length

    - Subtype: DSS - flags - F: datefin(データの終わ りを示す) - m: DSNが8oct - M:DSN,SSN,Dlvl,Csumが 存在する - a:Data Ackがある - A:DataAckは8oct - Data ACK - Data SeqNum - Subflow SeqNum - Data Level - Csum 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+----------------------+ | Kind | Length |Subtype| (reserved) |F|m|M|a|A| +---------------+---------------+-------+----------------------+ | Data ACK (4 or 8 octets, depending on flags) | +--------------------------------------------------------------+ | Data Sequence Number (4 or 8 octets, depending on flags) | +--------------------------------------------------------------+ | Subflow Sequence Number (4 octets) | +-------------------------------+------------------------------+ | Data-Level Length (2 octets) | Checksum (2 octets) | +-------------------------------+------------------------------+
  40. LBとMPTCP相性問題のワークアラウンドその2:1/3 - なるべく普通のMPTCPのLB対応を考えたい - ありそうな要件 - LB配下にServerを全て置きたい - セキュリティ的にGlobalアドレスを直接晒したくない -

    単一のNICで実現したい - コンテナとかで扱いたいためワンアーム構成にしたい - 考え方 - Serverに対して確実に疎通できる接続Endpointが提供 出来れば2本目以上のSubflowが作れる - 登場人物 - Client: 2つのAddrを持つ - LB: 1つのVIPを持つ - Server: 1つのAddrを持つ Client Server LB subflow init subflow 203.0.113.1 (VIP) 10.0.0.100 203.0.110.1 203.0.110.2
  41. LBとMPTCP相性問題のワークアラウンドその2:2/3 - 導入したい制約 - 1. 初回Subflowを行ったpathにはMP_JOINをさせない要求設定を渡す - 2. Clientから直接到達可能な自サーバのaddrとportをADD_ADDRで渡す -

    3. LBに対してaddr:portが来た時はサーバーに対してportforward - 1.init subflowはECMPしてLBしてサーバー接続して ネゴシエーションを完了させる - 2. サーバーはVIPとportをクライアントに通知 - 事前に通知するportを決めて、そのportに対応するサーバーは一台 だけに絞っておく、それでadd_addrする - 3. クライアントは、subflowを作るために通知されたVIP とportでLBに繋ぎに行ってサーバーと接続して ネゴシエーションを完了させる Client Server LB subflow init subflow 203.0.113.1 (VIP) 10.0.0.100:80 203.0.110.1 203.0.110.2 10.0.0.100:8081
  42. LBとMPTCP相性問題のワークアラウンドその2:3/3 Client - 実際にどの様に設定を入れる考える - 1. sysctl -w net.mptcp.allow_join_initial_addr_port=0 -

    2. ip mptcp endpoint add <SERVER_IP> dev <IF> [ port <NR> ] signal - 3. port forwardを追加する - nginxのパターンはupstream一つに絞ってproxypassでOK - cf.https://docs.nginx.com/nginx/admin-guide/load-balancer/t cp-udp-load-balancer/#proxy_pass - 他のクラウドLBでもupstream一つに絞ってproxypassで良いけど、 HealthCheckに関しては別のportを指定できるものである必要がありそう - ここで考えた方法はLB配下に置くことでも実現できるが、 サーバーNodeのスケールという観点だとやや厳しいので、 この部分には課題がありそうに見える... Server LB subflow init subflow 203.0.113.1 (VIP) 10.0.0.100:80 203.0.110.1 203.0.110.2 10.0.0.100:8081