baron tech blog

学びをアウトプットしていきたいです

BGP in the Data Centerを読みました (4) : Chapter 4 - Reimagining BGP Configuration

cumulusnetworks.com

今回はChapter 4についてまとめました。 内容はChapter 3に引き続き、構築を自動化しやすいようなIPv6のBGP設定です。 具体的にはBGP unnumberedおよびRFC 5549です。

データセンタネットワーク全般については、”Cloud-Native Data Center Networking” を読むのがおすすめです。 筆者が同じ方で、 "BGP in the Data Center" に記載されている内容も含まれています。

www.oreilly.com

各Chapterまとめ

Chapter 4 - Reimagining BGP Configuration

Chapter 3では、BGPの設定からIPアドレスを排除する方法を見てきました。 BGP設定からはインタフェースIPアドレスの記述をなくすことができました。 しかし、依然としてインタフェース自体にはIPアドレス (/30, /31) の設定が必要なままです。

インタフェースIPアドレスはBGP以外で使用されることはありません。 また、FIB (Forwarding Information Base) のサイズを削減するために、インタフェースIPアドレスはBGPで広報しません。

インタフェースIPアドレスを排除できれば、各ノードに固有の値はASNとrouter-id の2つだけになり、 ノードの設定はDCネットワーク構築自動化に適したシンプルなものになります。

インタフェースIPアドレスをBGP設定から排除するために、unnumberedインタフェースの概念をBGPに適用させます。

必要なインタフェースIPアドレスの総数

f:id:foobaron:20190916202344p:plain
2層Closトポロジ (spine 4台, leaf 32台)

図のような、4台のspineと32台のleafからなる2層のClosトポロジを考えます。 各spineには32本のリンクがあり、各leafには1本のリンクがあるものとします。 すると、インタフェースIPアドレスは、 32個のインタフェース * 4台のspine * リンクごとに2つ = 256個 必要です。 leafが96台の中規模ネットワークの場合、必要なインタフェースIPアドレスの総数は 96 * 4 * 2 = 768個 です。 更に規模の大きいspineが16台のネットワークでは、必要なインタフェースIPアドレスの総数は 96 * 16 * 2 = 3072個 です。

2層Closトポロジの規模とインタフェースIPアドレス

ネットワークの規模 インタフェースIPアドレスの数
leaf 32台, spine 4台 32 * 4 * 2 = 256
leaf 96台, spine 4台 96 * 4 * 2 = 768
leaf 96台, spine 16台 96 * 16 * 2 = 3072

これらのIPアドレスアルゴリズムで導出することはできますが、そうすると自動化のコードが複雑になってしまいます。

IPアドレスの所属先はノードかインタフェースか

従来のL3ネットワーク設計では、基本的にはインタフェースにIPアドレスを割り当てていきます。 この設計方法では、「IPアドレスはノードとインタフェースのどちらに属する」ものなのでしょうか。

具体的な質問にするなら、「ノードが、受信するインタフェースとは別のインタフェースに割り当てられているIPアドレスに対するARP requestに応答できるか」です。

f:id:foobaron:20190929210556p:plain
受信インタフェースと異なるインタフェースのIPアドレスに対するARP Request

ルータの場合はARP requestに応答しません。このような動作を有効にしたい場合はproxy-arpを有効化する必要があります。

Linuxの場合は、ARP requestを受信したインタフェースに関係なく、ノードは自身が持つ任意のIPアドレスに対するARP requestに応答できます。 可能な限り通信を有効にしたいという思想があるようです。

Unnumbered Interface

ノードの各インタフェースに固有のIPアドレスを割り当てないL3ネットワーク設計方法があります。

自身が一意のIPアドレスを持つインタフェースをnumbered interfaceと呼ぶのに対し、 自身が一意のIPアドレスを持たないインタフェースを "unnumbered" interface と呼びます。

unnumbered interfaceにIPアドレスが割り当てられていないわけではありません。 他のインタフェースからIPアドレスを借用します。 IPアドレスの借用元インタフェースに障害が発生した場合、そのIPアドレスは使用できなくなってしまいます。 そのため通常は、unnumbered interfaceはループバックインタフェースからIPアドレスを借用します。 ループバックインタフェースはダウンしないためです。

