SDN開発エンジニアを目指した活動ブログ

〜SDNなオープンソース製品を実際に使って試してみる〜

Ryu SDN FrameworkのBGP機能を試してみた(1) 〜BGP/MPLS網でのエッジルータ適用編〜

最新のRyu SDN Frameworkでは、BGPルーティング機能(以下、Ryu BGP)が活用できるようになったらしいです。
Ryu公式ドキュメントにも、API仕様やサンプルコードが公開されておりますね。
BGP speaker library API Reference — Ryu 3.12 documentation
BGP speaker library — Ryu 3.12 documentation

ここで注目したい点は、通信キャリアで活用されているBGP/MPLS VPN網の通信プロトコルに対応しているところなのです。
まだまだ活用事例が少ないので、最初から手探り状態で、どの程度、基本動作が可能なのかを試してみました。

◆そもそも、BGP/MPLS VPNとは ...

BGP/MPLS VPNによるC-Plane/D-Plane分離に関わる通信プロトコル基本動作原理の解説については、ブログ記事の領域を超越してしまうため、割愛させて頂きます。この技術分野に興味を持たれる方は、こちらの文献が一読されることを、お勧め致します。

インターネットルーティング入門 第3版

インターネットルーティング入門 第3版

昔のインターネット普及以前では、企業ユーザの各拠点間を専用線などの占有タイプのネットワークサービスを活用して相互接続を図っておりました。その後のインターネット技術の台頭あたりから、拠点間の相互接続を通信キャリアが運営する閉域ネットワークに重畳することにより、通信コストの低減を図りつつ、安定的なネットワーク品質のVPN環境を利用する時代に移行してきました。
ここでの、閉域ネットワークのスケール自動化を目的とした管理制御手法として、BGP/MPLS VPN技術が活用されてきました。
もともとは、BGP/MPLS VPNは、通信キャリア分野で活用していた技術でしたが、ルータ機器で動作する通信プロトコルは、ベンダプロプライエタリーな技術領域であり、技術エンジニア自らが、改変できるものではありませんでした。(一部、Quagga等のオープンソース製品はありましたが、)

最近のSDNによるC-Plane/D-Plane分離技術の台頭により、オープンソースベースのBGP/MPLSを活用したDC/WAN領域でのシームレスなマルチテナント制御が注目されております。(最近では、OpenContrailが有名でしょうか。)

ところで、BGP/MPLS VPNを活用したMPLS-VPN網には、どのような特徴があるのでしょうか?
ざっくり言えば、物理トポロジを構成する物理リソースをBGP/MPLS VPNを活用してオートスケールなアクティベーションを可能とする技術となります。

f:id:ttsubo:20140815223159j:plain
拠点間での相互接続およびテナント分離に関わる基本動作は、概ねエッジルータ(PE)で行うことになります。
さらに、拠点間でのL3経路情報の伝搬および拠点間の通信経路選定に関わる通信制御系の動作と拠点間のデータ転送系の動作は、明示的に分離されている特徴があります。昨今のSDNによるC-Plane/D-Plane分離技術に通じるものです。

f:id:ttsubo:20140815223700j:plain

◆Ryu BGP検証環境

BGP/MPLS VPN網ではエッジルータの役割が非常に重要ということになりますので、Ryu BGP機能のエッジルータ適用を想定した検証モデルを構築します。実際のBGP/MPLS VPN網は、GNS3によるCiscoエミュレータソフトを活用しました。
f:id:ttsubo:20140815224625j:plain

1. 制御系ネットワーク
本来のBGP/MPLS VPN網でのエッジルータでは、エッジルータ間の相互接続としてOSPF, LDPなどのトンネル・ルーティング制御が必要不可欠となるわけですが、今回は、この技術領域の検証は行いません。ただし、BGPプロトコルでは、NextHop指定として、Ryu BGP〜各PE間での到達性が必要となるため、Ryu BGPサーバも各PE間で構築されたOSPFルーティング面に参加される必要がありました。今回は、Ryu BGPサーバ自体でOSPFプロトコルを扱うことはせず、Ryu BGP〜RR間をパッシブインターフェース区間として扱いました。
f:id:ttsubo:20140815224436j:plain

