BGP backbone を RFC5549 を使って OSPFv3+iBGP over IPv6 だけで構築する

:::note info
この記事では，IPv6 のみを使って iBGP のバックボーンを構築し，かつ RFC5549 を使って IPv4 のルーティングもできるようにする方法を説明します。
:::

今まで，Clos アーキテクチャなど，データセンタ内部のネットワークを (e)BGP で構築し，BGP unnumbered にする方法の記事は多かったが，ISP などのバックボーンで RFC5549 を使うための情報が少なかったので，記事にしてみました。

## 動機
* AS 内の BGP backbone (ISP などの) は，ただでさえ OSPF (IGP) と iBGP の両方を使うことが多いのに，OSPFv2 (IPv4)，OSPFv3 (IPv6)，BGP (IPv4)，BGP (IPv6) の合計4つのルーティングプロトコルの接続をしないといけないのはシンプルじゃないので何とかしたい
* BGP backbone では，通常ルータ間のリンクに通常 `/31` の IPv4 アドレスを割り当ててリンクひとつあたり 2 個のグローバル IPv4 アドレスを消費してしまう。ルータが増えると，ルータ間のリンクが爆発的に増えるので，これは後発の事業者で IPv4 アドレスをあまり持っていないところにはつらい
* かといって，IPv4 を無くすわけにはいかない

## 解決法
* IGP としては，バックボーンでは OSPFv3 (IPv6) のみを走らせ，iBGP と併用する
* バックボーンのルータは，外部との接続を除き，基本的にループバックインタフェースのみにグローバル IP アドレスを割り当てる。OSPFv3 は， IPv6 のリンクローカルアドレスで動作する。これにより，**各ルータに割り当てられる IPv4 アドレスはループバックアドレス1個のみとなる**
* OSPFv3 はバックボーン内部でループバックインタフェースの IPv6 アドレスへの疎通性を確保するために使用する
* 従来通り，iBGP のピアはループバックインタフェースのアドレスで設定するが，IPv6 のみでピアを張る。IPv4 のルーティングは，**RFC5549** を利用して，IPv6 のリンクローカルアドレスをネクストホップとする経路を広告する
* AS の外からは通常通りに見えるほか， IPv4 で traceroute などを走らせても，ループバックに設定した IPv4 アドレスが表示されることにより通常の疎通性が確保される (ループバックの IPv4 アドレスはこのために，またルータに IPv4 の接続性を持たせるために必要)

## 前提とした条件
かならずしもこのようにする必要があるわけではありませんが，我々はこのアーキテクチャを実際に採用するにあたって以下の条件を採用することにしました。

<details>
<summary>バックボーンネットワークと組織内部のネットワークを分離</summary>

* ISP 的なインターネット接続を提供するバックボーンと，組織内部の自己消費用のネットワークを分離し，eBGP で接続 (この場合は，どちらも同じ組織が運用するので， BGP unnumbered でよい)
* インターネットフルルートはバックボーンのみが持ち，組織内部のネットワークに対しては eBGP でデフォルトルートのみを広告する (default-originate)

</details>

<details>
<summary>サービス用のネットワークとマネジメント用のネットワークを分離</summary>

* 各サイトにつき，バックボーン用と内部ネットワーク用の(最低)2個のマネジメントネットワークのサブネットを作り，マネジメントネットワークにはプライベート IP アドレスを使用する (IPv6 はグローバルアドレスを使用しても良いが，混乱防止のために ULA を使用することにする)
* 各ルータは，マネジメントネットワークに接続したインタフェースを1つづつ持ち，マネジメントネットワークとその他のネットワークの間のフォワーディングはパケットフィルタですべて拒否する
* 混乱防止のため，マネジメントネットワークに接続したルータは，ローカルのマネジメントネットワークのサブネットに対する経路のみを持つこととする (つまり何の経路も特別には設定しない)。もし，マネジメントネットワークの外からマネジメントネットワークに接続する必要がある場合，マネジメントネットワークの入口のルータで IP マスカレード (NAPT) を行い，同じサブネットからの接続に見えるようにする
* 各サイトのマネジメントネットワークに対しては，OOB (out-of-band) 的な方法によりメインの接続が切れたときでも外部のサイト等からもアクセスできるようにする
* サーバなど，マネジメントネットワークをインターネット接続 (アップデートなど) の手段として使用する機器が存在するので，マネジメントネットワークにデフォルトルートを設定した機器からはインターネットにアクセスできるようにする。ただし，イントラネットなど，組織内部への接続は遮断する