f:id:foobaron:20190929210136p:plain
unnumbered interfaceの例

ルータがunnumbered interfaceでARP requestを受信した場合、受信したインタフェースのMACアドレスを使用してARPに応答します。

BGP Unnumbered

リンクステートプロトコルであるOSPFやIS-ISでは、当初からunnumbered interfaceがサポートされています。 (IS-ISはIP上で動作しませんが、unnumbered interfaceでも動作します。)

リンクステートプロトコルでは、link-local multicast addressを使用してメッセージを送信します。 そのため、ルーティングプロトコル自体がピアのIPアドレスを事前に知っている必要はなく、 パケットを送受信するインタフェースのみ知っていればよいです。

一方のBGPはTCPで動作します。 そこで、「ピアへの経路がどのインタフェースにあり、ピアのIPアドレスが何であるか」を事前に知っている必要があります。 TCPでは、マルチキャストでなくユニキャストパケットが利用されるためです。

では、Chapter 3で課題になっていたインタフェースIPアドレスを使用せずに、BGPを利用する方法について見ていきます。 具体的には次のような特徴があります。

  • IPv6 link-local address (LLA) を利用
  • IPv6 Router Advertisementによってピアのlink-local addressを学習
  • RFC 5549を利用し、IPv6 link-local addressをネクストホップとするIPv4アドレスを広報
  • RFC 5549のIPアドレス広報を利用して取得した情報を利用するルーティングテーブル設定

IPv6 link-local address

IPv6は、明示的な設定がなくても可能な限り機能するよう設計されています。

IPv6ネットワーク内の全てのリンクには、リンクに固有のIPアドレスが自動で割り当てられます。 このようなIPv6アドレスをlink-local address (LLA) と呼びます。 IPv6 link-local addressは、インタフェースのMACアドレスに基づき自動生成されます。 link-local addressは直接接続されたピアからのみ到達可能であり、一意であることが保証されています。

IPv6 Router Advertisement

ノードが隣接するルータを自動検出するために導入された仕組みをRouter Advertisement (RA) と呼びます。 RAはIPv6のNeighbor Discovery (ND)で使用されるメッセージの1つです。 IPv6のNDは、IPv4ARPに相当します。

インタフェースでRAが有効になっている場合、定期的にlink-local addressを含むインタフェースのIPv6アドレスを定期的に広告します。 したがって、一方のノードが他方のノードのIPv6アドレスを自動で知ることができます。

なお、IPv6 link-local addressはBGPのTCPコネクションでのみ使用されます。 ネットワーク内では、コントロールプレーンでIPv6を使用していますが、 データプレーンでIPv6アドレスを使用する必要はありません。 従来使用していたIPv4を使用可能です。

RFC 5549

コントロールプレーンでIPv6 link-local addressを使用してBGPピアを確立できたとしても、 データプレーンではIPv4の経路への到達性が必要です。

BGPはマルチプロトコル対応 (MP-BGP: Multiprotocol BGP) であり、複数のアドレスファミリの広報を単一のBGPセッションで伝搬できます。 そのため、BGP IPv4 UPDATEメッセージは、IPv6 TCPコネクションを介して送信できます。 経路への到達可能性を通知するBGP UPDATEメッセージには、経路に関連付けられたネクストホップのIPアドレスが含まれています。

BGPは当初IPv4のみに対応しており、ネクストホップのIPv4アドレスは NEXT_HOP attributeに含まれていました。 BGPがIPv4だけでなくIPv6等のマルチプロトコルを扱えるようにするために、 RFC 4760 で導入されたのが次の2つのattributeです。

  • MP_REACH_NLRI (Multiprotocol Reachable NLRI)
  • MP_UNREACH_NLRI (Multiprotocol Unreachable NLRI)

MP_REACH_NLRI には、ネクストホップや経路情報等が含まれます。