2. 転送系ネットワーク
本来、BGPプロトコルで学習した拠点間経路情報をデータプレーンに注入する必要があります。
ただし、これを実現するために要素技術として、OpenFlow連携等を想定しなければなりません。
そもそも、BGP/MPLS VPN網でのエッジルータ間でデータプレーンを構築するためには、別途、LDPプロトコルの実装も必要になるため、今回は対象外としました。
近い将来、エッジルータ間をMPLSベースのトンネルでは無く、GREベースのトンネル技術を活用した転送系ネットワーク構築にチャレンジしたいと考えています。

3. Ryu BGPでの実装コード
Ryu公式ドキュメントでの、API仕様やサンプルコードを参考に、検証用のサンプルコード(sampleBGP_for_MPLS-VPN.py)を準備しました。

import eventlet
import time

eventlet.monkey_patch()

import logging
import sys
logging.basicConfig(level=logging.INFO)

from ryu.services.protocols.bgp.bgpspeaker import BGPSpeaker

def dump_remote_best_path_change(event):
    print 'the best path changed:', event.remote_as, event.prefix,\
        event.nexthop, event.is_withdraw

if __name__ == "__main__":
    speaker = BGPSpeaker(as_number=65010, router_id='10.0.0.8',
                         best_path_change_handler=dump_remote_best_path_change, ssh_console=True)

    speaker.neighbor_add('192.168.100.100', 65010, enable_ipv4=True, enable_vpnv4=True)
    speaker.vrf_add('65010:101', ['65010:101'], ['65010:101'])
    eventlet.sleep(5)
    speaker.prefix_add('192.168.104.0/30', next_hop='0.0.0.0', route_dist='65010:101')

    while True:
        eventlet.sleep(5)

◆Ryu BGP動作結果

1. 事前のBGPテーブル確認
CE1でのBGPテーブルには、CE1, CE2, CE3に関わるプレフィックス情報が出力されております。
Ryu BGPの起動前であるため、CE4に関わるプレフィックス情報は出力されておりません。

CE1#sh bgp ipv4 unicast 
BGP table version is 10, local router ID is 10.10.10.1
Status codes: s suppressed, d damped, h history, * valid, > best, i - internal, 
              r RIB-failure, S Stale, m multipath, b backup-path, f RT-Filter, 
              x best-external, a additional-path, c RIB-compressed, 
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found

     Network          Next Hop            Metric LocPrf Weight Path
 *>  10.10.10.1/32    0.0.0.0                  0         32768 ?
 *>  10.10.10.2/32    192.168.101.2                          0 65010 65012 ?
 *>  10.10.10.3/32    192.168.101.2                          0 65010 65013 ?
 *   192.168.101.0/30 192.168.101.2            0             0 65010 ?
 *>                   0.0.0.0                  0         32768 ?
 *>  192.168.102.0/30 192.168.101.2                          0 65010 ?
 *>  192.168.103.0/30 192.168.101.2                          0 65010 ?
 *>  192.168.201.0    0.0.0.0                  0         32768 i
 *>  192.168.202.0    192.168.101.2                          0 65010 65012 i
 *>  192.168.203.0    192.168.101.2                          0 65010 65013 i

2. Ryu BGPサンプルコード実行開始
サンプルコード(sampleBGP_for_MPLS-VPN.py)では、以下の処理を実行します。
(1) RR〜Ryu BGP間でBGPピアを開設
(2) VRF登録
(3) Ryu BGP〜CE4間のコネク区間(192.168.104.0/30)の経路情報登録

その実行結果です。

