JANOG53 では NETCON の作問や採点回りを担当しました!
こちらのブログでは、level 4-2 の問題について解説します。

level 4-2 問題の概要

トポロジ

問題文

LB01 の配下に認証用の Server を冗長化して設置し、Client01 から LB01 の Frontend IP (10.150.0.100) に対して認証用の通信を行います。

認証用の通信は複数のコネクションを張る必要がありますが、仕様上すべてのコネクションが同じ Backend Server に到達する必要があります。

認証用のプログラムは Client01 の /root/auth.py にあり、 python3 auth.py で実行可能です。

しかし、現在は Client01 から 10.150.0.100 までの到達性がなく、認証に失敗してしまいます。

まずは Client01 から LB01 の Frontend IP (10.150.0.100) への到達性を確保し、その後認証用のプログラムがすべて OK となるよう、ネットワーク構成を変更してください。

達成条件

  • Client01 から LB01 の Frontend IP (10.150.0.100) に到達性があること (iBGP を使用し、 ECMP で冗長性を持たせてください。)
  • Backend Server の冗長性は維持されていること
  • python3 auth.pyの結果がすべて OK となること

制約

  • Client01 内の auth.py を編集しないでください。(中身の閲覧は可能です)
  • 各 L3SW および RT 間は iBGP でネイバーを確立してください。
  • Server01, Server02にはログインできません

補足事項

L3SW01 : SONiC
RT01 : cEOS
RT02 : cEOS
L3SW02 : cEOS
Client01 : Alpine Linux
LB01 : Alpine Linux で openrc を利用して LVS が稼働
Server01 : http リクエストを受け付け、Server01 という文字列を返す
Server02 : http リクエストを受け付け、Server02 という文字列を返す

スポンサーリンク




初期 Config

L3SW01 initial config – /etc/frr/zebra.conf

interface eth1 
 description To_RT01 
 ip address 10.11.0.2/30 
 no shutdown

interface eth2 
 description To_RT02 
 ip address 10.21.0.2/30 
 no shutdown

interface eth3 
 description To_Client01 
 ip address 10.100.0.254/24 
 no shutdown

L3SW01 initial config – /etc/frr/bgpd.conf

router bgp 64512
 maximum-paths 100
 neighbor 10.11.0.1 remote-as 64512
 neighbor 10.11.0.1 update-source eth1
 neighbor 10.21.0.1 remote-as 64512
 neighbor 10.21.0.1 update-source eth2
 network 10.100.0.0/24

L3SW02 initial config

hostname L3SW02

interface Ethernet1
 description To_RT01
 no switchport
 ip address 10.12.0.2/30
 no shut

interface Ethernet2
 description To_RT02
 no switchport
 ip address 10.22.0.2/30
 no shut

vlan 200

interface Ethernet3
 description To_LB01_Backend_Port
 switchport mode access
 switchport access vlan 200
 no shut

interface Ethernet4
 description To_LB_Frontend_Port
 no switchport
 ip address 10.150.0.254/24
 no shut

interface Ethernet5
 description To_Server01
 switchport mode access
 switchport access vlan 200
 no shut

interface Ethernet6
 description To_Server02
 switchport mode access
 switchport access vlan 200
 no shut

interface vlan200
 description Vlan200_Gateway
 ip add 10.200.0.254/24
 no shut

ip routing

router bgp 64512
 maximum-paths 100
 neighbor 10.12.0.1 remote-as 64512
 neighbor 10.12.0.1 update-source Ethernet1
 neighbor 10.22.0.1 remote-as 64512
 neighbor 10.22.0.1 update-source Ethernet2
 network 10.200.0.0/24

RT01 initial config

hostname RT01

interface Ethernet1
 description To_L3SW01
 no switchport
 ip address 10.11.0.1/30
 no shut

interface Ethernet2
 description To_L3SW02
 no switchport
 ip address 10.12.0.1/30
 no shut

route-map Change_NH_To_10_11_0_1
 set ip next-hop 10.11.0.1
route-map Change_NH_To_10_12_0_1
 set ip next-hop 10.12.0.1

ip routing

router bgp 64512
 neighbor 10.11.0.2 remote-as 64512
 neighbor 10.11.0.2 update-source Ethernet1
 neighbor 10.12.0.2 remote-as 64512
 neighbor 10.12.0.2 update-source Ethernet2

RT02 initial config

hostname RT02

interface Ethernet1
 description To_L3SW01
 no switchport
 ip address 10.21.0.1/30
 no shut

