« ◆ Lubuntu 13.04 に Open vSwitch をインストールした時のログ | トップページ | ◆ 【Open vSwitchのみで OpenFlowプログラミング】VLAN ID コンバータ 改 »

2013年8月 5日 (月)

◆ 【Open vSwitchのみで OpenFlowプログラミング】VLAN ID コンバータ

OpenFlow コントーラを使わずに、Open vSwitch を OpenFlow スイッチとして使って VLAN ID を変換する機能を実装してみました。

Open vSwitch では、ovs-ofctl コマンドを使うことで OpenFlow スイッチとしての機能に対してフローを登録・変更・削除することができます。
動的にフローを変更する必要がなければ、このコマンドで事前に登録して動作させれば OpenFlow コントローラなしでも動かすことができそうだと思い以前作った VLAN ID を変換する例に対して試してみました。

Lubuntu 13.04 のパッケージの Open vSwitch で入る ovs-ofctl コマンドの man ページは、以下で参照できます:
http://manpages.ubuntu.com/manpages/raring/en/man8/ovs-ofctl.8.html

仮想ネットワークの構成は、以前書いた記事「◆ 【TremaでOpenFlowプログラミング】VLAN ID コンバータ」と全く一緒です。

使用した環境:
  OS: Lubuntu 13.04 Desktop (i386) (※ 12.04 ではありません)
  Open vSwitch: 1.9.0 (Lubuntu のパッケージでインストール)

補足:
Open vSwitch のインストールについては記事「◆ Lubuntu 13.04 に Open vSwitch をインストールした時のログ」を参照ください。

■今回の仮想ネットワークの構成図
記事「◆ 【TremaでOpenFlowプログラミング】VLAN ID コンバータ」と全く一緒です。
こんなストーリーを想定しています:
・2つの拠点があって、拠点ごとに別々に VLAN ID を管理していた。
・拠点1の VLAN ID 10, 20 の L2 ネットワークを拠点2 にも延ばす必要が生じた。
・しかし、拠点2 では VLAN ID 10, 20 は使えず、代わりに 拠点2 では LAN ID 30, 40 を割り当て、拠点間で VLAN ID を変換することにした。
・拠点1 の VLAN ID: 10 と 拠点2 の VLAN ID: 30 を接続する。
・拠点1 の VLAN ID: 20 と 拠点2 の VLAN ID: 40 を接続する。

Photo
■ 構成の確認
後述するシェルスクリプトで仮想ネットワークを作成したら OpenFlow ポートの1番が拠点1側、ポートの2番が拠点2側との接続となっていることを確認します。

$ sudo ovs-ofctl show ofs1
OFPT_FEATURES_REPLY (xid=0x1): dpid:00003670612aed45
n_tables:255, n_buffers:256
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE
1(vlinkSW1-1): addr:06:be:3f:87:9f:18
     config:     0
     state:      0
     current:    10GB-FD COPPER
     speed: 10000 Mbps now, 100 Mbps max
2(vlinkSW2-1): addr:f6:42:dc:fe:0d:ff
     config:     0
     state:      0
     current:    10GB-FD COPPER
     speed: 10000 Mbps now, 100 Mbps max
LOCAL(ofs1): addr:36:70:61:2a:ed:45
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 100 Mbps now, 100 Mbps max
OFPT_GET_CONFIG_REPLY (xid=0x3): frags=normal miss_send_len=0

ちなみに、Lubuntu 12.04 のパッケージとしてインストールした Open vSwitch で ovs-ofctl show を実行した時はcapabilities と actions が16進数表記だったのが、今回はシンボル名に変わっていました。

■ OpenFlow コントローラ

OpenFlow コントローラ自体はありませんが、後述するスクリプトから、フローテーブルを設定している部分を以下に抜粋します:

config_ofs1() {
    sudo ovs-ofctl del-flows "ofs1"


    sudo ovs-ofctl add-flow "ofs1" in_port=1,dl_vlan=10,actions=mod_vlan_vid:30,output:2
    sudo ovs-ofctl add-flow "ofs1" in_port=2,dl_vlan=30,actions=mod_vlan_vid:10,output:1
    sudo ovs-ofctl add-flow "ofs1" in_port=1,dl_vlan=20,actions=mod_vlan_vid:40,output:2
    sudo ovs-ofctl add-flow "ofs1" in_port=2,dl_vlan=40,actions=mod_vlan_vid:20,output:1
    sudo ovs-ofctl add-flow "ofs1" priority=100,actions=drop
}

 やっていることを文字にすると以下の通り:
・ポート1(拠点1) から来た VLAN ID: 10 のパケットなら、VLAN ID を 30 にすげかえてポート2(拠点2)へ出力。
・ポート2(拠点2) から来た VLAN ID: 30 のパケットなら、VLAN ID を 10 にすげかえてポート1(拠点1)へ出力。
・ポート1(拠点1) から来た VLAN ID: 20 のパケットなら、VLAN ID を 40 にすげかえてポート2(拠点2)へ出力。
・ポート2(拠点2) から来た VLAN ID: 40 のパケットなら、VLAN ID を 20 にすげかえてポート1(拠点1)へ出力。
・上記に当てはまらないパケットが来たら破棄する。(すべてのパケットに合致するフローエントリですが優先度 priority を他のフローエントリより下げることで「上記に当てはまらない」という動きにしています。)

先頭で、フローを削除しているのはデフォルトで登録されている actions=NORMAL のフローを削除するためです。
フローの編集を何もしていない時、ovs-ofctl dump-flow を行うと以下のような出力が得られます:

 cookie=0x0, duration=5.009s, table=0, n_packets=15, n_bytes=1690, idle_age=0, priority=0 actions=NORMAL

この actions=NORMAL は、通常のスイッチとして機能するということを意味します。

■ OpenFlow スイッチのフローテーブルの確認

$ sudo ovs-ofctl dump-flows ofs1
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=223.515s, table=0, n_packets=84, n_bytes=17360, idle_age=36, priority=100 actions=drop
cookie=0x0, duration=223.54s, table=0, n_packets=4, n_bytes=308, idle_age=214, in_port=2,dl_vlan=40 actions=mod_vlan_vid:20,output:1
cookie=0x0, duration=223.57s, table=0, n_packets=4, n_bytes=308, idle_age=214, in_port=1,dl_vlan=20 actions=mod_vlan_vid:40,output:2
cookie=0x0, duration=223.621s, table=0, n_packets=4, n_bytes=308, idle_age=214, in_port=1,dl_vlan=10 actions=mod_vlan_vid:30,output:2
cookie=0x0, duration=223.596s, table=0, n_packets=4, n_bytes=308, idle_age=215, in_port=2,dl_vlan=30 actions=mod_vlan_vid:10,output:1

■ 動作確認
vhost1(192.168.0.1, 拠点1, VLAN ID: 10) から ping で vhost3(192.168.0.3, 拠点2, VLAN ID: 30) とのみ通信できることを確認:

$ sudo ip netns exec vhost1 ping -c2 192.168.0.2
PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
From 192.168.0.1 icmp_seq=1 Destination Host Unreachable
From 192.168.0.1 icmp_seq=2 Destination Host Unreachable

--- 192.168.0.2 ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 999ms
pipe 2

$  sudo ip netns exec vhost1 ping -c2 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_req=1 ttl=64 time=0.849 ms
64 bytes from 192.168.0.3: icmp_req=2 ttl=64 time=0.060 ms

--- 192.168.0.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1003ms
rtt min/avg/max/mdev = 0.060/0.454/0.849/0.395 ms

$ sudo ip netns exec vhost1 ping -c2 192.168.0.4
PING 192.168.0.4 (192.168.0.4) 56(84) bytes of data.
From 192.168.0.1 icmp_seq=1 Destination Host Unreachable
From 192.168.0.1 icmp_seq=2 Destination Host Unreachable

--- 192.168.0.4 ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1010ms
pipe 2

vhost2(192.168.0.2, 拠点1, VLAN ID: 20) から ping で vhost4(192.168.0.4, 拠点2, VLAN ID: 40) とのみ通信できることを確認:

$ sudo ip netns exec vhost2 ping -c2 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
From 192.168.0.2 icmp_seq=1 Destination Host Unreachable
From 192.168.0.2 icmp_seq=2 Destination Host Unreachable

--- 192.168.0.1 ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1005ms
pipe 2

$ sudo ip netns exec vhost2 ping -c2 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
From 192.168.0.2 icmp_seq=1 Destination Host Unreachable
From 192.168.0.2 icmp_seq=2 Destination Host Unreachable

--- 192.168.0.3 ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1004ms
pipe 2

$ sudo ip netns exec vhost2 ping -c2 192.168.0.4
PING 192.168.0.4 (192.168.0.4) 56(84) bytes of data.
64 bytes from 192.168.0.4: icmp_req=1 ttl=64 time=0.809 ms
64 bytes from 192.168.0.4: icmp_req=2 ttl=64 time=0.068 ms

