Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

OpenDaylight Helium SR3を試してみた 【OpenDaylight 「Helium」でSDNを構築してみよう】

こんにちは、 miyakeです :-)

ちょっと先の話ですが、来月6月は幕張でINTEROPが開催されます :-)
ネットワーク機器からSDN、NFVのデモや展示が行われる、ネットワークに関する大きなイベントです。
今年はIoT関係の展示も増えているそうなので、見に行こうと思っています。

http://www.opendaylight.org/sites/all/themes/opendaylight/ixm/images/logo_opendaylight.png

前々回:OpenDaylight 「Helium」 概要編
 前回:OpenDaylight 「Helium」をインストールしてみよう
 今回:OpenDaylight 「Helium」でSDNを構築してみよう < イマココ

そんな訳で最終回の今回は、前回インストールを行った環境でSDNを構築します。

今回構築するネットワークのイメージは以下の図のようになります。

f:id:acro-engineer:20150524164551p:plain

open vSwitchでOpenFlow Switchを3つ(ofbr0~ofbr2)作成して、SwitchごとにNodeを4つずつ接続した構成となります。
このNodeをKVMなどの仮想マシンで構築するのはCPUやメモリなどの確保が困難なので、今回はNetwork Namespaceを使って疑似的にNodeを作成します。
Network Namespaceを使うと、一つのホスト内で独立したネットワーク環境を複数作成することが出来るようになります。この機能を使うことで、疑似的なNodeを作成することができます。
Dockerは、このNetwork Namespaceを使ってコンテナ内に独立したネットワーク環境を作っていたりします :-)

それではこれから、順番に環境を構築していきます。

OpenFlow Switchの作成

まずは図にあるOpenFlow Switch(ofbr0~ofbr2)を、以下のコマンドを実行して作成します。
なおこれらのコマンドはroot権限がないと実行できないものなので、rootで行ってください。

# ovs-vsctl add-br ofbr0
# ovs-vsctl add-br ofbr1
# ovs-vsctl add-br ofbr2

# ovs-vsctl set bridge ofbr0 protocols=OpenFlow13
# ovs-vsctl set bridge ofbr1 protocols=OpenFlow13
# ovs-vsctl set bridge ofbr2 protocols=OpenFlow13

# ovs-vsctl set-controller ofbr0 tcp:[OpenDaylightをインストールしたマシンのIPアドレス]
# ovs-vsctl set-controller ofbr1 tcp:[OpenDaylightをインストールしたマシンのIPアドレス]
# ovs-vsctl set-controller ofbr2 tcp:[OpenDaylightをインストールしたマシンのIPアドレス]

# ovs-vsctl set bridge ofbr0 other-config:datapath-id=0000000000000011
# ovs-vsctl set bridge ofbr1 other-config:datapath-id=0000000000000012
# ovs-vsctl set bridge ofbr2 other-config:datapath-id=0000000000000013

"ovs-vsctl"はopen vSwitchのコマンドです。

"ovs-vsctl add-br"で、open vSwitchのブリッジを作成しています。
"ovs-vsctl set bridge xxx protocols=OpenFlow13"は、ブリッジをOpenFlow1.3に対応したSwitchとなるように設定しています。
"ovs-vsctl set-controller xxx tcp:"は、SDNコントローラであるOpenDaylightに接続するための接続先IPアドレスを設定しています。
"ovs-vsctl set bridge ofbr0 other-config:datapath-id"は、OpenFlow Switchを識別するためのIDを設定しています。このIDは16進数で設定します。

実際に作成された内容は、"ovs-vsctl show"で確認することができます。