+---------------------------------------------------------+
| Address Family Identifier (2 octets)                    |
+---------------------------------------------------------+
| Subsequent Address Family Identifier (1 octet)          |
+---------------------------------------------------------+
| Length of Next Hop Network Address (1 octet)            |
+---------------------------------------------------------+
| Network Address of Next Hop (variable)                  |
+---------------------------------------------------------+
| Reserved (1 octet)                                      |
+---------------------------------------------------------+
| Network Layer Reachability Information (variable)       |
+---------------------------------------------------------+

MP_UNREACH_NLRI には、削除される経路情報等が含まれます。

+---------------------------------------------------------+
| Address Family Identifier (2 octets)                    |
+---------------------------------------------------------+
| Subsequent Address Family Identifier (1 octet)          |
+---------------------------------------------------------+
| Withdrawn Routes (variable)                             |
+---------------------------------------------------------+

IPv4アドレスのないインタフェースがeBGPセッションでIPv4の経路を広報する場合、 広報するネクストホップのIPアドレスIPv6 link-local addressです。 そこで必要となるのがRFC 5549です。

tools.ietf.org

RFC 5549は、 IPv6ネットワーク上でIPv4経路の広報およびIPv4パケットのルーティングを可能にすること を目的としたRFCです。 すなわち、IPv4は、IPv6アドレスをネクストホップとしてルーティングされます。

IPv6ネクストホップの情報は、BGP UPDATEメッセージの MP_REACH_NLRI に含まれます。

f:id:foobaron:20191012233801p:plain
BGP UPDATEメッセージのMP_REACH_NLRI内のNext hop network addressにIPv6 link-local addressが含まれている様子

IPv4経路をIPv6ネクストホップでエンコードするのは、通常のモデルではありません。 BGPピアでRFC 5549を使用するには、RFC 5549を理解する機能を持っていることを双方のルータが広報する必要があります。 RFC 5549の使用をネゴシエーションするために定義されているのが、Extended Next Hop Encoding Capabilityです。

一般的なルーティングの動作の観察

RFC 5549の理解のために、一般的なルーティングの動作を見てみます。

例) 10.1.1.0/24 via 20.1.1.1 dev swp1

  1. ルータが 10.1.1.1 宛のパケットを受信すると、ルータはルーティングテーブル内にある上記のルーティングエントリを使用します。 ネクストホップのIPアドレス20.1.1.1 であり、そしてネクストホップへの送信インタフェースが swp1 であると判断します。
  2. パケットを 20.1.1.1 に転送するには、 20.1.1.1MACアドレスが必要になります。 ルータのARPキャッシュに 20.1.1.1ARPエントリがない場合は、インタフェース swp1 からARP requestを送信します。
  3. 隣接ルータからのARP replyを受信すると、 20.1.1.1MACアドレスARPキャッシュに追加されます。
  4. ルータは、20.1.1.1MACアドレスを宛先MACアドレス、インタフェース swp1MACアドレスを送信元MACアドレスにして、フレームを転送します。

MACアドレスの学習を除き、ネクストホップのIPアドレスは使用されません。

IPv6の場合も同様で、NDを使用してネクストホップのMACアドレスを取得します。

RFC 5549はこのルーティングの動作の観察に基づいており、 ルータがIPv6ネクストホップでIPv4経路を広告できるようなエンコード方式を提供します。

RFC 5549によるパケット転送

今回、RFC 5549の実験で使用したネットワークトポロジは次のとおりです。

f:id:foobaron:20191013015118p:plain
RFC 5549の検証用ネットワークトポロジ

ルーティングテーブルは、IPv4経路にIPv4ネクストホップがあり、IPv6経路にはIPv6ネクストホップがあるという前提に基づいて実装されています。

IPv6 RAメッセージには、 インタフェースのlink-local addressだけでなく、MACアドレスを広告するためのフィールド (source link-layer address) もあります。 このRAメッセージを定期的に送信することで、隣接ノードに自身のインタフェースのIPv6 link-local addressおよびMACアドレスを広報できます。

FRRoutingで、インタフェースのRAを有効化する設定は次のとおりです。

interface swp3
  ipv6 nd ra-interval 5  # RAメッセージの送信間隔を5秒に設定
  no ipv6 nd suppress-ra # RAを有効化 (RAの抑止を無効化)

