別れ話をBGPに載せて

2023年12月22日 金曜日


【この記事を書いた人】
hori

社長室兼基盤エンジニアリング本部所属。これだけ見るとフルスタックエンジニアを超越しているが、実態はネットワークを中心にしたインフラ全般の企画が主なお仕事。AS2497 / The Internet / BGP / SRv6

「別れ話をBGPに載せて」のイメージ

IIJ 2023 TECHアドベントカレンダー 12/22の記事です】

警告: タイトルから推測できるとおり、人によってはメンタルに来る可能性があります。at your own riskでお読みください。

 

私のXタイムラインにシスコシステムズさんのこんな記事が流れてきた。

引用元:愛の告白をBGPに載せて 

本題

show ip bgpを実行するのに、こんなに緊張するのは初めてだ。流宇太(るうた)はターミナルソフト画面に表示されているshow ip bgpコマンドを凝視しながらこう思った。

 まだ若手エンジニアとは言えるが、幾つかの難関ネットワーク案件を完遂してきた実績を持っており、数々の本番環境で落ち着いて作業をこなしてきた流宇太は、人生初めて一つのコマンドを実行するのに、手のひらに汗をかくほど緊張している。

 それもそのはずだ。なぜならこのコマンドの実行結果には、愛の告白の返事が入っているからだ。

 二週間前にあの愛の告白作戦をやめとけばよかったかもしれないな、と心の中で嘆きながら、流宇太は無意識にWebex画面の向こうの女性に一瞬視線を向けた。

 彼女の名前は詩須子(しすこ)、流宇太とは保育園から大学までずっと一緒で、おまけに同じ会社に同期入社している仲だ。ネットワークという共通の趣味を持って、休日は一緒に自宅ラボで検証を楽しむこの二人は、周りから「流宇太と言えば詩須子(♡)、詩須子と言えば流宇太(♡)」と揶揄されるほどだ。

 保育園時代の名残で今でもお互いのことを「ちゃん」、「くん」をつけて呼び合っているが、幼馴染以上恋人未満の関係が長く続くと、なぜかその慣れたはずの呼び方から妙にもどかしさを感じる日々になっているようだ。

 あの形で愛の告白さえすれば、今年のクリスマスは恋人同士として一緒に過ごせると、自分なりに工夫してきたつもりだったが、逆に墓穴を掘ってしまったのか?

この時期に相応しい愛に溢れた素敵な内容だった。

