LINE株式会社は、2023年10月1日にLINEヤフー株式会社になりました。LINEヤフー株式会社の新しいブログはこちらです。 LINEヤフー Tech Blog

Blog


安定したネットワークメンテナンスに向けたネットワークオーケストレーターのstatic route機能の検討と実装

こんにちは,Verda Platform室ネットワーク開発チームの橘 直雪と申します.本記事では私が取り組んでいた「安定したネットワークメンテナンスに向けたネットワークオーケストレーターのstatic route機能の検討と実装」についての成果を紹介します.

背景

LINEのClosネットワークではメンテナンス性の高さやスケーラビリティの観点から,スイッチ,ハイパーバイザー,その上で動作するVMまで全てL3でルーティングされるようになっています.VMやハイパーバイザー上ではOSSのルーティングデーモンであるFRRouting(以下FRR)が動作しており,Top of RackスイッチからVMに向かう/32の経路をEBGPでハイパーバイザーのFRRからTop of Rackスイッチに広報しています.また,私達ネットワーク開発チームでは,常に拡大し続けているLINEのサービスの要件に合わせてネットワークの刷新を行っており,必要に応じてFRRへの機能拡張などを行っています.そのため,サーバー上のFRRを頻繁にアップデートする必要があります.しかしサーバーのFRRをアップデートのために再起動した場合,FRRからTop of Rackスイッチに広報されていた経路が削除され,サーバーとの疎通が失われます.サーバーではFRR以外のサービスも動作しているため,この疎通断はサービスに悪影響をもたらします.そのため,私達はサーバーとの疎通を損なわずにサーバーのFRRをアップグレードする手法を必要としていました.その候補としてBGP Graceful Restart (RFC4724)に着目していましたが,調査の結果私達のチームでBGP Graceful Restartを利用するまでにはさらなる調査・検討が必要だということが明らかになりました.BGP Graceful Restartに着目した理由や実際の調査内容,何故調査後に本番環境に適用されなかったかなどは以下の記事に詳細にまとまっていますので御覧ください.

https://engineering.linecorp.com/ja/blog/oss-routing-platform-involved-in-bgp-graceful-restart/

れらの調査を踏まえて,私達にはBGP Graceful Restartの追加調査と並行して代替するアップグレード手法を検討する必要があることが分かりました.


必要な機能の検討

BGP Graceful Restartを使わずに,ネットワーク機器にどのような設定を実施すればアップグレードを疎通断なしで実行することができるでしょうか.以下の図を例に考えてみます.

sv01, sv02共にFRRが動作しており,sw1とBGPで通信しているものとします.この時,sw1のRIBは以下のようになっています.

sw1 RIB
192.168.1.1 via <sv01-eth2 lladdr> dev swp1 proto bgp metric 20 onlink
192.168.1.2 via <sv02-eth2 lladdr> dev swp2 proto bgp metric 20 onlink

この状態で, sv01のFRRを再起動すると, BGP peerが再接続され, その瞬間はsv01から広報されていた経路がsw1で削除されます. 結果的に図のトラフィックが流れない状態になります.

sv01 FRR再起動中のsw1 RIB
192.168.1.2 via <sv02-eth2 lladdr> dev swp2 proto bgp metric 20 onlink # sv01向け経路が削除される

ここで問題になるのは,サーバーのFRRが一度停止することによってサーバー向けのBGP経路が広報されなくなり,サーバーへの疎通が失われることです.私達はこの問題に対処するために,サーバーの再起動前の段階でBGP経路よりもAdministrative Distance値が高いstatic routeを設定して,スイッチのRIBを更新するアプローチを考えました.しかし,実環境ではサーバーに接続されているスイッチは1台だけではありません.1データセンター辺りのサーバー数は約7200台で,かつ1台のサーバーにつき2つのTop of Rackスイッチに接続する構成のため,経路数は約14400にのぼります.FRRのアップグレード/再起動時に, 対応するスイッチ全てに手動で経路を設定するのは困難です.そこで,私はLINEのネットワークオーケストレーターにstatic routeを設定する機能を追加することにしました.

ネットワークオーケストレーターの概要

このセクションでは,本記事の理解に必要最低限な範囲でLINEのネットワークオーケストレーターの解説を行います.LINEでは,Closネットワーク下のすべてのネットワーク機器をネットワークオーケストレーターで管理しており、アーキテクチャの概観は以下のようになっています.ネットワークオーケストレーターは,オペレーターからなどのDatabase更新リクエストを受け付けるAPI Server,ネットワーク機器の設定をデータモデルに抽象化して記録するDatabase (etcd), etcdからデータを取得しネットワーク機器に設定を反映するSync-agent, スイッチ起動時の初期設定(Zero Touch Provisioning)に関わる処理を行うZTP Serverの4つのコンポーネントで構成されています.

