1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

SRv6 (Segment Routing over IPv6) をMininetで実行してみた

Last updated at Posted at 2022-05-10

SRv6の実行についての記事が少ないので,自分で書いてみた.Mininetであれば,100行程度で,そこそこのトポロジが作れて簡単にSRv6が試せる!!!おすすめ!!!!

全てのコードはGithubにあります.

SRv6とは?

SRv6はSegmentRoutingをIPv6データプレーンで実装したものです.SegmentRoutingは,ソースルーティングを活用したルーティング技術である.SRv6では,IPv6の拡張ヘッダであるSRH(Segment Routing Header)を用いる.SRHは,SRv6ポリシーを表すSegmentListを持つ.このSegmentListにより,パケットの転送方法などを指定できる.

Mininetとは?

Linuxのネームスペースなどの機能を用いて,ネットワークをエミュレートするためのツール.OpenFlowなどのSDNネットワークをテストするときによく使われる.pythonで簡単にネットワークを構築できる.

実行環境

SRv6の基本的な動作はLinuxにも実装されている.Linuxの実装状況はこのSegmentRoutingのサイトで確認できる.

  • 環境構築: Vagrant + VirtualBox
  • OS: Ubuntu20.04 LTS

Mininetを使用するのでMininetのインストールが必要です.MininetのインストールなどはMininet公式ページとか様々なブログに記載されている.

詳しくはGithubのVagrantfileを参照してください.

SRv6ノードの設定

Mininetのノードクラスを継承したSRv6ノードを作成する.SRv6を実行するための設定をconfigメソッドに書いておけば,Mininetのスタート時に実行してくれる.configメソッドで親のメソッドを呼び出していないのは,勝手にIPアドレスなどが割り当てられないようにするためである.

from mininet.node import Node

class SRv6Node(Node):

    def __init__(self, name, **params):
        super().__init__(name, **params)

    def config(self, **params):
        self.cmd("ifconfig lo up")
        self.cmd("sysctl -w net.ipv4.ip_forward=1")
        self.cmd("sysctl -w net.ipv6.conf.all.forwarding=1")
        self.cmd("sysctl -w net.ipv6.conf.all.seg6_enabled=1")
        self.cmd("sysctl -w net.ipv6.conf.all.seg6_require_hmac=0")

        for i in self.nameToIntf.keys():
            self.cmd("sysctl -w net.ipv6.conf.{}.seg6_enabled=1".format(i))

net.ipv4.ip_forwardなどのフォワーディングの設定とSRv6を有効化する設定が必要である.また,各インターフェースでもSRv6を有効化する必要があるため,nameToIntfのキーを使ってFor文でそれぞれ有効化している.

このクラスは以下のようにaddHostメソッドを使って追加する.

r1 = net.addHost("r1", cls=SRv6Node)

実行

テスト用のネットワーク構成を以下に示す.ルータはSRv6を有効にしたノードである.今回はSRv6を試すだけなので,ルーティングプロトコルは使用しない.
topo.drawio.png
上のネットワークの設定を反映した最終的なコードは以下に示す.

from mininet.cli import CLI
from mininet.net import Mininet
from mininet.log import setLogLevel
from mininet.node import Node


class SRv6Node(Node):

    def __init__(self, name, **params):
        super().__init__(name, **params)

    def config(self, **params):
        self.cmd("ifconfig lo up")
        self.cmd("sysctl -w net.ipv4.ip_forward=1")
        self.cmd("sysctl -w net.ipv6.conf.all.forwarding=1")
        self.cmd("sysctl -w net.ipv6.conf.all.seg6_enabled=1")
        self.cmd("sysctl -w net.ipv6.conf.all.seg6_require_hmac=0")

        for i in self.nameToIntf.keys():
            self.cmd("sysctl -w net.ipv6.conf.{}.seg6_enabled=1".format(i))