# ovs-vsctl show
e4b90a1e-584c-4de2-983d-c814e27581e4
    Bridge "ofbr1"
        Controller "tcp:192.48.128.40"
        Port "ofbr1"
            Interface "ofbr1"
                type: internal
    Bridge "ofbr2"
        Controller "tcp:192.48.128.40"
        Port "ofbr2"
            Interface "ofbr2"
                type: internal
    Bridge "ofbr0"
        Controller "tcp:192.48.128.40"
        Port "ofbr0"
            Interface "ofbr0"
                type: internal
    Bridge "br0"
        Port "br0"
            Interface "br0"
                type: internal
    ovs_version: "2.3.1"

OpenFlow Switch間の接続

次は、図にあるOpenFlow Switch間の接続(青い線)を、以下のコマンドを実行して作成します。

# ovs-vsctl add-port ofbr0 ofbr0_ofbr1 -- set interface ofbr0_ofbr1 type=patch options:peer=ofbr1_ofbr0
# ovs-vsctl add-port ofbr1 ofbr1_ofbr0 -- set interface ofbr1_ofbr0 type=patch options:peer=ofbr0_ofbr1

# ovs-vsctl add-port ofbr1 ofbr1_ofbr2 -- set interface ofbr1_ofbr2 type=patch options:peer=ofbr2_ofbr1
# ovs-vsctl add-port ofbr2 ofbr2_ofbr1 -- set interface ofbr2_ofbr1 type=patch options:peer=ofbr1_ofbr2

ここでは、OpenFlow Switch間を接続するための仮想インタフェースと、そのインタフェース間を接続する定義を行っています。
ポートは双方に接続する必要があるので、図の青い線1つに対して2つのコマンドを実行しています。

"ofbr1_ofbr0"としているのが、仮想インタフェースの名称になります。

"ovs-vsctl show"で結果を確認すると、以下のようになっているはずです。

# ovs-vsctl show
e4b90a1e-584c-4de2-983d-c814e27581e4
    Bridge "ofbr1"
        Controller "tcp:192.48.128.40"
        Port "ofbr1"
            Interface "ofbr1"
                type: internal
        Port "ofbr1_ofbr0"
            Interface "ofbr1_ofbr0"
                type: patch
                options: {peer="ofbr0_ofbr1"}
        Port "ofbr1_ofbr2"
            Interface "ofbr1_ofbr2"
                type: patch
                options: {peer="ofbr2_ofbr1"}
    Bridge "ofbr2"
        Controller "tcp:192.48.128.40"
        Port "ofbr2"
            Interface "ofbr2"
                type: internal
        Port "ofbr2_ofbr1"
            Interface "ofbr2_ofbr1"
                type: patch
                options: {peer="ofbr1_ofbr2"}
    Bridge "ofbr0"
        Controller "tcp:192.48.128.40"
        Port "ofbr0"
            Interface "ofbr0"
                type: internal
        Port "ofbr0_ofbr1"
            Interface "ofbr0_ofbr1"
                type: patch
                options: {peer="ofbr1_ofbr0"}
    Bridge "br0"
        Port "br0"
            Interface "br0"
                type: internal
    ovs_version: "2.3.1"

ブリッジごとに、仮想インタフェースがポートとして接続されています。
peer=で表示されているのが、対向として接続されている仮想インタフェースになります。

Nodeの生成

最後に、Network Namespaceを使用して疑似的なNodeを生成します。

まず先に、ブリッジとNode間を接続するためのveth peerを生成します。
veth peerとは、ホスト内に生成された2つの仮想インタフェースと、そのインタフェース間を接続した仮想ケーブルのセットだと考えてください。
図にある、OpenFlow SwitchとNode間のオレンジの線が、veth peerになります。

このveth peerの生成には、ipコマンドを使用します。

# ip link add name veth1 type veth peer name veth1_ovs

このコマンドで、veth1、veth1_ovsという名称の仮想インタフェースを持つveth peerが出来上がります。
"ip link"とコマンドを実行すると、この2つの仮想インタフェースが表示されます。

次に、Nodeに相当するNetwork Namespaceを生成して、上で作成したveth peerでOpenFlow Switchと接続します。