$ sudo python ./sampleBGP_for_MPLS-VPN.py 
[sudo] password for tsubo: 
INFO:bgpspeaker.api.base:API method core.start called with args: {'router_id': '10.0.0.8', 'waiter': <ryu.lib.hub.Event object at 0x7fe52d3ab450>, 'bgp_server_port': 179, 'local_as': 65010, 'refresh_max_eor_time': 0, 'refresh_stalepath_time': 0}
INFO:bgpspeaker.api.base:API method neighbor.create called with args: {'remote_as': 65010, 'cap_mbgp_vpnv6': False, 'cap_mbgp_vpnv4': True, 'cap_mbgp_ipv6': False, 'cap_mbgp_ipv4': True, 'is_route_server_client': False, 'peer_next_hop': None, 'password': None, 'ip_address': '192.168.100.100'}
INFO:bgpspeaker.api.base:API method vrf.create called with args: {'import_rts': ['65010:101'], 'route_family': 'ipv4', 'site_of_origins': None, 'route_dist': '65010:101', 'export_rts': ['65010:101']}
INFO:bgpspeaker.cli:starting ssh server at localhost:4990
INFO:bgpspeaker.peer:Connection to peer: 192.168.100.100 established
INFO:bgpspeaker.api.base:API method prefix.add_local called with args: {'prefix': '192.168.104.0/30', 'next_hop': '0.0.0.0', 'route_dist': '65010:101', 'route_family': 'ipv4'}

.. (snip)

3. Ryu BGPでのCLIによりBGPテーブル等の状態確認
RR〜Ryu BGP間でのBGPピア開設/VRF登録に伴い、BGP/MPLS VPN網からのVRFプレフィックス情報を取得できている様子が確認できます。さらに、Ryu BGP〜CE4間のコネク区間(192.168.104.0/30)の経路情報も確認できます。

$ ssh localhost -p 4990

Hello, this is Ryu BGP speaker (version 3.12).

bgpd> show vrf 65010:101 ipv4
Status codes: * valid, > best
Origin codes: i - IGP, e - EGP, ? - incomplete
     Network                          Labels   Next Hop             Reason          Metric LocPrf Path
 *>  192.168.202.0/24                 None     10.0.0.4             Only Path       0      100    65012 i
 *>  10.10.10.1/32                    None     10.0.0.1             Only Path       0      100    65011 ?
 *>  192.168.102.0/30                 None     10.0.0.4             Only Path       0      100    ?
 *>  192.168.104.0/30                 None     0.0.0.0              Only Path                     ?
 *>  10.10.10.3/32                    None     10.0.0.3             Only Path       0      100    65013 ?
 *>  192.168.203.0/24                 None     10.0.0.3             Only Path       0      100    65013 i
 *>  10.10.10.2/32                    None     10.0.0.4             Only Path       0      100    65012 ?
 *>  192.168.201.0/24                 None     10.0.0.1             Only Path       0      100    65011 i
 *>  192.168.103.0/30                 None     10.0.0.3             Only Path       0      100    ?
 *>  192.168.101.0/30                 None     10.0.0.1             Only Path       0      100    ?
bgpd> 
bgpd> show rib vpnv4
Status codes: * valid, > best
Origin codes: i - IGP, e - EGP, ? - incomplete
     Network                          Labels   Next Hop             Reason          Metric LocPrf Path
 *>  65010:101:10.10.10.3/32          [29]     10.0.0.3             Only Path       0      100    65013 ?
 *>  65010:101:192.168.202.0/24       [30]     10.0.0.4             Only Path       0      100    65012 i
 *>  65010:101:10.10.10.1/32          [29]     10.0.0.1             Only Path       0      100    65011 ?
 *>  65010:101:192.168.101.0/30       [30]     10.0.0.1             Only Path       0      100    ?
 *>  65010:101:192.168.201.0/24       [31]     10.0.0.1             Only Path       0      100    65011 i
 *>  65010:101:192.168.103.0/30       [30]     10.0.0.3             Only Path       0      100    ?
 *>  65010:101:192.168.102.0/30       [29]     10.0.0.4             Only Path       0      100    ?
 *>  65010:101:10.10.10.2/32          [28]     10.0.0.4             Only Path       0      100    65012 ?
 *>  65010:101:192.168.203.0/24       [31]     10.0.0.3             Only Path       0      100    65013 i
 *>  65010:101:192.168.104.0/30       [100]    0.0.0.0              Only Path                     ?
bgpd> 

4. CE1でのCLIによりBGPテーブル等の状態確認
RR〜Ryu BGP間でのBGPピア開設/VRF登録に伴い、Ryu BGPからのVRFプレフィックス情報を取得できている様子が確認できます。さらに、Ryu BGP〜CE4間のコネク区間(192.168.104.0/30)の経路情報も確認できます。