interface Ethernet2
 description To_L3SW02
 no switchport
 ip address 10.22.0.1/30
 no shut

route-map Change_NH_To_10_21_0_1
 set ip next-hop 10.21.0.1
route-map Change_NH_To_10_22_0_1
 set ip next-hop 10.22.0.1

ip routing

router bgp 64512
 neighbor 10.21.0.2 remote-as 64512
 neighbor 10.21.0.2 update-source Ethernet1
 neighbor 10.22.0.2 remote-as 64512
 neighbor 10.22.0.2 update-source Ethernet2

auth.py

import requests
import sys

auth_url = 'http://10.150.0.100/'

class Authenticator():
    def request_authentication(self):
        try:
            response = requests.get(auth_url, timeout=1)
            content_without_empty_lines = response.text.replace('\n', '')
            return content_without_empty_lines
        except:
            print("例外が発生しました。")
            print(sys.exc_info())
            exit()

def main():
    authenticator = Authenticator()

    first_result = authenticator.request_authentication()
    for i in range(1, 11):
        tmp_result = authenticator.request_authentication()

        if first_result == tmp_result:
            print("Step" + str(i) + " = " + "OK")
        else:
            print("Step" + str(i) + " = " + "ERROR")

main()

想定解答

① L3SW01 で bgpd を起動する必要があります。

`sed -i -e 's/bgpd=no/bgpd=yes/g' /etc/frr/daemons`
service frr restart

②L3SW02/RT01/RT02 で iBGP に関する設定を投入する必要があります。

L3SW02
router bgp 64512
 network 10.150.0.0/24

RT01
router bgp 64512
 neighbor 10.11.0.2 route-reflector-client
 neighbor 10.11.0.2 route-map Change_NH_To_10_11_0_1 out 
 neighbor 10.12.0.2 route-reflector-client
 neighbor 10.12.0.2 route-map Change_NH_To_10_12_0_1 out

RT02
router bgp 64512
 neighbor 10.21.0.2 route-reflector-client
 neighbor 10.21.0.2 route-map Change_NH_To_10_21_0_1 out
 neighbor 10.22.0.2 route-reflector-client
 neighbor 10.22.0.2 route-map Change_NH_To_10_22_0_1 out

③LB01 でセッションパーシステンスを有効化する必要があります。

ipvsadm -C
ipvsadm -A -t 10.150.0.100:80 -s rr -p
ipvsadm -a -t 10.150.0.100:80 -r 10.200.0.1:80 -m
ipvsadm -a -t 10.150.0.100:80 -r 10.200.0.2:80 -m

rc-service ipvsadm save
rc-service ipvsadm restart

解説

①L3SW01 で bgpd を起動

まずは L3SW01 で bgpd を起動する必要がありました。
これは SONiC では BGP の実装に FRR を利用しているためです。

少し古い部分もありますが、SONiC のアーキテクチャ概要は以下に記載があります。
Architecture · sonic-net/SONiC Wiki (github.com)

②L3SW02/RT01/RT02 で iBGP に関する設定を投入

以下の 3 点が達成できていれば基本的には点数となったはずです。
・route-reflector-client の設定
・nexthop-self の設定 (route-map でも nexthop-self でも ok)
・10.150.0.0/24 の広報

認証プログラムの疎通性があったとしても、Static Route での設定や、ECMP で冗長化されていない場合など、減点しています。

③LB01 でセッションパーシステンスを有効化

アプリケーションによっては異なるセッションが同じ Backend Server に到達する要件を持つ場合があり、それを簡易的に再現させました。

最初は LVS の -p オプションで session persistence を有効化する解答を想定していましたが、scheduling method を sh (soure hashing) とする方法も正解としました。

いくつか scheduling method を lblc としている回答がありましたが、サーバーの負荷状況によってはアプリケーションの要件を満たさない場合があると考え、減点しました。

lblc – Locality-Based Least-Connection: assigns jobs destined for the same IP address to the same server if the server is not overloaded and available; otherwise assign jobs to servers with fewer jobs, and keep it for future assignment.

ipvsadm(8) — ipvsadm — Debian unstable — Debian Manpages

※ 私も LVS にそこまで明るいわけではないので、見当違いだったら申し訳ありません。。

これらの設定を実施すると、 auth.py の実行結果がすべて ok となります。

おわりに

問題を解いていただいた皆様ありがとうございました!

皆様の解答を拝見して、すこし問題の前提条件が甘かったかなと反省しています。
反省点は次回に活かします!

本問題が SONiC や LVS を知るきっかけになれば幸いです。