1)veth1_nodeという名前のNamespaceを生成
# ip netns add veth1_node

2)veth1_nodeに、veth peerの仮想インタフェースveth1を接続
# ip link set veth1 netns veth1_node

3)仮想インタフェースveth1にIPアドレスを定義
# ip netns exec veth1_node ip addr add 10.0.0.1/24 dev veth1

4)OpenFlow Switchであるofbr0に、veth peerの仮想インタフェースveth1_ovsを接続
# ovs-vsctl add-port ofbr0 veth1_ovs

"ip netns"が、Network Namespaceに対する操作を行う際のコマンドだと思ってください。
"ip netns exec veth1_node..."は、Network Namespace上でコマンドを実行する際に使用します。
上の例では、Network Namespace上でipコマンドを実行して、veth1にIPアドレスを設定しています。

最後にveth peerの仮想インタフェースをLink Upにして完了です。

# ip netns exec veth1_node ip link set veth1 up
# ip link set veth1_ovs up

以上でNodeの生成は完了ですが、図にあるものを手で打つのも大変なので、以下のシェルスクリプトを実行すると、図にあるNodeが生成することが出来ます。

#!/bin/bash

#
# Network Name Space とOVS間のPeer生成
#
create_ovs_veth ()
{
    veth_ovs="veth"${2}"_ovs"
    veth="veth"${2}
    veth_node="veth"${2}"_node"
    ip_addr="10.0.0."${2}"/24"
    brg_name=${1}

    echo "veth_ovs=${veth_ovs} veth=${veth} veth_node=${veth_node} ip_addr=${ip_addr} brg_name=${brg_name}"

    # delete
    ovs-vsctl del-port $brg_name $veth_ovs
    ip netns del $veth_node
    ip link del $veth_ovs

    # add
    ip link add name $veth type veth peer name $veth_ovs
    ip netns add $veth_node
    ip link set $veth netns $veth_node
    ip netns exec $veth_node ip addr add $ip_addr dev $veth

    ovs-vsctl add-port $brg_name $veth_ovs
    ip netns exec $veth_node ip link set $veth up
    ip link set $veth_ovs up

    ip netns exec $veth_node ip addr
}

# ofbr0にNode生成
array0=("1" "2" "3" "4")

for elem in "${array0[@]}"
do
    create_ovs_veth "ofbr0" $elem
done

# ofbr1にNode生成
array1=("11" "12" "13" "14")

for elem in "${array1[@]}"
do
    create_ovs_veth "ofbr1" $elem
done

# ofbr2にNode生成
array2=("21" "22" "23" "24")

for elem in "${array2[@]}"
do
    create_ovs_veth "ofbr2" $elem
done

シェルを実行するための手順は、以下の通りです。

# vi veth_setup.sh

上記の内容を入力して実行します。

# chmod a+x veth_setup.sh
# ./veth_setup.sh

このシェルによって、SDN内に10.0.0.*/24のIPアドレスを持つ疑似的なNodeが生成されます。

生成されているNetwork Namespace一覧を確認したい場合は、"ip netns"と実行します。

# ip netns
veth24_node
veth23_node
veth22_node
veth21_node
veth14_node
veth13_node
veth12_node
veth11_node
veth4_node
veth3_node
veth2_node
veth1_node

IPアドレスは、Network Namespace名称"veth**_node"の**部分が、10.0.0.**となるように設定されます。
例えば"veth14_node"の場合、"10.0.0.14"となります。
まぁ、シェルを修正すれば、好きなIPアドレスに変更することもできるので、色々いじってみてください :-)

ちなみに、生成したNetwork Namespaceのネットワーク設定の確認は、以下のように行います。
Network Namespaceに、どのIPアドレスが割り当てられているかを確認したい場合は、このコマンドを実行してみてください。