</details>

## 実験環境
* FRR 9.1
* Ubuntu 22.04

![lab-20240318-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653437/834c98de-5120-5ad1-ff82-adc820b10c68.png)

### 設定

:::note warn
ルータのインタフェースには，netplan などで accept-ra を無効にしてあげる必要があります。そうしないと，IPv6 のデフォルトルートを勝手にカーネルが設定して動作しません。
:::

#### isp-r1

* lo: ループバック (127.0.0.1/8, ::1/128 も設定されている)
    * IPv4: 192.168.220.2/32
    * IPv6: 2001:df3:14c0:5002::1/128
* en-ext: インターネット接続，このテストにおいては NAPT する
* en-200: r1 と接続。 
    * IPv4: 192.168.220.0/31
    * IPv6: 2001:df3:14c0:5200::1/64

```:FRR
ip router-id 192.168.220.2
!
router bgp 65105
 no bgp ebgp-requires-policy
 neighbor 192.168.220.1 remote-as 65806
 neighbor 2001:df3:14c0:5200::2 remote-as 65806
 !
 address-family ipv4 unicast
  network 192.168.220.2/32
  neighbor 192.168.220.1 default-originate
  no neighbor 2001:df3:14c0:5200::2 activate
 exit-address-family
 !
 address-family ipv6 unicast
  network 2001:df3:14c0:5002::1/128
  neighbor 2001:df3:14c0:5200::2 activate
  neighbor 2001:df3:14c0:5200::2 default-originate
 exit-address-family
exit
```

#### r1

* lo: ループバック (127.0.0.1/8, ::1/128 も設定されている)
    * IPv4: 192.168.222.1/32
    * IPv6: 2001:df3:14c0:5001::1/128
* en-200: isp-r1 と接続
    * IPv4: 192.168.220.1/31
    * IPv6: 2001:df3:14c0:5200::2/64
* en-100: r2 と接続
    * IPv6 link-local だけ (何も設定しない)

```:FRR
ip router-id 192.168.222.1
ip route 192.168.222.0/24 blackhole
ipv6 route 2001:df3:14c0:5001::/64 blackhole
!
interface en-100
 ipv6 ospf6 area 0
exit
!
interface en-200
 ipv6 ospf6 area 0
 ipv6 ospf6 passive
exit
!
interface lo
 ipv6 ospf6 area 0
 ipv6 ospf6 passive
exit
!
router bgp 65806
 neighbor 192.168.220.0 remote-as 65105
 neighbor 2001:df3:14c0:5001::2 remote-as internal
 neighbor 2001:df3:14c0:5001::2 capability extended-nexthop
 neighbor 2001:df3:14c0:5200::1 remote-as 65105
 !
 address-family ipv4 unicast
  network 192.168.222.0/24
  network 192.168.222.1/32
  neighbor 192.168.220.0 prefix-list isp-in in
  neighbor 192.168.220.0 prefix-list isp-out out
  no neighbor 2001:df3:14c0:5200::1 activate
 exit-address-family
 !
 address-family ipv6 unicast
  network 2001:df3:14c0:5001::/64
  neighbor 2001:df3:14c0:5001::2 activate
  neighbor 2001:df3:14c0:5200::1 activate
  neighbor 2001:df3:14c0:5200::1 prefix-list isp6-in in
  neighbor 2001:df3:14c0:5200::1 prefix-list isp6-out out
 exit-address-family
exit
!
router ospf6
exit
!
ip prefix-list isp-in seq 100 permit 0.0.0.0/0 ge 0
ip prefix-list isp-out seq 100 permit 192.168.222.0/24
ip prefix-list isp-out seq 200 permit 192.168.223.0/24
ip prefix-list isp-out seq 1000 deny any
!
ipv6 prefix-list isp6-in seq 100 permit ::/0 ge 0
ipv6 prefix-list isp6-out seq 100 permit 2001:df3:14c0:5001::/64
ipv6 prefix-list isp6-out seq 200 permit 2001:df3:14c0:5101::/64
ipv6 prefix-list isp6-out seq 1000 deny any
!
```

#### r2

この例ではループバックインタフェースに適当な DNS サーバを走らせています。

* lo: ループバック (127.0.0.1/8, ::1/128 も設定されている)
    * IPv4: 192.168.222.2/32
    * IPv6: 2001:df3:14c0:5001::2/128