以下の図はネットワークオーケストレーターの設定変更の流れを示しています.Sync-agentはスイッチ上に搭載されており,Database上に記録されているスイッチの設定の変更を監視しています.オペレーターがAPI Serverを経由してDatabase上の機器設定を変更すると,Sync-agentはネットワーク機器にその変更を反映します.

データモデル

現在、LINEのClosネットワークではホワイトボックススイッチを利用して、CumulusLinuxとAristaのマルチベンダー構成で構築しています. ベンダーごとにネットワーク機器の設定方法は異なりますが,ベンダーによって異なる方式で設定をDatabaseに保存することはメンテナンス性や他のベンダーを導入する際のスケーラビリティの観点からいい選択肢とは言えません.そこで,LINEのネットワークオーケストレーターでは各ネットワーク機器の設定を,ベンダー非依存なデータモデルの形でAPI Serverを経由してDatabaseに保存しています.例えばDHCPの設定の場合,データモデルで以下のように宣言できます.

データモデル
{
  "INTERFACE": {
       ...
       "dhcp": True,
       ...
  }
}

これは,実際のCumulusLinuxやAristaのconfiguration commandで以下のように表現されます.

Cumulus
# /etc/network/interfaces
 
auto swp1
iface swp1 inet dhcp
...
arista
interface Ethernet 1/1
  ip address dhcp
  ...

データモデルは,機能ごとにまとまったパラメーターシートという単位で管理されています.

例えば,Interface パラメーターシートには該当するスイッチの各インターフェースのmacアドレスやIPアドレスなどの情報が記録されるようになっています.