# ip netns exec veth1_node ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
57: veth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 9a:3e:45:e4:9f:e2 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.1/24 scope global veth1
       valid_lft forever preferred_lft forever
    inet6 fe80::983e:45ff:fee4:9fe2/64 scope link
       valid_lft forever preferred_lft forever

【ちょっと補足】
今回、ipアドレスやLinkUpの設定にifconfigコマンドを使用せず、すべてipコマンドで行っています。
知っている方もいると思いますが、RHEL7/CentOS7ではnet-toolsそのものが廃止予定となっていて、iproute2パッケージに含まれているipコマンドやssコマンドに移行することが推奨されています。
実際RHEL7では標準でnet-toolsがインストールされていないため、ifconfigコマンドが使えない環境に当たることもあります...
そういう背景もあり、今回は明示的にifconfigコマンドを使用していません。
遅かれ早かれifconfigコマンドは使えなくなるので、早いうちにipコマンドに慣れておきましょう...

OpenDaylightを起動して実際にネットワークを見てみよう

前回のOpenDaylight 「Helium」をインストールしてみようの最後にある方法にしたがってOpenDaylightを起動し、画面を開いてみてください。
SDNの作成に成功していれば、ログイン後に以下のように3つのOpenFlow Switchが表示されます。

f:id:acro-engineer:20150524201120p:plain

Switchの下にopenflow:17と表示されているので、OpenFlow Switchとして認識されていることがわかります。
ちなみに17という数字は、OpenFlow Switchの作成時に16進数で設定したIDが10進数で表示されたものです。
この値で、どのSwitchなのかを区別します。

Switchが表示されているけど、Nodeが表示されていません...
これはまだ、NodeからMACアドレス解決のため通信が行われていないため、Switch側でNodeがどこに接続されているのかを認識できていないためです。
通常この認識は、APRによるMAC解決のパケットを利用しています。
OpenFlowでは、このARPパケットをコントローラ側に送ることで、SwitchのどのポートにどのNodeが接続されているかを関連付ける仕組みになっています。
これをよく「ポート学習」などと言っています。

それでは実際にpingを実行してARPによるMAC解決のための通信を行ってみましょう。
SDNとして正常に機能していれば、pingが通ります :-)

Nodeに対してpingを打ってみる

今回、NodeはNetwork Namespaceで疑似的に作成したので、pingはNetwork Namespace上で実行する必要があるので、以下のようにipコマンドを使って実行します。

# ip netns exec veth1_node ping 10.0.0.11
PING 10.0.0.11 (10.0.0.11) 56(84) bytes of data.
64 bytes from 10.0.0.11: icmp_seq=1 ttl=64 time=0.521 ms
64 bytes from 10.0.0.11: icmp_seq=2 ttl=64 time=0.200 ms
64 bytes from 10.0.0.11: icmp_seq=3 ttl=64 time=0.046 ms
64 bytes from 10.0.0.11: icmp_seq=4 ttl=64 time=0.037 ms
64 bytes from 10.0.0.11: icmp_seq=5 ttl=64 time=0.036 ms
...

この例では、veth1_node上で、10.0.0.11にpingを打っています。
ちゃんとpingが届いて、応答が返ってきているので、SDNの構築は成功です :-)

"ip netns exec [Namespace名] [Namespace上で実行するコマンド]"というパターンでpingを打つことで、OpenFlow Switchを通して、他のNamespace上の仮想インタフェースに対してpingが行われます。
このpingをすべてのNodeに対して行ったのち、先ほどの画面の「Reload」ボタンを押下すると、以下の画面のようにすべてのNodeが表示されるようになります。

f:id:acro-engineer:20150524203828p:plain

Switchの情報を確認してみよう

画面の「Nodes」タブを選択すると、接続されているSwitchの一覧が表示されます。

f:id:acro-engineer:20150524205643p:plain

この一覧の右側にある"Node Connectors"を選択すると、Switchのポート情報が表示されます。

f:id:acro-engineer:20150524210238p:plain