FRRoutingのBGP unnumberedでは、定期的に送信されるRAメッセージを受信してARP tableにエントリを設定すると、BGPセッションの確立を開始します。 FRRoutingでBGPのExtended Next Hop Encoding Capabilityを有効化する設定は次のとおりです。

router bgp 4210000001
 neighbor ISL peer-group                  # peer-group ISLを定義
 neighbor ISL capability extended-nexthop # peer-group ISLでExtended Next Hop Encoding Capabilityを有効化
 !

手順の概略は次の図のとおりです。

f:id:foobaron:20191012231634p:plain
BGP unnumberedの手順の概略

検証用ネットワークトポロジにて、leaf-01とspine-01の間のBGP unnumberedの手順で送受信されたパケットを、leaf-01でキャプチャした結果は次のとおりです。

f:id:foobaron:20191013015755p:plain
BGP unnumberedの手順のパケットキャプチャ結果

BGPセッションが確立されると、BGPはピアのIPv6 link-local addressを使用して経路広報を受信します。 BGPが受信した経路をベストパスに選択する場合、BGP UPDATEメッセージで受信したIPv6 link-local addressをネクストホップに設定するという情報を、 RIB (Routing Information Base) に渡します。 RIBはノードで実行されている全ルーティングプロトコルから受信した全経路およびstatic routeの集合です。 FRRoutingでは、zebraがRIBに相当します。

f:id:foobaron:20191012235214p:plain
FRRoutingにおけるbgpdとzebra

IPv6 link-local addressをネクストホップとするIPv4の経路を受信し、RIBがそれをFIB (Forwarding Information Base) のベストパスに選択することを考えます。 kernel routing tableがFIBに相当します。

RIBの状態を確認すると、IPv4アドレスのネクストホップが fe80:: で始まるIPv6 link-local addressになっています。

dc-leaf01:~$ sudo vtysh -c 'show ip route'
[sudo] password for cumulus:
Codes: K - kernel route, C - connected, S - static, R - RIP,
       O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
       T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
       F - PBR,
       > - selected route, * - FIB route

C>* 10.0.254.1/32 is directly connected, lo, 08:19:16
B>* 10.0.254.2/32 [20/0] via fe80::20c:29ff:fede:9b3c, swp4, 02:28:45
  *                      via fe80::20c:29ff:feee:f3a6, swp3, 02:28:45
B>* 10.0.254.3/32 [20/0] via fe80::20c:29ff:fede:9b3c, swp4, 02:28:45
  *                      via fe80::20c:29ff:feee:f3a6, swp3, 02:28:45
B>* 10.0.254.4/32 [20/0] via fe80::20c:29ff:fede:9b3c, swp4, 02:28:45
  *                      via fe80::20c:29ff:feee:f3a6, swp3, 02:28:45
B>* 10.0.254.253/32 [20/0] via fe80::20c:29ff:fede:9b3c, swp4, 08:19:10
B>* 10.0.254.254/32 [20/0] via fe80::20c:29ff:feee:f3a6, swp3, 02:28:45
C>* 10.1.1.0/26 is directly connected, vlan10, 08:19:16
B>* 10.1.2.0/26 [20/0] via fe80::20c:29ff:fede:9b3c, swp4, 02:28:45
  *                    via fe80::20c:29ff:feee:f3a6, swp3, 02:28:45
B>* 10.1.3.0/26 [20/0] via fe80::20c:29ff:fede:9b3c, swp4, 02:28:45
  *                    via fe80::20c:29ff:feee:f3a6, swp3, 02:28:45
B>* 10.1.4.0/26 [20/0] via fe80::20c:29ff:fede:9b3c, swp4, 02:28:45
  *                    via fe80::20c:29ff:feee:f3a6, swp3, 02:28:45

RIBプロセスは、そのIPv6 link-local addressと関連付けられたMACアドレスの情報があるか確認します。 そしてRIBは、 169.254.0.1 とそのMACアドレスに関するstatic ARPエントリを追加します。 PERMANENT と記載されているのがstatic ARPエントリです。