--- 192.168.0.4 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1009ms
rtt min/avg/max/mdev = 0.068/0.438/0.809/0.371 ms

■今回の仮想ネットワークの作成・削除シェルスクリプト
引数 delete で削除、add で追加です。
共通ファイル vnetcommon.sh がカレントディレクトリにおいてあることを前提としています。

赤字にした箇所は記事「◆ 【TremaでOpenFlowプログラミング】VLAN ID コンバータ」の仮想ネットワークのスクリプトからの変更点です。フローテーブルの設定を追加しています。また、スイッチ ofs1 は、OpenFlow コントローラの設定無しにするため addOFSwitch ではなくて addVSwitch を使って追加しています。

#!/bin/sh
. ./vnetcommon.sh

delete() {
    deleteVSwitch "ofs1" "vswitch1" "vswitch2"
    deleteVLink "vlinkSW1" "vlinkSW2"
    deleteVHost "vhost1" "vhost2" "vhost3" "vhost4"
    deleteVLink "vlink1" "vlink2" "vlink3" "vlink4"
}

config_ofs1() {
    sudo ovs-ofctl del-flows "ofs1"

    sudo ovs-ofctl add-flow "ofs1" in_port=1,dl_vlan=10,actions=mod_vlan_vid:30,output:2
    sudo ovs-ofctl add-flow "ofs1" in_port=2,dl_vlan=30,actions=mod_vlan_vid:10,output:1
    sudo ovs-ofctl add-flow "ofs1" in_port=1,dl_vlan=20,actions=mod_vlan_vid:40,output:2
    sudo ovs-ofctl add-flow "ofs1" in_port=2,dl_vlan=40,actions=mod_vlan_vid:20,output:1
    sudo ovs-ofctl add-flow "ofs1" priority=100,actions=drop
}


add() {
    #addOFSwitch "ofs1"
    addVSwitch "ofs1"

    addVSwitch "vswitch1"
    addVSwitch "vswitch2"
    connectVSwitchToVSwitch "vswitch1" "vlinkSW1" "ofs1"
    connectVSwitchToVSwitch "vswitch2" "vlinkSW2" "ofs1"

    addVHost "vhost1"
    connectVHostToVSwitch "vhost1" "vlink1" "vswitch1" tag=10
    vhostExec "vhost1" ifconfig "vlink1" "192.168.0.1"

    addVHost "vhost2"
    connectVHostToVSwitch "vhost2" "vlink2" "vswitch1" tag=20
    vhostExec "vhost2" ifconfig "vlink2" "192.168.0.2"

    addVHost "vhost3"
    connectVHostToVSwitch "vhost3" "vlink3" "vswitch2" tag=30
    vhostExec "vhost3" ifconfig "vlink3" "192.168.0.3"

    addVHost "vhost4"
    connectVHostToVSwitch "vhost4" "vlink4" "vswitch2" tag=40
    vhostExec "vhost4" ifconfig "vlink4" "192.168.0.4"

    config_ofs1
}

case "$1" in
add)
    sudo sh -c exit
    set -x
    add
    ;;
delete)
    sudo sh -c exit
    delete > /dev/null 2>&1
    ;;
*)
    echo "usage: $0 { add | delete }"
esac

vnetcommon.sh のコードは、以前の記事の末尾を参照ください。


記事をひと通り書いてから、気が付いたのですが上記では、ovs-ofctl del-flow をするタイミングが遅いような気がします(一般論として)。del-flow するまでは普通のスイッチとして動いているので、トラブルのもとになりそう。addOFSwitch のOpenfFlow コントローラなし版を作ったほうが良いかもしれません。
[2013/08/10 追記: 上記の気になる点を修正した記事を書きました。]

« ◆ Lubuntu 13.04 に Open vSwitch をインストールした時のログ | トップページ | ◆ 【Open vSwitchのみで OpenFlowプログラミング】VLAN ID コンバータ 改 »

Open vSwitch」カテゴリの記事

Open vSwitch のみで OpenFlow プログラミング」カテゴリの記事

OpenFlow」カテゴリの記事

仮想ネットワーク」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/1776113/52756771

この記事へのトラックバック一覧です: ◆ 【Open vSwitchのみで OpenFlowプログラミング】VLAN ID コンバータ:

« ◆ Lubuntu 13.04 に Open vSwitch をインストールした時のログ | トップページ | ◆ 【Open vSwitchのみで OpenFlowプログラミング】VLAN ID コンバータ 改 »

最近のトラックバック

無料ブログはココログ