CE1#sh bgp ipv4 unicast 
BGP table version is 13, local router ID is 10.10.10.1
Status codes: s suppressed, d damped, h history, * valid, > best, i - internal, 
              r RIB-failure, S Stale, m multipath, b backup-path, f RT-Filter, 
              x best-external, a additional-path, c RIB-compressed, 
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found

     Network          Next Hop            Metric LocPrf Weight Path
 *>  10.10.10.1/32    0.0.0.0                  0         32768 ?
 *>  10.10.10.2/32    192.168.101.2                          0 65010 65012 ?
 *>  10.10.10.3/32    192.168.101.2                          0 65010 65013 ?
 *   192.168.101.0/30 192.168.101.2            0             0 65010 ?
 *>                   0.0.0.0                  0         32768 ?
 *>  192.168.102.0/30 192.168.101.2                          0 65010 ?
 *>  192.168.103.0/30 192.168.101.2                          0 65010 ?
 *>  192.168.104.0/30 192.168.101.2                          0 65010 ?
 *>  192.168.201.0    0.0.0.0                  0         32768 i
 *>  192.168.202.0    192.168.101.2                          0 65010 65012 i
 *>  192.168.203.0    192.168.101.2                          0 65010 65013 i

◆おまけ(BGP Update Messageパケットの各種パラメータ値をのぞいてみる)

Ryu BGPでは、BGPピアでの送受信単位にBGP Update Messageパケットの各種パラメータ値を確認することができます。各種アドレスファミリー毎に確認するも可能です。
複数のRyu BGPサーバ間でBGPピアを開設した上で、BGP Update Messageパケットの各種パラメータ値をのぞいてみると、BGP学習環境を簡単に構築できるメリットがあると思います。

1. Ryu BGP側でのmpBGP Update Messageの確認
さきほどの「◆Ryu BGP動作結果」後に、Ryu BGPのCLIから、RRに送信したBGP Update Message

bgpd> show neighbor sent-routes 192.168.100.100 all

{'65010:101:192.168.104.0/30': {'as_path': [],
                                'is_withdraw': False,
                                'local_pref': None,
                                'metric': None,
                                'nexthop': '0.0.0.0',
                                'nlri': {'formatted_nlri': '65010:101:192.168.104.0/30',
                                         'labels': [100],
                                         'prefix': '192.168.104.0/30',
                                         'rd': '65010:101'},
                                'origin': 2,
                                'route_family': {'afi': 1, 'safi': 128},
                                'rt_list': ['65010:101'],
                                'soo_list': [],
                                'source_version_num': 0}}

2. 既存BGP/MPLS側でのmpBGP Update Messageの確認
PE1側で受信したBGP Update Messageパケットの各種パラメータ値を確認しました。
Ryu BGPのCLIで確認したNextHop値と、PE1側で受信したNextHop値が異なる点については、今度とも留意が必要かもしれません。

No.     Time           Source                Destination           Protocol Length Info
   1247 1030.151634000 10.0.0.7              10.0.0.1              BGP      152    UPDATE Message