当初IPv4しか運べなかったBGPも魔改造が繰り返され、IPv6は当然としてMACなど何でもNLRIに詰めて運べる夢のControl Planeになった。(ref. BGP ParametersAFISAFIつまりは愛も運べるということ。

しかし、年末の忙しさでやさぐれ気味な私は記事のタイトルだけ見てRFC8203 BGP Administrative Shutdown Communicationが思い浮かんだ。

よくできたBGPはPath Attribute MP_UNREACH_NLRIを使うことで送ってしまった愛をなかったことすることができる。(いわゆるwithdraw)
関係を続けることすら嫌になった場合はMessage Type NOTIFICATIONを投げてBGP自体を切断することで綺麗さっぱり精算する。

RFC8203は “BGP Administrative Shutdown Communication” というタイトルの通り、NOTIFICATIONを送る際に任意のメッセージを添えてコミュニケーションをしよう、というもの。
例えば、自社のチケットIDなどを送ることで、相手が問い合わせる際に受け取ったチケットIDを伝えれば話が早いよね、と言った使い方。RFC8203がなくとも、BGPにはエラーコードエラーサブコードが規定されていてある程度のことを通知することは可能だが、自分の言葉じゃないと気持ちは伝わらないもの。
それを実現するのがRFC8203である。しらんけど。

本当に気持ちが伝えられるか試してみたいが、ただでさえ忙しい年末に物理配線する余裕もないし、物理でやると別れ話が意図せずリアリティを伴いかねないので仮想空間で行う。
仮想空間でネットワークのシミュレーションを行うアプリケーションは代表的なところでcontainerlabEVE-NGなどがあるが、今回は元ネタへの敬意を込めてCMLを利用した。ルータはCML 2.2.3(本ブログの執筆時点で最新は2.6.1なので相当古い)に付いてきたCisco XRv 9000(IOS-XR 7.2.2)と自分で用意したJuniper vMX(JUNOS 22.1R1)。ずいぶん古いOSが、RFC8203は2017年にpublishedなので大きな問題はないだろう。

なお、私個人としてはルータに関しては一切の無宗教。
あえて言うなら3高(高パフォーマンス、高機能、高電力効率)かつ4低(低CAPEX、低OPEX、低不具合、低フットプリント)な機械が好きです。素敵な提案待ってます❤️

トポロジはこんな感じ。あえて書くほどでもなかった。

“xr9kv-0″がXRv 9000、”vmx-{vfp,vcp}-0″がvMX。vMXに関してはアーキテクチャ的にforwarding planeとcontrol planeがノードとして分離されているが、ここでは気にする必要はなし。
ノード間のアドレスは考えるのがダルいのでLink Local Address fe80::/10とする。こういうとき便利よね、LLA。と言っても、結局Router IDでIPv4が必要になるのはあるある。IPv4 document address 192.0.2.0/24を使う。ASNはIIJのAS2497Private UseのAS4294967294

BGPの設定はわざわざ書くほどではない(あえて言えばLLAなのでinterfaceの指定が必要)のですっとばしestablishになった前提で、メッセージを送ってみる。
…という所まで来て、IOS-XRはRFC8203に対応していないことが判明。RFC8203のAuthorにCiscoの人がいるのに、これは完全に想定外。IOS-XRユーザ各位におかれましては是非ともEnhancement Requestを送りましょう。みんなの愛がメーカのBusiness Unitを動かします。(間違っていたら教えてください > シスコシステムズさん)
仕方ないのでLogical Systemという機能を使いvMXの中にもう1台仮想的なルータも作った。

早速、別れを切り出してみる。
ネットワークエンジニアたるもの、本命とは別にバックアップパスを常に確保しておくべきである。もちろんバックアップへの切換えはFRRやTI-LFAを駆使してぼっち期間はsub-secondで。

root@vmx-0# show | compare
[edit protocols bgp group 1]
+  shutdown {
+      notify-message "ごめんね、らうた君。私、今年のクリスマス🎄は別の人と過ごしたいの。あ、でも別れてもいい友達👫でいようね";
+  }

なお、AS同士の接続、いわゆるピアリングの世界において別れ話は de-peer と呼ばれ、現実世界と同じく日常的に起きていることである。

vMX同士ではログこそ化けてはいるが、”show bgp neighbor”からバッチリ気持ちが伝わったことがわかる。絵文字も問題なく表示され、表現力も高い。

Dec 14 14:05:04  vmx-0 ls:rpd[20281]: bgp_handle_notify:4529: NOTIFICATION received from fe80::5254:1:b:b12/0/0.2 (External AS 4294967294): code 6 (Cease) subcode 2 (Administratively Shutdown), Data: M-^AM-^TM-^BM-^AM-^BM-^SM-^AM-^@M-^AM-^BM-       M-^AM-^FM-^AM-^_M-^PM-^[M-^@M-^BM-^AM-^@M-^AM- 年M-^AM-^BM-^CM-^BM-^CM-^^M-^BM-^_M-^NM-^DM-^AM-^HM-^A人M-^AM-^AM-^NM-^AM-^TM-^AM-^WM-^AM-^_M-^AM-^DM-^AM-^@M-^BM-^AM-^BM-^@M-^AM-^AM-^BM-^BM-^HM-^BM-^LM-^AM-^BM-^BM-^AM-^DM-^AM-^DM-^OM-^KM-^AM-^TM-^_M-^QM-^AM-^AM-^DM-^BM-^HM-^AM-^FM-^A
 
root@vmx-0> show bgp neighbor logical-system ls
Peer: fe80::5254:1:b:b12%lt-0/0/0.2 AS 4294967294 Local: fe80::5254:2:b:b12%lt-0/0/0.2 AS 2497
  Last Received Notify Msg: ごめんね、らうた君。私、今年のクリスマス🎄は別の人と過ごしたいの。あ、でも別れてもいい友達👫でいようね
  Group: 1                   Routing-Instance: master
  Forwarding routing-instance: master 
  Type: External    State: Active         Flags: <>
  Last State: Idle          Last Event: Start
  Last Error: Open Message Error
  Options: <LocalAddress AddressFamily PeerAS Refresh>
  Options: <GracefulShutdownRcv>
  Address families configured: inet6-unicast
  Local Address: fe80::5254:2:b:b12 Holdtime: 90 Preference: 170
  Graceful Shutdown Receiver local-preference: 0
  Number of flaps: 11
  Last flap event: RecvNotify
  Error: 'Open Message Error' Sent: 13 Recv: 0
  Error: 'Cease' Sent: 0 Recv: 761
  Local Interface: lt-0/0/0.2

ここまで来るとどこまでいけるか試したくなるのがエンジニアのsaga。CLIでは制約が強そうなので、ネットワークエンジニアの強い味方であるRFC6241 NETCONFのパワーを借りる。

root@vmx-0> start shell
root@vmx-0:~ # cat <<EOF | ssh fe80::5254:ff:fe0b:b12%ge-0/0/0.0 -p 830 -s netconf
<rpc>
  <edit-config>
    <target>
      <candidate />
    </target>
    <default-operation>merge</default-operation>
    <config>
      <configuration>
        <protocols>
          <bgp>
            <group>
              <name>1</name>
              <shutdown operation="create">
                <notify-message>
   *    *  ()   *   *
*        * /\         *
      *   /i\\    *  *
    *     o/\\  *      *
 *       ///\i\    *
     *   /*/o\\  *    *
   *    /i//\*\      *
        /o/*\\i\   *
  *    //i//o\\\\     *
    * /*////\\\\i\*
 *    //o//i\\*\\\   *
   * /i///*/\\\\\o\   *
  *    *   ||     * jrei
                </notify-message>
              </shutdown>
            </group>
          </bgp>
        </protocols>               
      </configuration>
    </config>
  </edit-config>
</rpc>
]]>]]>
 