* en-100: r1 と接続
    * IPv6 link-local だけ (何も設定しない)
* en-101: Internal VLAN
    * IPv4: 192.168.223.1/24
    * IPv6: 2001:df3:14c0:5101::1/64

```:FRR
ip router-id 192.168.222.2
!
interface en-101
 ipv6 nd rdnss 2001:df3:14c0:5001::2
 no ipv6 nd suppress-ra
exit
!
interface en-100
 ipv6 ospf6 area 0
exit
!
interface lo
 ipv6 ospf6 area 0
 ipv6 ospf6 passive
exit
!
router bgp 65806
 neighbor 2001:df3:14c0:5001::1 remote-as internal
 neighbor 2001:df3:14c0:5001::1 capability extended-nexthop
 !
 address-family ipv4 unicast
  network 192.168.222.2/32
  network 192.168.223.0/24
 exit-address-family
 !
 address-family ipv6 unicast
  network 2001:df3:14c0:5101::/64
  neighbor 2001:df3:14c0:5001::1 activate
 exit-address-family
exit
!
router ospf6
exit
!
```

#### ホスト (host1) の設定

IPv4 のデフォルトルートを 192.168.223.1 宛てに設定，IPv6 のデフォルトルートを RA で設定します。

* eth0: r2 の en-101 に接続
    * IPv4: 192.168.223.2/24
    * IPv6: RA で設定 (accept-ra: true)


```:/etc/netplan/99-local.yaml
network:
    version: 2
    ethernets:
        eth0:
            dhcp4: false
            accept-ra: true
            addresses: [192.168.223.2/24]
            routes:
                - to: default
                  via: 192.168.223.1
            nameservers:
                addresses: [192.168.222.2]
```

### 動作確認

```:host1
root@host1:~# ping -c3 1.1.1.1
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
64 bytes from 1.1.1.1: icmp_seq=1 ttl=54 time=12.8 ms
64 bytes from 1.1.1.1: icmp_seq=2 ttl=54 time=10.8 ms
64 bytes from 1.1.1.1: icmp_seq=3 ttl=54 time=10.3 ms

--- 1.1.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 10.340/11.319/12.801/1.065 ms

root@host1:~# ping -c3 2606:4700:4700::1111
PING 2606:4700:4700::1111(2606:4700:4700::1111) 56 data bytes
64 bytes from 2606:4700:4700::1111: icmp_seq=1 ttl=55 time=8.91 ms
64 bytes from 2606:4700:4700::1111: icmp_seq=2 ttl=55 time=8.94 ms
64 bytes from 2606:4700:4700::1111: icmp_seq=3 ttl=55 time=8.55 ms

--- 2606:4700:4700::1111 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 8.545/8.798/8.938/0.179 ms

root@host1:~# traceroute 192.168.220.2
traceroute to 192.168.220.2 (192.168.220.2), 30 hops max, 60 byte packets
 1  _gateway (192.168.223.1)  0.058 ms  0.006 ms  0.005 ms
 2  192.168.222.1 (192.168.222.1)  0.025 ms  0.009 ms  0.009 ms
 3  192.168.220.2 (192.168.220.2)  0.022 ms  0.012 ms  0.013 ms
 
root@host1:~# traceroute 2001:df3:14c0:5002::1
traceroute to 2001:df3:14c0:5002::1 (2001:df3:14c0:5002::1), 30 hops max, 80 byte packets
 1  2001:df3:14c0:5101::1 (2001:df3:14c0:5101::1)  0.052 ms  0.007 ms  0.005 ms
 2  2001:df3:14c0:5001::1 (2001:df3:14c0:5001::1)  0.029 ms  0.010 ms  0.010 ms
 3  2001:df3:14c0:5002::1 (2001:df3:14c0:5002::1)  0.025 ms  0.012 ms  0.012 ms

 ```

 traceroute ではループバックに設定したアドレスが表示されることが分かります。

## 個人的な感想
* 今までバックボーンで我々が慣れ親しんできた OSPF+iBGP のループバックでのピア構成を最小限の変更で使えるので汎用性が高い
* ルートリフレクタなどを使った大規模な構成にも応用できる

 ----

 みなさんからの感想をお待ちしています。

 GitHub: metastable-void
 X (Twitter): vericava
 Bluesky: mori.yuka.org