見てもらうとわかりますが、ポートごとのパケット量やエラーパケット数、ドロップパケット数が表示されているので、ある程度のネットワークの状況であれば、この画面で確認することが出来そうです :-)

OpenFlowのフローエントリを確認する方法

open vSwitchのコマンドを使って、OpenFlow Switchに設定されているOpenFlowのフローエントリを確認してみましょう。
設定されているフローエントリを見ることで、どのような制御が行われているのかを確認することができます :-)

# ovs-ofctl dump-flows ofbr0 --protocol=OpenFlow13
OFPST_FLOW reply (OF1.3) (xid=0x2):
cookie=0x2a00000000000001, duration=5.648s, table=0, n_packets=5, n_bytes=490, idle_timeout=1800, hard_timeout=3600, priority=10,dl_src=ae:8a:bd:a4:7e:f7,dl_dst=7a:9c:01:d3:a1:46 actions=output:2
cookie=0x2a00000000000000, duration=5.648s, table=0, n_packets=5, n_bytes=490, idle_timeout=1800, hard_timeout=3600, priority=10,dl_src=7a:9c:01:d3:a1:46,dl_dst=ae:8a:bd:a4:7e:f7 actions=output:1
cookie=0x2b0000000000000d, duration=51.144s, table=0, n_packets=0, n_bytes=0, priority=2,in_port=3 actions=output:1,output:7,output:2,output:4,CONTROLLER:65535
cookie=0x2b0000000000000c, duration=51.145s, table=0, n_packets=0, n_bytes=0, priority=2,in_port=7 actions=output:1,output:3,output:2,output:4
cookie=0x2b0000000000000b, duration=51.146s, table=0, n_packets=7, n_bytes=574, priority=2,in_port=1 actions=output:7,output:3,output:2,output:4,CONTROLLER:65535
cookie=0x2b0000000000000f, duration=51.144s, table=0, n_packets=0, n_bytes=0, priority=2,in_port=4 actions=output:1,output:7,output:3,output:2,CONTROLLER:65535
cookie=0x2b0000000000000e, duration=51.144s, table=0, n_packets=7, n_bytes=574, priority=2,in_port=2 actions=output:1,output:7,output:3,output:4,CONTROLLER:65535
cookie=0x2b00000000000004, duration=56.289s, table=0, n_packets=12, n_bytes=1044, priority=100,dl_type=0x88cc actions=CONTROLLER:65535

この内容を見る限り、"CONTROLLER:65535"によってポート学習用のパケットがコントローラに送られており、dl_src、dl_dstのMACアドレスのパケットが届いた場合に特定のポートに転送するフローエントリーが登録されていました。これはOpenFlowでL2スイッチを実現するための定番の動作です。
ここからも、正常にSDNとして機能していることが確認できました :-)


そんなわけで、3回に分けて「OpenDaylight Heliumを試してみました」をやってみましたが、いかがだったでしようか?
昨今、NFVに注目が集まってきており、今まで物理マシンで実現していたネットワーク機器にまでも仮想化の波が押し寄せるようになってきました。
このNFVの制御部分にSDNコントローラが使われるケースも出てきており、Open Platform for NFV (OPNFV)ではOpenDaylightが使用されています。

今回のブログをきっかけに、仮想ネットワークやSDNに興味を持ってもらえれば幸いです :-)

それではまたの機会に~~

Acroquest Technologyでは、キャリア採用を行っています。


  • 日頃勉強している成果を、Hadoop、Storm、NoSQL、HTML5/CSS3/JavaScriptといった最新の技術を使ったプロジェクトで発揮したい。
  • 社会貢献性の高いプロジェクトに提案からリリースまで携わりたい。
  • 書籍・雑誌等の執筆や対外的な勉強会の開催を通した技術の発信や、社内勉強会での技術情報共有により、技術的に成長したい。
  • OSSの開発に携わりたい。

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
 キャリア採用ページ