<rpc>
  <commit/>
</rpc>
]]>]]>
 
<rpc>
  <close-session/>
</rpc>
]]>]]>
EOF
 
Password:
<!-- No zombies were killed during the creation of this user interface -->
<!-- user root, class super-user -->
<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <capabilities>
    <capability>urn:ietf:params:netconf:base:1.0</capability>
    <capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>
    <capability>urn:ietf:params:netconf:capability:confirmed-commit:1.0</capability>
    <capability>urn:ietf:params:netconf:capability:validate:1.0</capability>
    <capability>urn:ietf:params:netconf:capability:url:1.0?scheme=http,ftp,file</capability>
    <capability>urn:ietf:params:xml:ns:netconf:base:1.0</capability>
    <capability>urn:ietf:params:xml:ns:netconf:capability:candidate:1.0</capability>
    <capability>urn:ietf:params:xml:ns:netconf:capability:confirmed-commit:1.0</capability>
    <capability>urn:ietf:params:xml:ns:netconf:capability:validate:1.0</capability>
    <capability>urn:ietf:params:xml:ns:netconf:capability:url:1.0?scheme=http,ftp,file</capability>
    <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring</capability>
    <capability>http://xml.juniper.net/netconf/junos/1.0</capability>
    <capability>http://xml.juniper.net/dmi/system/1.0</capability>
  </capabilities>
  <session-id>54379</session-id>
</hello>
]]>]]>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:junos="http://xml.juniper.net/junos/22.1R0/junos">
<ok/>
</rpc-reply>
]]>]]>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:junos="http://xml.juniper.net/junos/22.1R0/junos">
<ok/>
</rpc-reply>
]]>]]>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:junos="http://xml.juniper.net/junos/22.1R0/junos">
<ok/>
</rpc-reply>
]]>]]>
<!-- session end at 2023-12-16 04:34:59 UTC -->
root@vmx-0> show bgp neighbor logical-system ls
Peer: fe80::5254:1:b:b12%lt-0/0/0.2 AS 4294967294 Local: fe80::5254:2:b:b12%lt-0/0/0.2 AS 2497
  Last Received Notify Msg:    *    *  ()   *   *
  Last Received Notify Msg: *        * /\         *
  Last Received Notify Msg:       *   /i\\    *  *
  Last Received Notify Msg:     *     o/\\  *      *
  Last Received Notify Msg:  *       ///\i\    *
  Last Received Notify Msg:      *   /*/o\\  *    *
  Last Received Notify Msg:    *    /i//\*\      *
  Last Received Notify Msg:         /o/*\\i\   *
  Last Received Notify Msg:   *    //i//o\\\\     *
  Last Received Notify Msg:     * /*////\\\\i\*
  Last Received Notify Msg:  *    //o//i\\*\\\   *
  Last Received Notify Msg:    *
  Group: 1                   Routing-Instance: master
  Forwarding routing-instance: master 
  Type: External    State: Active         Flags: <>
  Last State: Idle          Last Event: Start
  Last Error: Open Message Error
  Options: <LocalAddress AddressFamily PeerAS Refresh>
  Options: <GracefulShutdownRcv>
  Address families configured: inet6-unicast
  Local Address: fe80::5254:2:b:b12 Holdtime: 90 Preference: 170
  Graceful Shutdown Receiver local-preference: 0
  Number of flaps: 18
  Last flap event: RecvNotify
  Error: 'Open Message Error' Sent: 13 Recv: 0
  Error: 'Cease' Sent: 0 Recv: 1760
  Local Interface: lt-0/0/0.2