dc-leaf01:~$ ip neighbor show
169.254.0.1 dev swp4 lladdr 00:0c:29:de:9b:3c PERMANENT
169.254.0.1 dev swp3 lladdr 00:0c:29:ee:f3:a6 PERMANENT
fe80::20c:29ff:fede:9b3c dev swp4 lladdr 00:0c:29:de:9b:3c router REACHABLE
fe80::20c:29ff:feee:f3a6 dev swp3 lladdr 00:0c:29:ee:f3:a6 router REACHABLE

169.254.0.1IPv4 link-local addressですが、これをIPv6 link-local addressの代わりにネクストホップIPv4アドレスのダミーとして利用します。

そのため、FRRoutingでは 169.254.0.1 が予約されていることを前提としています。 なおIPv4 link-local addressは、IPv6 link-local addressのように自動でインタフェースに割り当てられることはありません。

FIBには、 169.254.0.1ネクストホップとする経路が設定されます。

dc-leaf01:~$ ip route show
10.0.254.2  proto bgp  metric 20
        nexthop via 169.254.0.1  dev swp4 weight 1 onlink
        nexthop via 169.254.0.1  dev swp3 weight 1 onlink
10.0.254.3  proto bgp  metric 20
        nexthop via 169.254.0.1  dev swp4 weight 1 onlink
        nexthop via 169.254.0.1  dev swp3 weight 1 onlink
10.0.254.4  proto bgp  metric 20
        nexthop via 169.254.0.1  dev swp4 weight 1 onlink
        nexthop via 169.254.0.1  dev swp3 weight 1 onlink
10.0.254.253 via 169.254.0.1 dev swp4  proto bgp  metric 20 onlink
10.0.254.254 via 169.254.0.1 dev swp3  proto bgp  metric 20 onlink
10.1.1.0/26 dev vlan10  proto kernel  scope link  src 10.1.1.1
10.1.2.0/26  proto bgp  metric 20
        nexthop via 169.254.0.1  dev swp4 weight 1 onlink
        nexthop via 169.254.0.1  dev swp3 weight 1 onlink
10.1.3.0/26  proto bgp  metric 20
        nexthop via 169.254.0.1  dev swp4 weight 1 onlink
        nexthop via 169.254.0.1  dev swp3 weight 1 onlink
10.1.4.0/26  proto bgp  metric 20
        nexthop via 169.254.0.1  dev swp4 weight 1 onlink
        nexthop via 169.254.0.1  dev swp3 weight 1 onlink

これらが設定された時点で、パケット転送が正しく動作します。

なお、リンクがダウンしたり隣接ノードがRAを無効化した場合、 ローカルのRAプロセスは、RIBから該当するlink-local addressとMACアドレスのエントリを削除します。

RIBプロセスは、ネクストホップが到達不可であると判断し、ピアが到達不可であることをBGPプロセスに通知します。 そして、該当するstatic ARPエントリを削除します。

ピアへ到達不可になったことでBGPセッションがダウンするので、 BGPプロセスは該当するインタフェースに関連する経路を破棄します。

BGP

BGP unnumberedの動作をまとめると、次のとおりです。

  • BGP unnumberedは、インタフェースのIPv6 link-local addressを使用してBGPセッションのピアを設定する
  • 隣接ノードのIPv6 link-local addressおよびMACアドレスは、IPv6 RAによって提供される
  • RIBプロセスは、RAによって学習されたMACアドレスおよび予約されたIPv4 link-local address 169.254.0.1 を使用して、static ARPエントリを設定する
  • RFC 5549により、BGPは、IPv6 link-local adderssを使用してRIBプロセスのIPv4経路を設定する
  • RIBプロセスは、RIBにおけるネクストホップのIPv6 link-local addressをIPv4 link-local address 169.254.0.1 に変換して、FIBにIPv4経路を設定する

実験用ネットワークトポロジでのBGP unnumberedとRFC 5549の動作確認

Chapter 3で見てきたBGP設定では、リンク間のインタフェースにIPアドレスを設定する必要がありました。 BGP unnumberedおよびRFC 5549を採用することで、 インタフェースのIPアドレス設定を排除し、各ノードに固有の値はASNとrouter-id の2つだけになりました。

