bobuhiro11/mininetlab - GitHub

Mininet 1 の中でSRv6 L3VPNを動かす実験をやってみた。 スクリプトはこちら

srv6l3vpn

ひとまず図のような小さな構成で動かすことができたのでここで紹介したい。 2台のルータ(r1とr2)がSRv6によるEncap/Decapを担当しており、 r1-r2間でL3VPNに関する情報をeBGPで交換する。 r1とr2はそれぞれ2つのVRF(vrf10とvrf20)を持っており、 VRFごとにテナントが分けられている(Tenant10とTenant20)。 もちろんテナントごとにL3の疎通性はなくIPレンジの重複は許されているので、 ここでは同じPrefixを割り当てている。

r1とr2ではBGPデーモンとしてFRRを使っている。設定の一部を抜粋するとこんな感じ。 FRRの設定ファイル(frr.conf)全体についてはmininetlab 2 に記載している。 FRR本体のテストコード 3 が非常に簡潔で綺麗にまとまっているので、それを参考にした。 FRRではSRv6 L3VPNの開発は活発に行われているので、できれば新しいバージョンをおすすめする。 ここではFRR 8.5を使った。

mininet> r1 vtysh -c "show running-config"
# 一部抜粋
router bgp 65001
 bgp router-id 203.0.113.1
 bgp default ipv4-vpn
 bgp default ipv6-unicast
 bgp bestpath as-path multipath-relax
 no bgp network import-check
 neighbor r1-eth0 interface remote-as external
 !
 segment-routing srv6
  locator default
 exit
exit
!
router bgp 65001 vrf vrf10
 bgp router-id 203.0.113.1
 !
 address-family ipv4 unicast
  redistribute connected
  sid vpn export 16
  rd vpn export 65001:10
  rt vpn both 0:10
  export vpn
  import vpn
 exit-address-family
exit
!
segment-routing
 srv6
  locators
   locator default
    prefix 2001:db8:1:1::/64 block-len 40 node-len 24 func-bits 16
!
end

SRv6ではEncap時に宛先をSID(Segment ID)のリストで表現する。 SIDはIPv6フォーマットで記載できLocator、Function、Argumentの3つのフィールドから構成される。 Locatorは普通ルータごとに個別の値を与えるのでr1には2001:db8:1:1::/64を割り当てた。

ルータのASNとrouter idは全てのvrfで共通でr1では65001と203.0.113.1とした。 VPNを有効にするにはDefault VRFにおいて、 全てのneighborで有効化する bgp default ipv4-vpnを設定するか、 あるいは address-family ipv4 vpn の中で neighbor ごとに個別で設定する必要がある。

sid vpn export はSIDのfunctionに相当するのでVRFごとに個別の値を設定する。 VPNで広報するIP Prefixは、VRFの設定における address-family ipv4 unicast で設定する。

Mininetには各ホストに入ってコマンドを発行できる便利なCLI機構があるので、 下のように追加して色々みていく。

$ git diff
diff --git a/mininetlab/srv6_l3vpn.py b/mininetlab/srv6_l3vpn.py
index 4a7c4a9a3f94..d3185398e252 100644
--- a/mininetlab/srv6_l3vpn.py
+++ b/mininetlab/srv6_l3vpn.py
@@ -2,6 +2,7 @@

 from mininet.net import Mininet
 from mininet.log import setLogLevel