表現力は無限大である。
ただし、RFC8203で規定されたメッセージの最大長は128Bで無限長ではない点に注意。愛というのは多少制約があるくらいのほうが燃えるらしいと聞くので問題ない。

なお、RFC8203では128Bだったメッセージ最大長だが、たった128Bでは私の気持ちは伝えきれない!という声が多かったからかRFC9003で255Bに拡張されている。調子に乗った上記のNETCONFはRFC9003の255Bすら超えて327Bあるが、vMXは気にせず送っているし、”show bgp neighbors”をよく見ると半端なところで途切れている。気になる人はJTACにcase openしてみてほしい。

一方でRFC8203非対応なXRv 9000は気持ちを全く理解してくれない。

RP/0/RP0/CPU0:Dec 14 14:05:06.839 UTC: bgp[1079]: %ROUTING-BGP-5-ADJCHANGE_DETAIL : neighbor fe80::5254:ff:fe0b:b12 Down - BGP Notification received, administrative shutdown (VRF: default; AFI/SAFI: 2/1) (AS: 4294967294)
 
RP/0/RP0/CPU0:xr9kv#show bgp ipv6 unicast neighbors
(snip)
  Connections established 27; dropped 27
  Local host: fe80::5054:ff:fe00:49bc, Local port: 179, IF Handle: 0x01000018
  Foreign host: fe80::5254:ff:fe0b:b12, Foreign port: 63787
  Last reset 00:00:02, due to BGP Notification received: administrative shutdown
  Time since last notification sent to neighbor: 1d05h
  Error Code: administrative reset
  Notification data sent:
    None
  Time since last notification received from neighbor: 00:00:02
  Error Code: administrative shutdown
  Notification data received:
    E38194E3 8281E382 93E381AD E38081E3
    8289E381 86E3819F E5909BE3 8082E7A7
    81E38081 E4BB8AE5 B9B4E381 AEE382AF
    E383AAE3 82B9E383 9EE382B9 F09F8E84
    E381AFE5 88A5E381 AEE4BABA E381A8E9
    818EE381 94E38197 E3819FE3 8184E381
    AEE38082 E38182E3 8081E381 A7E38282
    E588A5E3 828CE381 A6E38282 E38184E3
    8184E58F 8BE98194 F09F91AB E381A7E3
    8184E382 88E38186 E381AD

これではXRv 9000が何を受け取ったかわからないので、パケットを直接見てみる。簡単にキャプチャできるのも仮想環境の良いところ。
RFC8203ではUTF-8でencodeすべしとあるので、decodeを試みる。
どうやらwireshark(CLI版がtshark)もRFC8203には対応していないようだ。是非とも冬休みの課題として実装に取り組んでみて欲しい(他力本願)。

