NetplanだけでデュアルWANにVPNを通してリンクアグリゲーションを実現したい!

# 注釈

**本論では特に明示しておらず、後で気がついたのですが、Netoplan(netplan.io)と一緒にWireguard(wireguard)とopenvswitch(openvswitch-switch)を先にインストールする必要があります。**
**また、TCPではなくUDP通信になりますので、UDP通信に起因する輻輳問題等が降りかかってくるものと思ってください。**

# 前提

2024年夏、筆者は色々試した結果、一つの問題に直面していました。

**「ぶっちゃけMPTCP化したSoftEtherVPNだったりMLVPNだったりを使ってインターネット回線を2本束ねてVultrと疎通を取っても、思った程スループット伸びないよね。なんなら時々自分のサイトの画像ロードが遅かったり、帯域もレイテンシも十分にあるはずなのにどうもパケロスしてるっぽいし」**

特に通信のやり直しが発生しているあたりが致命的です。

元々「ひかり電話が必要なので回線を引いたので序でにその帯域を使って、(やや)IPoE回線としてはVultrとのスループットが振るわない傾向にある、自宅マンションの無料インターネット回線の遅さを補えないかな？　というところが出発点なのに、 **却ってスループットが振るわない&レスポンスが悪化している** のではそんなに意味がありません。

あとリアルで色々あって、色々扱うソフトウェアが増殖してきて、管理が煩雑になってもいました。**やる事が……やる事が多い……!**

というわけで色々考え、

+ この際スループットが振るわないのは諦めるけど、パケロスは許せない
+ 2回線あるんだからちゃんとどちらかが断しても通信し続けられて、そこそこスループットがきちんと出る冗長構成を取りたい
+ あれこれ試して管理対象が増えてリソースが取られているのをなんとかしたい

以上３点の改善に取り組むことにしました(※毎回それで結局新たなソリューション導入して管理対象を増やしていた事実は忘れるものとする)。

# 設計

兎に角管理対象を減らしたい。つまり設定ファイルは一つに集約しておきたい。

