こんにちは、 miyakeです :-)
ちょっと先の話ですが、来月6月は幕張でINTEROPが開催されます :-)
ネットワーク機器からSDN、NFVのデモや展示が行われる、ネットワークに関する大きなイベントです。
今年はIoT関係の展示も増えているそうなので、見に行こうと思っています。
前々回:OpenDaylight 「Helium」 概要編
前回:OpenDaylight 「Helium」をインストールしてみよう
今回:OpenDaylight 「Helium」でSDNを構築してみよう < イマココ
そんな訳で最終回の今回は、前回インストールを行った環境でSDNを構築します。
今回構築するネットワークのイメージは以下の図のようになります。
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が表示されます。
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が表示されるようになります。
Switchの情報を確認してみよう
画面の「Nodes」タブを選択すると、接続されているSwitchの一覧が表示されます。
この一覧の右側にある"Node Connectors"を選択すると、Switchのポート情報が表示されます。
見てもらうとわかりますが、ポートごとのパケット量やエラーパケット数、ドロップパケット数が表示されているので、ある程度のネットワークの状況であれば、この画面で確認することが出来そうです :-)
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の開発に携わりたい。
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
キャリア採用ページ