$ tshark -n -r rfc8203.pcap
1 0.000000 fe80::5254:ff:fe0b:b12 → fe80::5054:ff:fe00:49bc BGP 93 KEEPALIVE Message
2 0.203562 fe80::5054:ff:fe00:49bc → fe80::5254:ff:fe0b:b12 TCP 74 52404 → 179 [ACK] Seq=1 Ack=20 Win=32624 Len=0
3 12.628171 fe80::5254:ff:fe0b:b12 → fe80::5054:ff:fe00:49bc BGP 250 NOTIFICATION Message
4 12.632593 fe80::5054:ff:fe00:49bc → fe80::5254:ff:fe0b:b12 TCP 74 52404 → 179 [FIN, ACK] Seq=1 Ack=196 Win=32448 Len=0
5 12.634235 fe80::5254:ff:fe0b:b12 → fe80::5054:ff:fe00:49bc TCP 74 179 → 52404 [FIN, ACK] Seq=196 Ack=1 Win=16384 Len=0
6 12.635164 fe80::5254:ff:fe0b:b12 → fe80::5054:ff:fe00:49bc TCP 74 [TCP Retransmission] 179 → 52404 [FIN, ACK] Seq=196 Ack=2 Win=16384 Len=0
7 12.636126 fe80::5054:ff:fe00:49bc → fe80::5254:ff:fe0b:b12 TCP 74 52404 → 179 [ACK] Seq=2 Ack=197 Win=32448 Len=0
8 12.636826 fe80::5054:ff:fe00:49bc → fe80::5254:ff:fe0b:b12 TCP 74 [TCP Dup ACK 7#1] 52404 → 179 [ACK] Seq=2 Ack=197 Win=32448 Len=0
9 12.931709 fe80::5054:ff:fe00:49bc → fe80::5254:ff:fe0b:b12 TCP 74 [TCP Retransmission] 52404 → 179 [FIN, ACK] Seq=1 Ack=197 Win=32448 Len=0
10 12.933369 fe80::5254:ff:fe0b:b12 → fe80::5054:ff:fe00:49bc TCP 74 [TCP Dup ACK 6#1] 179 → 52404 [ACK] Seq=197 Ack=2 Win=16384 Len=0
 
$ tshark -n -r rfc8203.pcap -Y "frame.number==3" -VV -x
(snip)
Border Gateway Protocol - NOTIFICATION Message
    Marker: ffffffffffffffffffffffffffffffff
    Length: 176
    Type: NOTIFICATION Message (3)
    Major error Code: Cease (6)
    Minor error Code (Cease): Administratively Shutdown (2)
    Data [truncated]: e38194e38281e38293e381ade38081e38289e38186e3819fe5909be38082e7a781e38081e4bb8ae5b9b4e381aee382afe383aae382b9e3839ee3
82b9f09f8e84e381afe588a5e381aee4babae381a8e9818ee38194e38197e3819fe38184e381aee38082e38182e38081e381a7e38
 
0000  52 54 00 00 49 bc 52 54 00 0b 0b 12 86 dd 6c 03   RT..I.RT......l.
0010  a6 cb 00 c4 06 01 fe 80 00 00 00 00 00 00 52 54   ..............RT
0020  00 ff fe 0b 0b 12 fe 80 00 00 00 00 00 00 50 54   ..............PT
0030  00 ff fe 00 49 bc 00 b3 cc b4 a9 42 fd 44 a4 f0   ....I......B.D..
0040  88 b4 50 18 40 00 cd 43 00 00 ff ff ff ff ff ff   ..P.@..C........
0050  ff ff ff ff ff ff ff ff ff ff 00 b0 03 06 02 e3   ................
0060  81 94 e3 82 81 e3 82 93 e3 81 ad e3 80 81 e3 82   ................
0070  89 e3 81 86 e3 81 9f e5 90 9b e3 80 82 e7 a7 81   ................
0080  e3 80 81 e4 bb 8a e5 b9 b4 e3 81 ae e3 82 af e3   ................
0090  83 aa e3 82 b9 e3 83 9e e3 82 b9 f0 9f 8e 84 e3   ................
00a0  81 af e5 88 a5 e3 81 ae e4 ba ba e3 81 a8 e9 81   ................
00b0  8e e3 81 94 e3 81 97 e3 81 9f e3 81 84 e3 81 ae   ................
00c0  e3 80 82 e3 81 82 e3 80 81 e3 81 a7 e3 82 82 e5   ................
00d0  88 a5 e3 82 8c e3 81 a6 e3 82 82 e3 81 84 e3 81   ................
00e0  84 e5 8f 8b e9 81 94 f0 9f 91 ab e3 81 a7 e3 81   ................
00f0  84 e3 82 88 e3 81 86 e3 81 ad                     ..........
 
$ tshark -n -r rfc8203.pcap -Y "frame.number==3" -T fields -e bgp.notify.minor_data | ruby -e 'p [STDIN.read.chomp].pack("H*").force_encoding("utf-8")'
"ごめんね、らうた君。私、今年のクリスマス🎄は別の人と過ごしたいの。あ、でも別れてもいい友達👫でいようね"

気持ちは間違いなく伝わっていた。
FIN,ACKも返ってきているのが何よりの証拠である。再送しているのは、念のための確認か。確かに重大な局面なので、間違いは許されない。

 

まとめ。BGPはやはり何でも運べる夢のプロトコルである。もちろん、愛もね。

 

流宇太と詩須子がde-peerすることなく素敵な新年を迎えられますように。

With love on BGP,

IIJ Engineers blog読者プレゼントキャンペーン

Xのフォロー&条件付きツイートで、「IoT米」と「バリーくんシール」のセットを抽選でプレゼント!
応募期間は2023/12/01~2023/12/31まで。詳細はこちらをご覧ください。
今すぐポストするならこちら→ フォローもお忘れなく!

hori

2023年12月22日 金曜日

社長室兼基盤エンジニアリング本部所属。これだけ見るとフルスタックエンジニアを超越しているが、実態はネットワークを中心にしたインフラ全般の企画が主なお仕事。AS2497 / The Internet / BGP / SRv6

Related
関連記事