最近知ったholo routing. rustで書かれたルーティングスイートである.

build

とりあえずbuildしてみよう。 https://github.com/holo-routing/holo/blob/master/INSTALL.md を参考にソースコードを取得して、

$ git clone https://github.com/holo-routing/holo.git
# apt-get install build-essential cmake libpcre2-dev protobuf-compiler
$ cd holo/
$ cargo build --release

を行うとyang関連で失敗します。よく読むと、

Holo uses unstable Rust features, so building it from the source code requires a nightly version of the Rust compiler.

と書いてありnightlyにしないといけないようです。 https://qiita.com/object-kazuAtGitHub/items/a24cc8a833f4663ad4b2 の記事を参考にnightlyの環境を作ります。

  rustup update
  rustup override set nightly
  rustup self update
  rustup update nightly

これを行った後に、cargo build --releaseを再度行ったところコンパイルが出来ました。作成されたファイルを見てみるとどうやらholodholo-cliというバイナリができてます。Zebra/Quagga/FRRみたいにプロトコル毎にプロセスが分かれないんですね。1プロセスで動作するという意味でコンテナ向きだけど、複数組み合わせて動くマイクロサービス感はない。

ls holo/target/release/
build  deps  examples  holo-cli  holo-cli.d  holod  holod.d  incremental  libholo_ospf.d  libholo_ospf.rlib

containerlab

ビルドしてみたのはいいけど、動作確認にはネットワーク組まないといけない。というわけでcontainerlabで動かすことにしました。 containerlabのインストールは https://containerlab.dev/quickstart/ の通りです。

# download and install the latest release (may require sudo)
bash -c "$(curl -sL https://get.containerlab.dev)"

あとは https://github.com/holo-routing/containerlab-topologies に記載の通りです。

git clone git clone https://github.com/holo-routing/containerlab-topologies.git

ブリッジを作ります

$ sudo ip link add br1 type bridge
$ sudo ip link set dev br1 up

OSPFを試してみようと思います。

$ cd containerlab-topologies
$ sudo containerlab deploy -c --topo ospfv2/topology.yml

ですが、私の環境では失敗しました。eth0とeth1が既に存在しているため、br1に括り付ける新規インタフェースが異なるためと推測し、topology.ymlでインタフェースの括り付けを変更すると動作しました。

-    - endpoints: ["rt1:eth1", "br1:eth1"]
-    - endpoints: ["rt2:eth1", "br1:eth2"]
-    - endpoints: ["rt3:eth1", "br1:eth3"]
+    - endpoints: ["rt1:eth1", "br1:eth2"]
+    - endpoints: ["rt2:eth1", "br1:eth3"]
+    - endpoints: ["rt3:eth1", "br1:eth4"]

動いた状態で、以下のコマンドでdocker内部のshell(bash)をとります。

sudo docker exec -it clab-ospfv2-rt1 bash