ふむ……Netplanなら確かWireguardとVXLANを取り扱えた筈だから、ルーターのNetplanを弄って **VXLAN over Wireguard** すればセキュリティ強度も高くて尚且つ自宅サーバーのDMZネットワークをL2延伸できるんじゃないか？(※連日の猛暑で茹った頭で見切り発車

で、出来上がったNetplanがこちらです。

```/etc/netplan/99-init-network.yaml
network:
  renderer: networkd
  version: 2
  ethernets:
    eth0: #マンションの無料インターネット回線との接続用インターフェイス
      accept-ra: false
      addresses:
      - '<マンションの無料インターネット回線のルーターから振り出されたIPv6アドレス>/64'
      dhcp4: true
      dhcp6: false
      mtu: 1460
      nameservers:
        addresses: []
      optional: true
      routes:
      - to: default
        via: '<マンションの無料インターネット回線のルーターのリンクローカルアドレス>'
      routes:
      - to: '<Vultrが待ち受けているIPv6アドレス1>'
        via: '<マンションの無料インターネット回線のルーターのリンクローカルアドレス>'
    eth1: #VDSLとの接続用インターフェイス
      accept-ra: false
      addresses:
      - '<ひかり電話(VDSL)HGWから振り出されたIPv6アドレス>/64'
      dhcp4: false
      dhcp6: false
      mtu: 1460
      nameservers:
        addresses: []
      optional: true
      routes:
      - to: '<Vultrが待ち受けているIPv6アドレス2>'
        via: '<HGWのリンクローカルアドレス>'
    eth2: #LANのブリッジ用インターフェイス
      accept-ra: false
      dhcp4: false
      dhcp6: false
      mtu: 1460
      optional: true
    eth3: #DMZのブリッジ用インターフェイス
      accept-ra: false
      dhcp4: false
      dhcp6: false
      mtu: 1280
      optional: true
  tunnels:
    vxlan1:
      mode: vxlan
      local: <ルーター側のWireguard1が持つIPアドレス>
      remote: <Vultr側のWireguard1が持つIPアドレス>
      id: 100
      link: wireguard1
      mtu: 1330
      optional: true
      port: 4649
    vxlan2:
      mode: vxlan
      local: <ルーター側のWireguard2が持つIPアドレス>
      remote: <Vultr側のWireguard2が持つIPアドレス>
      id: 101
      link: wireguard2
      mtu: 1330
      optional: true
      port: 4649
    wireguard1:
      mode: wireguard
      local: '<マンションの無料インターネット回線のルーターから振り出されたIPv6アドレス>'
      key: '<Wireguard1用にルーターで生成したプライベートKey>'
      port: 4649
      addresses: [ <ルーター側のWireguard1が持つIPアドレス>/24 ]
      peers:
      - allowed-ips: [ <Vultr側のWireguard1が持つIPアドレス>/24 ]
        endpoint: '[<Vultrが待ち受けているIPv6アドレス1>]:4649'
        keepalive: 25
        keys:
          public: '<Wireguard1用にVultr側で生成したパブリックKey>'
      mtu: 1330
      optional: true
    wireguard2:
      mode: wireguard
      local: '<ひかり電話(VDSL)HGWから振り出されたIPv6アドレス>'
      key: '<Wireguard2用にルーターで生成したプライベートKey>'
      port: 4670
      addresses: [ <ルーター側のWireguard2が持つIPアドレス>/24 ]
      peers:
      - allowed-ips: [ <Vultr側のWireguard2が持つIPアドレス>/24 ]
        endpoint: '[<Vultrが待ち受けているIPv6アドレス2>]:4670'
        keepalive: 25
        keys:
          public: '<Wireguard2用にVultr側で生成したパブリックKey>'
      mtu: 1330
      optional: true
  bridges:
    bridge2:
      interfaces:
      - eth2
      accept-ra: false
      addresses:
      - <LANのアドレス帯のIP>/22
      dhcp4: false
      dhcp6: false
      mtu: 1460
      nameservers:
        addresses: [ '::1', 127.0.0.1 ]
      optional: true
    bridge3:
      interfaces:
      - eth3
      - vxbond0
      accept-ra: false
      addresses:
      - <DMZのアドレス帯のIP>/22
      dhcp4: false
      dhcp6: false
      mtu: 1280
      optional: true
  bonds:
    vxbond0:
      interfaces:
      - vxlan1
      - vxlan2
      accept-ra: false
      dhcp4: false
      dhcp6: false
      mtu: 1280
      openvswitch:
        lacp: active
      parameters:
        lacp-rate: fast
        mii-monitor-interval: 1s
        mode: balance-tcp
        transmit-hash-policy: layer2
      optional: true
```

:::note alert

**※IPアドレスやポートは飽く迄も例ですので適当に置き換えてお読みください。**

:::

# 解説

上掲のNetplanで重要なポイントは5つです。

:::note info

+ Vultr(または他のVPS/クラウドサービス)が待ち受けているIPアドレス2つに対し、**それぞれ別のルートを強制する**
+ その上で **Wireguardのローカル側アドレスを明示する**
+ **Wireguardは違うIPをローカル側に設定して待ち受けていてもポート番号が被っていると繋がらない** のでポート番号はずらす
+ **VXLANとWireguardをLink** させる
+ bondインターフェイスで**Key「openvswitch」を宣言してLACPの設定を入れる**

:::

Wireguardの中にVXLANを通すまでは大して難しくないと思います。

**最大の難関はVXLANをbondインターフェイスで1つに纏めた時に、インターフェイスがNO-CARIIER(接続されているワイヤーがない≒オフライン)と認識され、bondインターフェイスに纏められたVXLANの向こうで対向している筈のクラウド側のbondインターフェイスと疎通が取れなくなる** 点だと思います。

これをどうにかしてシステム的にオンラインだと認識させ、対向している筈のクラウド側のbondインターフェイスとL2接続させなければいけない訳です。

結論から言えば、これは**bondインターフェイスをOpenvswitch(通常、Netplanを使っているなら一緒にインストールされている筈です)に接続**してやれば解決します。

設定は難しくありません。Netplanのbondインターフェイスで、「#<-この行」と示した箇所

```/etc/netplan/99-init-network.yaml
  bonds:
    vxbond0:
      interfaces:
      - vxlan1
      - vxlan2
      accept-ra: false
      dhcp4: false
      dhcp6: false
      mtu: 1280
      openvswitch: #<-この行
        lacp: active #<-この行
      parameters:
        lacp-rate: fast
        mii-monitor-interval: 1s
        mode: balance-tcp
        transmit-hash-policy: layer2
      optional: true
```

を記述するだけです。**ね、簡単でしょう？~~(見つけるまでのトライアンドエラーが大変だったけど)~~**

あとはVultr(クラウド)側でもほぼ同様のNetplanを書いて適用し、Wireguardが2本とその中を通るVXLAN 2本がオンラインになるのを待つだけです。

Openvswitchに収容されたbondインターフェイスは一見、**ipコマンドからは見えなくなりますが** 、代わりに **ovs-appctl** コマンドで確認することが出来ます。

```shell
sudoer@vmname:~$ sudo ovs-appctl lacp/show vxbond0
---- vxbond0 ----
  status: active negotiated
  sys_id: <MAC ADDRESS>
  sys_priority: 65534
  aggregation key: 1
  lacp_time: slow

member: vxlan1: current attached
  port_id: 1
  port_priority: 65535
  may_enable: true

  actor sys_id: <MAC ADDRESS>
  actor sys_priority: 65534
  actor port_id: 1
  actor port_priority: 65535
  actor key: 1
  actor state: activity aggregation synchronized collecting distributing

  partner sys_id: <MAC ADDRESS>
  partner sys_priority: 65534
  partner port_id: 2
  partner port_priority: 65535
  partner key: 1
  partner state: aggregation synchronized collecting distributing

member: vxlan2: current attached
  port_id: 2
  port_priority: 65535
  may_enable: true

  actor sys_id: <MAC ADDRESS>
  actor sys_priority: 65534
  actor port_id: 2
  actor port_priority: 65535
  actor key: 1
  actor state: activity aggregation synchronized collecting distributing

  partner sys_id: <MAC ADDRESS>
  partner sys_priority: 65534
  partner port_id: 1
  partner port_priority: 65535
  partner key: 1
  partner state: aggregation synchronized collecting distributing
```

こんな感じですね。不可視のように見えてちゃんと実在していますので、これをbridgeインターフェイスに収容してやっていれば疎通が取れる筈です。

# 総括

:::note info

**「NetplanだけでデュアルWANにVPNを通してリンクアグリゲーションまで実現」は可能であると実証できた**

:::

:::note info

**VXLAN over Wireguard を更にbondingしたことによって、VPNのスループットが著しく向上し、レイテンシは低下し、パケロス率も減り、bondingなのでどちらのWAN回線が断たれても通信し続ける事ができるようになった**

(※実験結果は特に書いていませんが、太い方の回線(マンション共有無料インターネット回線。帯域は太いがレイテンシがVDSLの倍ぐらいかかる)が通信経路に選択された場合で大体TCPベースで30Mbps -> 150Mbps、UDPベースで80Mbps -> 210Mbps(瞬間的には300Mbps)ぐらい露骨に向上しています)

(※VDSLが通信経路に選択された場合は概ねUDP/TCP共に85〜90Mbpsで律速されます)

:::

:::note info

**上掲の結果を以て、「MPTCP化したSoftEtherVPN」や「MLVPN」などの、非公式だったりほぼサポートされていなかったりするVPNソフトウェアの管理・使用を停止する事が出来る目処が立った**

:::