+from mininet.cli import CLI
 import time

 frr_conf = '''
@@ -185,6 +186,8 @@ def run():

     loss_rate = net.ping(hosts=[c11, c21]) + net.ping(hosts=[c12, c22])

+    CLI(net)
+
     for h in [r1, r2]:
         h.cmd("/usr/lib/frr/frrinit.sh stop")

まずはVPN内通信をざっくりチェックしてみる。 c11とc12は異なるテナントに所属しているため、 例え宛先IPアドレスが一緒であっても異なるホスト宛への通信となる。

mininet> c11 curl 192.168.2.1
c21
mininet> c12 curl 192.168.2.1
c22

続いてr1において、Default VRFとTenant10それぞれのルーティングテーブルを確認してみる。 proto bgpが付与されているエントリはBGPによって設定されたもの。 Default VRFではSID宛の通信に対してDecapを行い、 vrf10やvrf20に対してEnd.DT4アクションが適用される。 Tenant10に対応するVRFでは、192.168.2.0/24への経路として、 r2のSID 2001:db8:2:2:10:: でEncapするアクションが適用されている。 このようにBGPを使ってEncap/Decapのルーティングを設定することができる。

# Default VRF.
mininet> r1 ip -6 route show
2001:db8:1:1::1 dev lo proto kernel metric 256 pref medium
2001:db8:1:1:10:: nhid 11  encap seg6local action End.DT4 vrftable 10 dev vrf10 proto bgp metric 20 pref medium
2001:db8:1:1:20:: nhid 12  encap seg6local action End.DT4 vrftable 20 dev vrf20 proto bgp metric 20 pref medium
2001:db8:2:2::/64 nhid 22 via fe80::98de:31ff:fe2d:6903 dev r1-eth0 proto bgp metric 20 pref medium
fe80::/64 dev r1-eth0 proto kernel metric 256 pref medium

# VRF for Tenant10.
mininet> r1 ip -4 route show vrf vrf10
192.168.1.0/24 dev r1-eth1 proto kernel scope link src 192.168.1.254
192.168.2.0/24 nhid 23  encap seg6 mode encap segs 1 [ 2001:db8:2:2:10:: ] via inet6 fe80::98de:31ff:fe2d:6903 dev r1-eth0 proto bgp metric 20

SRv6パケットについても見ていく。 これはc11からpingをうちながらr1でパケットキャプチャすることで確認できる。 意図した通り SID 2001:db8:2:2:10::宛にSRv6パケットが送られている。

mininet> c11 ping 192.168.2.1 &
mininet> r1 tshark -i r1-eth0 -V host 2001:db8:2:2:10::

Frame 2: 162 bytes on wire (1296 bits), 162 bytes captured (1296 bits) on interface r1-eth0, id 0
Ethernet II, Src: 1a:4c:3e:9d:f7:09 (1a:4c:3e:9d:f7:09), Dst: 9a:de:31:2d:69:03 (9a:de:31:2d:69:03)
Internet Protocol Version 6, Src: 2001:db8:1:1::1, Dst: 2001:db8:2:2:10::
    Next Header: Routing Header for IPv6 (43)
    Source Address: 2001:db8:1:1::1
    Destination Address: 2001:db8:2:2:10::
    Routing Header for IPv6 (Segment Routing)
        Next Header: IPIP (4)
        Length: 2
        [Length: 24 bytes]
        Type: Segment Routing (4)
        Segments Left: 0
        Last Entry: 0
        Flags: 0x00
        Tag: 0000
        Address[0]: 2001:db8:2:2:10::
Internet Protocol Version 4, Src: 192.168.1.1, Dst: 192.168.2.1
    0100 .... = Version: 4
    Protocol: ICMP (1)
    Source Address: 192.168.1.1
    Destination Address: 192.168.2.1
Internet Control Message Protocol
    Type: 8 (Echo (ping) request)

BGP UPDATEメッセージも見てみる。新たに192.168.5.0/24をr1 vrf10に追加してみる。 RFC 9252 - BGP Overlay Services Based on Segment Routing over IPv6 (SRv6) で記載されている TLV の形式と合致している。

mininet> r1 bash -c "sleep 10; ip addr add 192.168.5.254/24 dev r1-eth1" &
mininet> r1 tshark -i r1-eth0 -V port 179

Frame 6: 250 bytes on wire (2000 bits), 250 bytes captured (2000 bits) on interface r1-eth0, id 0
Ethernet II, Src: 9a:de:31:2d:69:03 (9a:de:31:2d:69:03), Dst: 1a:4c:3e:9d:f7:09 (1a:4c:3e:9d:f7:09)
Internet Protocol Version 6, Src: fe80::98de:31ff:fe2d:6903, Dst: fe80::184c:3eff:fe9d:f709
Transmission Control Protocol, Src Port: 179, Dst Port: 34248, Seq: 20, Ack: 163, Len: 164
Border Gateway Protocol - UPDATE Message
    Path attributes
...
        Path Attribute - MP_REACH_NLRI
            Flags: 0x90, Optional, Extended-Length, Non-transitive, Complete
            Type Code: MP_REACH_NLRI (14)
            Address family identifier (AFI): IPv4 (1)
            Subsequent address family identifier (SAFI): Labeled VPN Unicast (128)
            Next hop:  RD=0:0 IPv6=fe80::98de:31ff:fe2d:6903 RD=0:0 Link-local=fe80::98de:31ff:fe2d:6903
                Route Distinguisher: 0:0
                IPv6 Address: fe80::98de:31ff:fe2d:6903
                Route Distinguisher: 0:0
                Link-local Address: fe80::98de:31ff:fe2d:6903
            Number of Subnetwork points of attachment (SNPA): 0
            Network Layer Reachability Information (NLRI)
                BGP Prefix
                    Prefix Length: 112
                    Label Stack: 256 (bottom)
                    # "rd vpn export 65001:10" より。
                    Route Distinguisher: 65001:10
                    # 今回VPNに追加したPrefix 192.168.5.0/24
                    MP Reach NLRI IPv4 prefix: 192.168.5.0
...
        Path Attribute - BGP Prefix-SID
            Type Code: BGP Prefix-SID (40)
            SRv6 L3 Service
                # L3なら5、L2なら6とする。「2. SRv6 Services TLVs」より。
                Type: SRv6 L3 Service (5)
                SRv6 Service Sub-TLVs
                    SRv6 Service Sub-TLV - SRv6 SID Information
                        #「3.1. SRv6 SID Information Sub-TLV」より。
                        Type: SRv6 SID Information (1)
                        # r1 vrf10のSID
                        SRv6 SID Value: 2001:db8:1:1::
                        SRv6 SID Flags: 0x00
                        # https://www.iana.org/assignments/segment-routing/segment-routing.xhtml より。
                        SRv6 Endpoint Behavior: End.DT4 (0x0013)
                        Reserved: 00
                        SRv6 Service Data Sub-Sub-TLVs
                            SRv6 Service Data Sub-Sub-TLV - SRv6 SID Structure
                                # 「3.2.1. SRv6 SID Structure Sub-Sub-TLV」より。
                                Type: SRv6 SID Structure (1)
                                # Locatorのビット数
                                Locator Block Length: 40
                                Locator Node Length: 24
                                Function Length: 16
                                Argument Length: 0
                                Transposition Length: 16
                                Transposition Offset: 64

ざっくりとした挙動を理解することができた。 今後はSR Domainを複雑にしてみたり、 テナントごとにNetwork Functionを生やしたりしてみたい。 おしまい。