{
  "lo": {
    "type": "loopback",
    "is_enabled": true,
    "description": "foo",
    "speed": 1000,
    "mtu": 1500,
    "ipv4": ["10.0.0.1/32"],
    "ipv6": ["fc00::2/128"]
  },
  "swp1": {
    "type": "dataport",
    "is_enabled": true,
    "speed": 10000,
    "ipv6_nd_ra": true
  },
.........

ネットワークオーケストレーターに関する詳細なシステム構成や分散システムとしての設定の流れ, 細かいデータモデルに関しては以下の資料が参考になります.

https://www.janog.gr.jp/meeting/janog49/lineorc/

また,ネットワークオーケストレーターの導入に至った背景などを知りたい方は以下の資料をご参照ください.

https://www.janog.gr.jp/meeting/janog43/program/line/

追加するデータモデルの検討

ネットワークオーケストレーターにstatic routeを設定する機能を追加するにあたって,どのパラメーターシートにどのような値を格納すればいいのかを検討する必要があります. この際に意識したいのは,サーバーのFRRが再起動する際に,サーバーが接続する全てのスイッチにstatic routeを設定する必要があるということです.LINEのClosネットワークは下図のように一つのサーバに対して2つのTop of Rackスイッチが接続する構成のため,sv01のFRRを再起動する場合に矢印の2つのstatic routeを一つのパラメーターシートで同時に設定できるのが理想です.

そこで,私はServer というパラメーターシートに着目しました.LINEのClosネットワークでは各サーバー上においてもFRRが動作しており,Top of RackスイッチにBGPを利用して/32の経路の広報を行っています.この時,サーバーが不適切な経路を広報しないようにするためにTop of RackスイッチでWhite list形式のprefix-listを適用する必要があります.そのためには,各サーバーがどのような経路を広報するかという情報に加えて,どのスイッチにどのサーバーが接続されるかという情報を把握する必要があります.これを実現するために作られたのがServerパラメーターシートです.Serverパラメーターシートでは,サーバーのHostnameをkeyとしてprefix-listに追加する経路を登録しています.サーバーがスイッチに接続されると,スイッチはLLDPを介してインターフェースに接続されたサーバーのHostnameを認識します.そして,Hostnameの情報を元にprefix-listの設定を反映します.

このパラメーターシートであれば,サーバーが接続する全てのスイッチに設定を適用するという要件が満たせます.更に,LLDPで情報を取得する関係上,インターフェースとその対向のサーバーが紐付けられた状態で情報を取得できます.そのため,next-hopのインターフェースやIPアドレスをパラメーターとして設定する必要がありません.以上の理由から,serverパラメーターシートにstatic routeのprefixのみを格納する方針で実装することにしました.

{
  "server_confs": {
    "swp1": { ## このインターフェース名をnext-hopにするように実装すれば良い
      "hostname": "SV01",
      "static_route_ipv4": [
        {"prefix": "192.168.1.1/32"},
      ],
      "static_route_ipv6": [
        {"prefix": "a::1/128"}
      ],
      "description": "sv01"   
     }
  }
}

Sync-agent実装

今回のstatic routeパラメーターに限定されたことではありませんが,etcdから共通のデータモデルで配布されたパラメーターをスイッチに反映する際にネットワークOSの差分を反映する必要があります.その際にSync-agentでどのような処理を介して差分の反映を行っているかをネットワークOS別にご紹介します.

CumulusLinuxの場合

CumulusLinuxの設定は,frr.confというファイルに保存されます.そのため,Sync-agentでは,このfrr.confを書き換える必要があります.そこで,jinja templateを利用し,データモデルとして受け取ったパラメーターをtemplateに展開することで設定を反映しています

データモデル
{
  "server_confs": {
    "swp1": {
      "hostname": "SV01",
      "static_route_ipv4": [
        {"prefix": "192.168.1.1/32"},
        {"prefix": "192.168.1.2/32"}     
      ],
      "static_route_ipv6": [
        {"prefix": "a::1/128"}
      ],
      "description": "sv01"   
    }
  }
}

jinja template
{% for if_name, sv_conf in (server_confs | default({})).items() %}
{% for prefixes in sv_conf.static_route_ipv4 | default({}) %}
ip route {{ prefixes.prefix }} {{ if_name }}
{% endfor %}
{% for prefixes in sv_conf.static_route_ipv6 | default({}) %}
ipv6 route {{ prefixes.prefix }} {{ if_name }}
{% endfor %}

frr.confに出力されるコマンド
ip route 192.168.1.1/32 swp1
ip route 192.168.1.2/32 swp1
ipv6 route a::1/128 swp1

Aristaの場合

Aristaでは,CumulusLinuxのようなファイル形式での設定管理を行っていないため,CLIにコマンドを投入する形で設定変更を行います.この時にスイッチに設定する全てのstatic routeを一度全て削除し,現在適用すべきstatic routeを設定し直すことも可能ですが,これはあまり効率がよくありません.そのため,etcdに登録されているstatic routeと現在スイッチに設定されているstatic routeの差分を確認して,その差分だけSync-agentを介してコマンドを投入することで対応しています.

動作検証

動作検証においては,ネットワークオーケストレーター経由のstatic route追加でサーバーのFRRの再起動を疎通断なく実施できるかを検証します.検証では以下のような構成を利用します.sv01のFRRを再起動し,疎通断しているかを確認します.疎通断の判断はsv02からsv01へのpingコマンドの実行で行い,同時にs1-01bのip routeコマンドをwatchしてRIBの変化を確認します.

s1-01b RIB
10.254.10.11 via 169.254.0.1 dev swp1.100 proto bgp metric 20 onlink
10.254.10.12 via 169.254.0.1 dev swp2.100 proto bgp metric 20 onlink
...

何も設定しない場合

sv01のFRRを再起動すると,pingではdestination unreachableが発生し,その際にs1-01bのRIBからsv01に向けた経路が削除されています.このことから,sv01が瞬間的に疎通断状態になっていることがわかります.

ping: interval=1s
64 bytes from 10.254.10.11: icmp_seq=49 ttl=63 time=0.470 ms
64 bytes from 10.254.10.11: icmp_seq=50 ttl=63 time=0.430 ms
64 bytes from 10.254.10.11: icmp_seq=51 ttl=63 time=0.431 ms
64 bytes from 10.254.10.11: icmp_seq=52 ttl=63 time=0.414 ms
64 bytes from 10.254.10.11: icmp_seq=53 ttl=63 time=0.449 ms
64 bytes from 10.254.10.11: icmp_seq=54 ttl=63 time=0.398 ms # 再起動開始
From 10.254.20.3 icmp_seq=55 Destination Net Unreachable  # 疎通断が発生している
From 10.254.20.3 icmp_seq=56 Destination Net Unreachable
From 10.254.20.3 icmp_seq=57 Destination Net Unreachable
From 10.254.20.3 icmp_seq=58 Destination Net Unreachable
64 bytes from 10.254.10.11: icmp_seq=64 ttl=63 time=0.497 ms
64 bytes from 10.254.10.11: icmp_seq=65 ttl=63 time=0.439 ms
64 bytes from 10.254.10.11: icmp_seq=66 ttl=63 time=0.491 ms
64 bytes from 10.254.10.11: icmp_seq=67 ttl=63 time=0.487 ms
64 bytes from 10.254.10.11: icmp_seq=68 ttl=63 time=0.560 ms
64 bytes from 10.254.10.11: icmp_seq=69 ttl=63 time=0.532 ms

sv01 FRR再起動中のs1-01b RIB
10.254.10.12 via 169.254.0.1 dev swp2.100 proto bgp metric 20 onlink
...  # 10.254.10.11(sv01)向けの経路が消えている

ネットワークオーケストレーターによるstatic routeの設定

ネットワークオーケストレーターにsv01のstatic routeを投入します.これにより,s1-01bのRIBにおけるsv01向けの経路がBGP経路よりAdministrative Distance値が高いstatic routeに更新されます.

etcdに投入するデータ
{
  "description""sv01",
  "hostname""SV01",
  "ipv4_prefixes": [],
  "ipv6_prefixes": [],
  "static_route_ipv4": [
    {"prefix""10.254.10.11/32"}
  ],
  "static_route_ipv6": []
}

static route適用後のs1-01b RIB
10.254.10.11 dev swp1.100 proto static metric 20 # sv01向けの経路がstatic routeに変更されている
10.254.10.12 via 169.254.0.1 dev swp2.100 proto bgp metric 20 onlink
...

static route設定後の挙動

static route設定後,もう一度sv01のFRRを再起動してみます.すると,再起動後もpingでdestination unreachableは発生せず,またs1-01bのRIBからsv01向けの経路は削除されていません.このことから,static routeの設定によってsv01を疎通断させずに再起動することが可能になったことがわかります.

ping: interval=1s
64 bytes from 10.254.10.11: icmp_seq=10 ttl=63 time=0.308 ms
64 bytes from 10.254.10.11: icmp_seq=11 ttl=63 time=0.500 ms
64 bytes from 10.254.10.11: icmp_seq=12 ttl=63 time=0.571 ms
64 bytes from 10.254.10.11: icmp_seq=13 ttl=63 time=0.485 ms
64 bytes from 10.254.10.11: icmp_seq=14 ttl=63 time=0.535 ms
64 bytes from 10.254.10.11: icmp_seq=15 ttl=63 time=0.494 ms # 再起動開始
64 bytes from 10.254.10.11: icmp_seq=16 ttl=63 time=0.496 ms
64 bytes from 10.254.10.11: icmp_seq=17 ttl=63 time=0.458 ms
64 bytes from 10.254.10.11: icmp_seq=18 ttl=63 time=0.451 ms
64 bytes from 10.254.10.11: icmp_seq=19 ttl=63 time=0.424 ms
64 bytes from 10.254.10.11: icmp_seq=20 ttl=63 time=0.504 ms
64 bytes from 10.254.10.11: icmp_seq=21 ttl=63 time=0.469 ms
64 bytes from 10.254.10.11: icmp_seq=22 ttl=63 time=0.440 ms
64 bytes from 10.254.10.11: icmp_seq=23 ttl=63 time=0.448 ms
64 bytes from 10.254.10.11: icmp_seq=24 ttl=63 time=0.374 ms
64 bytes from 10.254.10.11: icmp_seq=25 ttl=63 time=0.455 ms # 疎通断が発生していない
再起動中のs1-01b RIB
10.254.10.11 dev swp1.100 proto static metric 20 # sv01向けの経路が削除されていない
10.254.10.12 via 169.254.0.1 dev swp2.100 proto bgp metric 20 onlink
...

この検証から,ネットワークオーケストレーター経由でのstatic route追加によって, FRRのアップデート時に必要な再起動をした際に発生する疎通断を防止することができることが示されました.

今後の展望

サーバー側ネットワークへのネットワークオーケストレーターの導入

今回のネットワークオーケストレーターへのサーバー向けstatic route機能の追加によって,Top of Rackスイッチにサーバー向けのBGP経路を少ない工数で設定できるようになりました.しかし,サーバーからTop of Rackスイッチに向ける経路に関しては手動でstatic routeを設定する必要があるのが現状です. これはサーバーで動作しているFRRがネットワークオーケストレーターの管理下にないことに起因しています.今後サーバー側のFRRを含めたネットワークコンポーネントをネットワークオーケストレーターで管理できるようにすることで,サーバーとスイッチの協調した動作が可能となり,オペレーションコストの軽量化を実現できます.

継続したBGP Graceful Restartに関する調査

LINEのネットワークオーケストレーターはLINE独自のメカニズムを用いて運用しています.今回開発した機能によるフォワーディングの継続はアドホック的な対応としては十分だと考えていますが,理解するのに時間を要することから保守コストや人員的観点のスケーラビリティには課題が残ります.BGP Graceful Restartを始めとした標準化されたネットワークプロトコルの採用によってこの問題は解決できるため,これらの導入のための調査は引き続き行っていく予定です.

まとめ

今回の取り組みでは,ネットワークオーケストレーターにstatic routeを設定する機能を追加することで,サーバー上で動作するFRRを疎通断なくアップグレードすることを可能にしました.また,LINEのネットワークオーケストレーターの実際の開発過程や検討事項の一部をご紹介しました.

ネットワーク開発チームでは,Verdaでのクラウドネットワークに加え,ネットワークオーケストレーターを始めとする,アンダーレイのClosネットワークに関連するソフトウェアの開発にも取り組んでいます.この記事を通じて,Verdaに関連するネットワーク開発に興味を持っていただければ幸いです.