動作しているプロセスを見てみます。コンテナ内にpsコマンドがないため代替手段(https://pet2cattle.com/2021/12/docker-ps-command-not-found)を使いました。holodしか動いていないみたいです。

root@rt1:/# for proc in /proc/*/cmdline; do echo $(basename $(dirname $proc)) $(cat $proc | tr "\0" " "); done
1 sh -c holod 2>> /tmp/holod.err
194 bash
7 holod
self cat /proc/self/cmdline
thread-self cat /proc/thread-self/cmdline

経路表を見てみます。トポロジ(https://github.com/holo-routing/containerlab-topologies/blob/master/ospfv2/topology.yml)通りのOSPFの経路がインストールされています。

root@rt1:/# ip route
default via 172.20.20.1 dev eth0
2.2.2.2 via 10.0.1.2 dev eth1 proto ospf
3.3.3.3 via 10.0.1.3 dev eth1 proto ospf
4.4.4.4 via 10.0.1.2 dev eth1 proto ospf
5.5.5.5 via 10.0.1.3 dev eth1 proto ospf
6.6.6.6 via 10.0.1.3 dev eth1 proto ospf
10.0.1.0/24 dev eth1 proto kernel scope link src 10.0.1.1
10.0.2.0/24 via 10.0.1.2 dev eth1 proto ospf
10.0.3.0/24 via 10.0.1.2 dev eth1 proto ospf
10.0.4.0/24 via 10.0.1.3 dev eth1 proto ospf
10.0.5.0/24 via 10.0.1.3 dev eth1 proto ospf
10.0.6.0/24 via 10.0.1.3 dev eth1 proto ospf
10.0.7.0/24 via 10.0.1.2 dev eth1 proto ospf
10.0.8.0/24 via 10.0.1.3 dev eth1 proto ospf
172.20.20.0/24 dev eth0 proto kernel scope link src 172.20.20.3

それではholo内のRIBはどうなっているんでしょうか?holo-cliを使ってみましょう。 インタラクティブにはholo-cliを打って、holo-cli内で、show state xpath /ietf-routing:routing/ribsを打つのですが、今回は-cオプションを使って1コマンドで出力させています。

root@rt1:/# holo-cli -c show state xpath /ietf-routing:routing/ribs

結果は以下になりました。

{
  "ietf-routing:routing": {
    "ribs": {
      "rib": [
        {
          "name": "ipv4",
          "routes": {
            "route": [
              {
                "route-preference": 0,
                "source-protocol": "direct",
                "active": [null],
                "last-updated": "2023-12-24T13:15:06.822702766+00:00",
                "ietf-ipv4-unicast-routing:destination-prefix": "1.1.1.1/32"
              },
              {
                "route-preference": 110,
                "next-hop": {
                  "ietf-ipv4-unicast-routing:next-hop-address": "10.0.1.2"
                },
                "source-protocol": "ietf-ospf:ospfv2",
                "active": [null],
                "last-updated": "2023-12-24T13:15:18.994319097+00:00",
                "ietf-ipv4-unicast-routing:destination-prefix": "2.2.2.2/32"
              },
              {
                "route-preference": 110,
                "next-hop": {
                  "ietf-ipv4-unicast-routing:next-hop-address": "10.0.1.3"
                },
                "source-protocol": "ietf-ospf:ospfv2",
                "active": [null],
                "last-updated": "2023-12-24T13:15:18.994539254+00:00",
                "ietf-ipv4-unicast-routing:destination-prefix": "3.3.3.3/32"
              },
              {
                "route-preference": 110,
                "next-hop": {
                  "ietf-ipv4-unicast-routing:next-hop-address": "10.0.1.2"
                },
                "source-protocol": "ietf-ospf:ospfv2",
                "active": [null],
                "last-updated": "2023-12-24T13:15:18.994540616+00:00",
                "ietf-ipv4-unicast-routing:destination-prefix": "4.4.4.4/32"
              },
              {
                "route-preference": 110,
                "next-hop": {
                  "ietf-ipv4-unicast-routing:next-hop-address": "10.0.1.3"
                },
                "source-protocol": "ietf-ospf:ospfv2",
                "active": [null],
                "last-updated": "2023-12-24T13:15:18.994788445+00:00",
                "ietf-ipv4-unicast-routing:destination-prefix": "5.5.5.5/32"
              },
              {
                "route-preference": 110,
                "next-hop": {
                  "next-hop-list": {
                    "next-hop": [
                      {
                        "ietf-ipv4-unicast-routing:address": "10.0.1.2"
                      },
                      {
                        "ietf-ipv4-unicast-routing:address": "10.0.1.3"
                      }
                    ]
                  }
                },
                "source-protocol": "ietf-ospf:ospfv2",
                "active": [null],
                "last-updated": "2023-12-24T13:15:18.994790479+00:00",
                "ietf-ipv4-unicast-routing:destination-prefix": "6.6.6.6/32"
              },
              {
                "route-preference": 0,
                "source-protocol": "direct",
                "active": [null],
                "last-updated": "2023-12-24T13:15:06.822697496+00:00",
                "ietf-ipv4-unicast-routing:destination-prefix": "10.0.1.0/24"
              },
              {
                "route-preference": 110,
                "next-hop": {
                  "ietf-ipv4-unicast-routing:next-hop-address": "10.0.1.2"
                },
                "source-protocol": "ietf-ospf:ospfv2",
                "active": [null],
                "last-updated": "2023-12-24T13:15:18.994791161+00:00",
                "ietf-ipv4-unicast-routing:destination-prefix": "10.0.2.0/24"
              },
              {
                "route-preference": 110,
                "next-hop": {
                  "ietf-ipv4-unicast-routing:next-hop-address": "10.0.1.2"
                },
                "source-protocol": "ietf-ospf:ospfv2",
                "active": [null],
                "last-updated": "2023-12-24T13:15:18.994791832+00:00",
                "ietf-ipv4-unicast-routing:destination-prefix": "10.0.3.0/24"
              },
              {
                "route-preference": 110,
                "next-hop": {
                  "ietf-ipv4-unicast-routing:next-hop-address": "10.0.1.3"
                },
                "source-protocol": "ietf-ospf:ospfv2",
                "active": [null],
                "last-updated": "2023-12-24T13:15:18.994792503+00:00",
                "ietf-ipv4-unicast-routing:destination-prefix": "10.0.4.0/24"
              },
              {
                "route-preference": 110,
                "next-hop": {
                  "ietf-ipv4-unicast-routing:next-hop-address": "10.0.1.3"
                },
                "source-protocol": "ietf-ospf:ospfv2",
                "active": [null],
                "last-updated": "2023-12-24T13:15:18.996033332+00:00",
                "ietf-ipv4-unicast-routing:destination-prefix": "10.0.5.0/24"
              },
              {
                "route-preference": 110,
                "next-hop": {
                  "next-hop-list": {
                    "next-hop": [
                      {
                        "ietf-ipv4-unicast-routing:address": "10.0.1.2"
                      },
                      {
                        "ietf-ipv4-unicast-routing:address": "10.0.1.3"
                      }
                    ]
                  }
                },
                "source-protocol": "ietf-ospf:ospfv2",
                "active": [null],
                "last-updated": "2023-12-24T13:15:18.996035556+00:00",
                "ietf-ipv4-unicast-routing:destination-prefix": "10.0.6.0/24"
              },
              {
                "route-preference": 110,
                "next-hop": {
                  "ietf-ipv4-unicast-routing:next-hop-address": "10.0.1.2"
                },
                "source-protocol": "ietf-ospf:ospfv2",
                "active": [null],
                "last-updated": "2023-12-24T13:15:18.996036558+00:00",
                "ietf-ipv4-unicast-routing:destination-prefix": "10.0.7.0/24"
              },
              {
                "route-preference": 110,
                "next-hop": {
                  "ietf-ipv4-unicast-routing:next-hop-address": "10.0.1.3"
                },
                "source-protocol": "ietf-ospf:ospfv2",
                "active": [null],
                "last-updated": "2023-12-24T13:15:18.996484015+00:00",
                "ietf-ipv4-unicast-routing:destination-prefix": "10.0.8.0/24"
              }
            ]
          }
        },
        {
          "name": "ipv6",
          "routes": {
            "route": [
              {
                "route-preference": 0,
                "source-protocol": "direct",
                "active": [null],
                "last-updated": "2023-12-24T13:14:51.471248652+00:00",
                "ietf-ipv6-unicast-routing:destination-prefix": "fe80::/64"
              }
            ]
          }
        },
        {
          "name": "mpls"
        }
      ]
    }
  }
}