Frame 1247: 152 bytes on wire (1216 bits), 152 bytes captured (1216 bits) on interface 0
Ethernet II, Src: ca:06:09:87:00:1c (ca:06:09:87:00:1c), Dst: ca:04:09:78:00:1d (ca:04:09:78:00:1d)
Internet Protocol Version 4, Src: 10.0.0.7 (10.0.0.7), Dst: 10.0.0.1 (10.0.0.1)
Transmission Control Protocol, Src Port: bgp (179), Dst Port: 49516 (49516), Seq: 343, Ack: 362, Len: 98
Border Gateway Protocol - UPDATE Message
    Marker: ffffffffffffffffffffffffffffffff
    Length: 98
    Type: UPDATE Message (2)
    Unfeasible routes length: 0 bytes
    Total path attribute length: 75 bytes
    Path attributes
        ORIGIN: INCOMPLETE (4 bytes)
            Flags: 0x40 (Well-known, Transitive, Complete)
                0... .... = Optional: Well-known
                .1.. .... = Transitive: Transitive
                ..0. .... = Partial: Complete
                ...0 .... = Length: Regular length
            Type code: ORIGIN (1)
            Length: 1 byte
            Origin: INCOMPLETE (2)
        AS_PATH: empty (3 bytes)
            Flags: 0x40 (Well-known, Transitive, Complete)
                0... .... = Optional: Well-known
                .1.. .... = Transitive: Transitive
                ..0. .... = Partial: Complete
                ...0 .... = Length: Regular length
            Type code: AS_PATH (2)
            Length: 0 bytes
            AS path: empty
        LOCAL_PREF: 100 (7 bytes)
            Flags: 0x40 (Well-known, Transitive, Complete)
                0... .... = Optional: Well-known
                .1.. .... = Transitive: Transitive
                ..0. .... = Partial: Complete
                ...0 .... = Length: Regular length
            Type code: LOCAL_PREF (5)
            Length: 4 bytes
            Local preference: 100
        EXTENDED_COMMUNITIES: (11 bytes)
            Flags: 0xc0 (Optional, Transitive, Complete)
                1... .... = Optional: Optional
                .1.. .... = Transitive: Transitive
                ..0. .... = Partial: Complete
                ...0 .... = Length: Regular length
            Type code: EXTENDED_COMMUNITIES (16)
            Length: 8 bytes
            Carried Extended communities
                two-octet AS specific Route Target: 65010:101
        CLUSTER_LIST: 10.0.0.7 (7 bytes)
            Flags: 0x80 (Optional, Non-transitive, Complete)
                1... .... = Optional: Optional
                .0.. .... = Transitive: Non-transitive
                ..0. .... = Partial: Complete
                ...0 .... = Length: Regular length
            Type code: CLUSTER_LIST (10)
            Length: 4 bytes
            Cluster list: 10.0.0.7
                Cluster List: 0a000007
        ORIGINATOR_ID: 10.0.0.8 (7 bytes)
            Flags: 0x80 (Optional, Non-transitive, Complete)
                1... .... = Optional: Optional
                .0.. .... = Transitive: Non-transitive
                ..0. .... = Partial: Complete
                ...0 .... = Length: Regular length
            Type code: ORIGINATOR_ID (9)
            Length: 4 bytes
            Originator identifier: 10.0.0.8 (10.0.0.8)
        MP_REACH_NLRI (36 bytes)
            Flags: 0x80 (Optional, Non-transitive, Complete)
                1... .... = Optional: Optional
                .0.. .... = Transitive: Non-transitive
                ..0. .... = Partial: Complete
                ...0 .... = Length: Regular length
            Type code: MP_REACH_NLRI (14)
            Length: 33 bytes
            Address family: IPv4 (1)
            Subsequent address family identifier: Labeled VPN Unicast (128)
            Next hop network address (12 bytes)
                Next hop: Empty Label Stack RD=0:0 IPv4=192.168.100.102 (12)
            Subnetwork points of attachment: 0
            Network layer reachability information (16 bytes)
                Label Stack=100 (bottom) RD=65010:101, IPv4=192.168.104.0/30
                    MP Reach NLRI Prefix length: 118
                    MP Reach NLRI Label Stack: 100 (bottom)
                    MP Reach NLRI Route Distinguisher: 65010:101
                    MP Reach NLRI IPv4 prefix: 192.168.104.0 (192.168.104.0)

◆おわりに

今回は、最新のRyu SDN Frameworkにおける、BGPルーティング機能の動作確認として、BGP/MPLS VPN網で同一AS内でのエッジルータ適用を想定した検証モデルで試してみました。BGPについては、アドレスファミリー(IPv4, VPNv4)において、問題なく動作しておりました。ただし、エッジルータ適用を想定した場合、コントロールプレーンでの他のプロトコル連携の実現形態を想定するとなると、相当なるハードルが待ち構えている点が懸念されます。将来のデータプレーン連携を想定した場合、BGP/MPLS VPN網とのInter-AS接続形態のほうが、基本動作がシンプルになると想定されるます。現状のRyu BGPを、BGP/MPLS VPN網でのエッジルータとして実網に適用するユースケースは現実解として適切ではないと思われます。