def main():
    setLogLevel("info")
    net = Mininet()

    r1 = net.addHost("r1", cls=SRv6Node)
    r2 = net.addHost("r2", cls=SRv6Node)
    r3 = net.addHost("r3", cls=SRv6Node)
    r4 = net.addHost("r4", cls=SRv6Node)
    r5 = net.addHost("r5", cls=SRv6Node)
    r6 = net.addHost("r6", cls=SRv6Node)

    h1 = net.addHost("h1", ip=None)
    h2 = net.addHost("h2", ip=None)
    h3 = net.addHost("h3", ip=None)
    h4 = net.addHost("h4", ip=None)

    net.addLink(r1, h1,
                intfName1="r1_h1", params1={"ip": "192.168.1.1/24"},
                intfName2="h1_r1", params2={"ip": "192.168.1.2/24"})
    h1.cmd("ip route add default dev h1_r1 via 192.168.1.1")
    
    net.addLink(r1, h2,
                intfName1="r1_h2", params1={"ip": "192.168.2.1/24"},
                intfName2="h2_r1", params2={"ip": "192.168.2.2/24"})
    h2.cmd("ip route add default dev h2_r1 via 192.168.2.1")
    
    net.addLink(r6, h3,
                intfName1="r6_h3", params1={"ip": "192.168.3.1/24"},
                intfName2="h3_r6", params2={"ip": "192.168.3.2/24"})
    h3.cmd("ip route add default dev h3_r6 via 192.168.3.1")
    
    net.addLink(r6, h4,
                intfName1="r6_h4", params1={"ip": "192.168.4.1/24"},
                intfName2="h4_r6", params2={"ip": "192.168.4.2/24"})
    h4.cmd("ip route add default dev h4_r6 via 192.168.4.1")

    net.addLink(r1, r2, intfName1="r1_r2", intfName2="r2_r1")
    net.addLink(r1, r3, intfName1="r1_r3", intfName2="r3_r1")

    net.addLink(r2, r4, intfName1="r2_r4", intfName2="r4_r2")
    net.addLink(r2, r3, intfName1="r2_r3", intfName2="r3_r2")

    net.addLink(r3, r5, intfName1="r3_r5", intfName2="r5_r3")

    net.addLink(r4, r6, intfName1="r4_r6", intfName2="r6_r4")
    net.addLink(r4, r5, intfName1="r4_r5", intfName2="r5_r4")

    net.addLink(r5, r6, intfName1="r5_r6", intfName2="r6_r5")

    h1.cmd("ip -6 addr add fc00:1::2/64 dev h1_r1")
    h1.cmd("ip -6 route add default dev h1_r1 via fc00:1::1")
    r1.cmd("ip -6 addr add fc00:1::1/64 dev r1_h1")
    
    h2.cmd("ip -6 addr add fc00:2::2/64 dev h2_r1")
    h2.cmd("ip -6 route add default dev h2_r1 via fc00:2::1")
    r1.cmd("ip -6 addr add fc00:2::1/64 dev r1_h2")

    r1.cmd("ip -6 addr add fc00:a::1/64 dev r1_r2")
    r2.cmd("ip -6 addr add fc00:a::2/64 dev r2_r1")

    r1.cmd("ip -6 addr add fc00:b::1/64 dev r1_r3")
    r3.cmd("ip -6 addr add fc00:b::2/64 dev r3_r1")

    r2.cmd("ip -6 addr add fc00:c::1/64 dev r2_r3")
    r3.cmd("ip -6 addr add fc00:c::2/64 dev r3_r2")

    r2.cmd("ip -6 addr add fc00:d::1/64 dev r2_r4")
    r4.cmd("ip -6 addr add fc00:d::2/64 dev r4_r2")

    r3.cmd("ip -6 addr add fc00:e::1/64 dev r3_r5")
    r5.cmd("ip -6 addr add fc00:e::2/64 dev r5_r3")

    r4.cmd("ip -6 addr add fc00:f::1/64 dev r4_r5")
    r5.cmd("ip -6 addr add fc00:f::2/64 dev r5_r4")

    r4.cmd("ip -6 addr add fc00:aa::1/64 dev r4_r6")
    r6.cmd("ip -6 addr add fc00:aa::2/64 dev r6_r4")

    r5.cmd("ip -6 addr add fc00:ab::1/64 dev r5_r6")
    r6.cmd("ip -6 addr add fc00:ab::2/64 dev r6_r5")
    
    h3.cmd("ip -6 addr add fc00:3::2/64 dev h3_r6")
    h3.cmd("ip -6 route add default dev h3_r6 via fc00:3::1")
    r6.cmd("ip -6 addr add fc00:3::1/64 dev r6_h3")
    
    h4.cmd("ip -6 addr add fc00:4::2/64 dev h4_r6")
    h4.cmd("ip -6 route add default dev h4_r6 via fc00:4::1")
    r6.cmd("ip -6 addr add fc00:4::1/64 dev r6_h4")
    
    r1.cmd("ip -6 route add fc00:3::/64 encap seg6 mode encap segs fc00:a::2,fc00:d::2,fc00:aa::2 dev r1_r2")
    r6.cmd("ip -6 route add fc00:1::/64 encap seg6 mode encap segs fc00:ab::1,fc00:e::1,fc00:b::1 dev r6_r5")

    net.start()

    CLI(net)

    net.stop()


if __name__ == "__main__":
    main()

SRv6のルートの設定

今回は,H1とH3で疎通できるようなルーティングを行う.ルーティングの設定方法はencapでそれぞれのSIDを指定する.
flow.drawio.png

Mininetのノードには,cmdメソッドがあり,シェルのコマンドをノード内で実行できる.このメソッドで,ルーティングを以下のように設定する.

r1.cmd("ip -6 route add fc00:3::/64 encap seg6 mode encap segs fc00:a::2,fc00:d::2,fc00:aa::2 dev r1_r2")
r6.cmd("ip -6 route add fc00:1::/64 encap seg6 mode encap segs fc00:ab::1,fc00:e::1,fc00:b::1 dev r6_r5")

h1 => R1 => R2 => R4 => R6 => H3 となるように,通過するインターフェースを全て指定しておく.

実行手順

Mininetを実行する.その後,xterm h1でh1のコンソールを立ち上げる.

$ sudo python3 net.py
*** Configuring hosts
r1 r2 r3 r4 r5 r6 h1 h2 h3 h4 
*** Starting controller

*** Starting 0 switches

*** Starting CLI:
mininet> xterm h1

h1のコンソールでh3に対してpingする.

$ ping -6 fc00:3::2

実行結果

ping実行画面を下に示す.

screenshot000111.JPG

r1_r2でキャプチャしたパケットを以下に示す.
screenshot000112.JPG
ちゃんとパケットが通ってることは確認できた.

終わりに

今回は,MininetでSRv6を実行する方法についてまとめた.時間がある時に,他のBehaivorであるEnd.DX4とかEnd.DT4を実行する記事とかを書きたい.

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?