openvswitch installと設定

参考:

source最新版にopenvswitch-1.2.2.tar.gz があるけど、redhat用の起動スクリプトにBRCOMPAT(linux互換のブリッジモード)の設定が入っていなかったり,他にも何か怪しいのでgitの最新使ったほうがよい。

Scientific Linux 6.1 + libvirt 0.8.7で実験。仮想化のホストサーバになるのでブリッジを利用。

目的

(VLANを分けたりせずに同一のネットワークで仮想マシンを構築して)仮想マシンにroot権限付きで渡した場合に、任意にIPを変えられると重複したりするので困る。そこで仮想マシン(正確には、それに割り当てるNICMACアドレス)とIPアドレスをホストOS側で管理したい。

結論

とりあえず結論を先に書くと、やりたいことは一応できたけど仮想マシンの起動/停止の際のflowの自動適用をどうやればいいかわからないので実用できず。さくらはどうやってんだろう。。。

install

autoconf 2.64以上のinstall

openvswitch 1.3以上の場合はautoconf 2.64以上が必要。しかしSL 6.1はautoconf 2.63 なのでこれもsourceから最新を入れる。

展開して普通にconfigure && make && make install

openvswitch install

linuxのbridgeの設定が入っているとinstallできないので、入れている場合は外しておく。
SL6.1なのでINSTALL.RHEL を参考にしてrpmパッケージ作る方法でやった。他のdistriの場合はINSTALL.Linuxを参考に、make, make install, insmod をするぐらいなのでほとんど同じなはず。

  • rpmファイル完成
$ git clone git://openvswitch.org/openvswitch
#### boot.shのautoreconfのPATHをあらかじめinstallした最新版の場所に変更
$ perl -pi -e 's!autoreconf!/usr/local/bin/autoreconf!' boot.sh
$ ./configure --with-linux=/lib/modules/`uname -r`/build
$ make dist
$ rpmbuild -bb rhel/openvswitch.spec
$ rpmbuild -bb rhel/openvswitch-kmod-rhel6.spec
$ ls -1 ~/rpmbuild/RPMS/x86_64/
kmod-openvswitch-1.4.90-1.el6.x86_64.rpm
openvswitch-1.4.90-1.x86_64.rpm
openvswitch-debuginfo-1.4.90-1.x86_64.rpm
  • install
$ cd ~/rpmbuild/RPMS/x86_64/
$ su -
# rpm -ivh *rpm
# ovs-vsctl -V
ovs-vsctl (Open vSwitch) 1.4.90
# chkconfig openvswitch on
# vim /etc/sysconfig/openvswitch
##### BRCOMPAT=yes に変更
# /etc/init.d/openvswitch start
##### /etc/openvswitch/conf.db 等は勝手に作ってくれる
# ovs-vsctl show
##### version, interface等が出てくればOK

bridgeの設定

bridgeに割り当てる時に一旦NICが切れるので、コンソールで作業するか複数NICがある場合には作業しないNICからログインして1つずつ作業する。

eth0をbr0に割り当てる
# ifdown eth0
# ovs-vsctl add-br br0
# ovs-vsctl add-port br0 eth0
ifcfg configの設定

通常のbridge設定とほとんど同じ。1つ違うのは"eth0をbr0に割り当てる"というところはovs-vsctlで設定しているので(実態はovsdb-serverがもっている/etc/openvswitch/conf.db)
ifcfg-eth0にBRIDGE=br0 という設定は"書かない"。

# cd /etc/sysconfig/network-scripts/
# vi ifcfg-eth0
DEVICE="eth0"
BOOTPROTO="none"
IPV6INIT="yes"
ONBOOT="yes"
# vi ifcfg-br0
DEVICE="br0"
BOOTPROTO="none"
ONBOOT="yes"
TYPE="Bridge"

IPADDR=192.168.0.10
NETMASK=255.255.255.0

network restartでbridge deviceにIPがつくことを確認

IP/ARP 偽装対策

初めにも書いたけど一番やりたかったのはこれ。仮想OSでroot権限を渡していると同じネットワークの他のIPを偽装(偽装というかこっちが想定していない他のIPを勝手に割り振る)
出来てしまうのでそれを制限する。

ex: 仮想マシンAのeth0 52:54:00:11:22:33 (ホストOS上でvnet0のFE:54:00:11:22:33)を192.168.0.100 に制限するflowを適用する

ovs-ofctlの最後の引数はスペースを入れないのだったらクォート不要。

注意点

KVMの仕様? KVMの仮想OS上のNICmacアドレスは(手動で設定しない限り)52:54:00:から始まるんだけど、ホストOS上のvnet0ではFE:54:00と表示されている。当然ovs-ofctl で出力される値もfe:54:00:...となるが、ovs-ofctlで設定するflowには仮想OS本来のMACアドレス 52:54:00 で設定しないとダメ。

flowの適用

  1. MAC-IPの組み合わせが一致するものはnormal => 許可
  2. それ以外はdrop => 拒否 というflow

このときpriorityを書いておかないと、問答無用でdropされてしまうようなので、

  • 明示的にpriorityを設定し、dropするflowを一番低いpriorityにする
  • dropするflowのpriority=0 に設定し、他にはpriorityを設定しない

などの設定が必要になる。

# ovs-ofctl show br0 | grep vnet0
2(vnet0): addr:fe:54:00:11:22:33
#### => id 2 が割り当てられている
# ovs-ofctl add-flow br0 'in_port=2, dl_src=52:54:00:11:22:33, \
priority=100, ip, nw_src=192.168.0.100, actions=normal'
# ovs-ofctl add-flow br0 'in_port=2, dl_src=52:54:00:11:22:33, \
priority=100, arp, nw_src=192.168.0.100, actions=normal'
# ovs-ofctl add-flow br0 'in_port=2, dl_src=52:54:00:11:22:33, \
udp, nw_src=0.0.0.0,tp_src=68, nw_dst=255.255.255.255, tp_dst=67, actions=normal'
# ovs-ofctl add-flow br0 'in_port=2, priority=0, action=drop'

これで完了。

flowの削除

特定の仮想NICのflowを消す場合はin_portを指定する。

# ovs-ofctl del-flows br0 in_port=2

in_port=2 を指定しないとbr0の全flowが削除されてしまう == defaultで用意されているactions=normalのflowも消えてしまってbr0の全通信が拒否されてしまうので注意。

flowの保存

dump-flowsでflowの内容がテキストに出てくるのでファイルに保存

# ovs-ofctl dump-flows br0
NXST_FLOW reply (xid=0x4):
 cookie=0x0, duration=11.052s, table=0, n_packets=49, n_bytes=5908, priority=0 actions=NORMAL
# ovs-ofctl dump-flows br0 | grep -v NXST_FLOW > br0.flow

cookie=.. からはじまる部分がflowルールの本体。これをadd-flowsの引数に与えれば
保存していたflowを追加できる。

# ovs-ofctl add-flows br0 br0.flow

問題点

flow適用のところで書いた

# ovs-ofctl show br0 | grep vnet0
2(vnet0): addr:fe:54:00:11:22:33

この2という数値がNICのidでflowの大事な識別子になるんだけど、これが仮想マシンが停止/起動する度にコロコロ変わる(当然か)。これをイベントドリブンのようにリアルタイムに検知して動的にflowを適用するという手段が思いつかないのでどうすりゃいいんだろう。。。

追記

openvswitch 挫折したのでlibvirtのnwfilterでやってみた。