Ansible等のツールを利用した自動化が非常に容易です。

最後に、実験用ネットワークトポロジでのleaf01とspine01について確認しておきます。

ノードの設定は次のとおりです。spineとleafの設定はほぼ同じです。

  • leaf01の設定
  • dc-leaf01:~$ sudo cat /etc/frr/frr.conf
frr version 4.0+cl3u13
frr defaults datacenter
hostname dc-leaf01
!
interface swp3
 ipv6 nd ra-interval 5
 no ipv6 nd suppress-ra
!
interface swp4
 ipv6 nd ra-interval 5
 no ipv6 nd suppress-ra
!
router bgp 4210000001
 bgp router-id 10.0.254.1
 no bgp default ipv4-unicast
 bgp bestpath as-path multipath-relax
 neighbor ISL peer-group
 neighbor ISL remote-as external
 neighbor ISL bfd
 neighbor ISL timers connect 5
 neighbor ISL capability extended-nexthop
 neighbor swp3 interface peer-group ISL
 neighbor swp4 interface peer-group ISL
 !
 address-family ipv4 unicast
  redistribute connected route-map ACCEPT_DC_LOCAL
  neighbor ISL activate
  maximum-paths 64
 exit-address-family
!
ip prefix-list DC_LOCAL_SUBNET seq 5 permit 10.1.0.0/16 ge 26
ip prefix-list DC_LOCAL_SUBNET seq 10 permit 10.0.254.0/24 ge 32
!
route-map ACCEPT_DC_LOCAL permit 10
 match ip address prefix-list DC_LOCAL_SUBNET
!
  • spine01の設定
  • dc-spine01:~$ sudo cat /etc/frr/frr.conf
frr version 4.0+cl3u13
frr defaults datacenter
hostname dc-leaf01
!
interface swp1
 no ipv6 nd suppress-ra
 ipv6 nd ra-interval 5
!
interface swp2
 no ipv6 nd suppress-ra
 ipv6 nd ra-interval 5
!
interface swp3
 no ipv6 nd suppress-ra
 ipv6 nd ra-interval 5
!
interface swp4
 no ipv6 nd suppress-ra
 ipv6 nd ra-interval 5
!
router bgp 4200000000
 bgp router-id 10.0.254.254
 no bgp default ipv4-unicast
 bgp bestpath as-path multipath-relax
 neighbor ISL peer-group
 neighbor ISL remote-as external
 neighbor ISL bfd
 neighbor ISL timers connect 5
 neighbor ISL capability extended-nexthop
 neighbor swp1 interface peer-group ISL
 neighbor swp2 interface peer-group ISL
 neighbor swp3 interface peer-group ISL
 neighbor swp4 interface peer-group ISL
 !
 address-family ipv4 unicast
  redistribute connected route-map ADV_LO
  neighbor ISL activate
  maximum-paths 64
 exit-address-family
!
route-map ADV_LO permit 10
 match interface lo
!

spine01にてBGPの状態を確認すると、次のとおりです。 leaf4台とBGPピアが確立できていることがわかります。

dc-spine01:~$ net show bgp ipv4 unicast summary
BGP router identifier 10.0.254.254, local AS number 4200000000 vrf-id 0
BGP table version 73
RIB entries 17, using 2584 bytes of memory
Peers 4, using 77 KiB of memory
Peer groups 1, using 64 bytes of memory

Neighbor        V         AS MsgRcvd MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd
dc-leaf01(swp1) 4 4210000001   62551   62431        0    0    0 03:51:55            2
dc-leaf02(swp2) 4 4210000002   62353   62344        0    0    0 2d03h55m            2
dc-leaf03(swp3) 4 4210000003   62353   62344        0    0    0 2d03h55m            2
dc-leaf04(swp4) 4 4210000004   62356   62347        0    0    0 2d03h55m            2

Total number of neighbors 4

まとめ

  • BGP unnumberedによりインタフェースのIPアドレス設定を排除
  • RFC 5549により、BGPでIPv6 link-local addressをネクストホップとするIPv4経路を設定