Shadow bridging and Xen

Xenがデフォルトで使うネットワークブリッジの設定スクリプトは、いったんネットワークを切断してしまう。
これはいろいろとよろしくないので、あらかじめ作っておいたブリッジに、vifを単純に追加するだけの設定スクリプトを作った。


まずはブリッジを作るスクリプト。RedHat系のディストリビューションなら動くと思うけど、試したのはMandriva 2007だけ。
/etc/init.d/bridge-shadow

#!/bin/bash
# chkconfig: 2345 05 89
# description: Shadow Layer 2 Bridge
#

# Source function library.
. /etc/init.d/functions

INTERFACES=""
[ -f /etc/sysconfig/bridge-shadow ] && . /etc/sysconfig/bridge-shadow

PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin

start() {
    gprintf "Starting Shadow Layer 2 Bridge: "

    msg=""

    for i in $INTERFACES; do
            # load aliased drivers
            ifconfig "$i" 0.0.0.0 up

            # link down interface
            ip link set "$i" down
            ip addr flush dev "$i" 2>/dev/null

            # swap name
            ip link set "$i" name "s$i"

            # add bridge
            brctl addbr "$i"

            # add interface to bridge
            brctl addif "$i" "s$i"

            # link up bridge
            ip link set "$i" up

            # link up interface
            ifconfig "s$i" 0.0.0.0 up
    done

    # wait for bridge to be in running state
    for i in $INTERFACES; do
            try=0
            while [ "$try" -lt 50 ]; do
                    if ifconfig "$i" | grep -q "RUNNING"; then
                            break
                    else
                            usleep 100000
                    fi
                    try=$(expr $try + 1)
            done
    done

    if [ -n "$msg" ];then
            failure "$msg"
    else
            success
    fi

    echo
}

stop() {
    gprintf "Shutting down Shadow Layer 2 Bridge: "

    msg=""

    for i in $INTERFACES; do
            # link down interface
            ip link set "s$i" down
            ip addr flush dev "s$i" 2>/dev/null

            # link down bridge
            ip link set "$i" down
            ip addr flush dev "$i" 2>/dev/null

            # delete interface from bridge
            brctl delif "$i" "s$i"

            # delete bridge
            brctl delbr "$i"

            # swap name
            ip link set "s$i" name "$i"
    done

    if [ -n "$msg" ];then
            failure "$msg"
    else
            success
    fi

    echo
}

status() {
    brctl show
}

case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  restart)
        stop
        sleep 1
        start
        ;;
  status)
        status
        ;;
  *)
        gprintf "Usage: %s {star|stop|restart|status}\n" "$0"
        exit 1
esac

/etc/sysconfig/bridge-shadow

INTERFACES="eth0"
  1. eth0をリンクダウンし、名前をseth0に変更する。
  2. eth0という名前のブリッジを作る
  3. eth0(ブリッジ)にseth0(物理インターフェース)を追加する

というもの。ブリッジ前後で使用するネットワークインターフェースの名前が変わらない。
ちなみにeth0(ブリッジ)のMACアドレスは、seth0(物理インターフェース)と同じになる。

chkconfigなどを使って、bridge-shadowが起動された後にネットワークが立ち上がるようにしておく。




Xenのブリッジ構築スクリプト:
/etc/xen/scripts/network-bridge-additional

#!/bin/sh
#============================================================================
# Custermized Xen network start/stop script.
# Xend calls a network script when it starts.
# The script name to use is defined in /etc/xen/xend-config.sxp
# in the network-script field.
#
# This script just adds the virtual device to the existent bridge,
# doesn't set IP addresses.
# Setting IP addresses or
#
# Usage:
#
# network-bridge-additional (start|stop|status) {VAR=VAL}*
#
# Vars:
#
# vifnum     Virtual device number to use (default 0). Numbers >=8
#            require the netback driver to have nloopbacks set to a
#            higher value than its default of 8.
# bridge     The bridge to use (default xenbr${vifnum}).
# antispoof  Whether to use iptables to prevent spoofing (default no).
#
# Internal Vars:
# vif0="vif0.${vifnum}"
#
# start:
# Enslaves vif0 to bridge
#
# stop:
# Removes vif0 from the bridge
#
# status:
# Print addresses, interfaces, routes
#
#============================================================================


dir=$(dirname "$0")
. "$dir/xen-script-common.sh"
. "$dir/xen-network-common.sh"

findCommand "$@"
evalVariables "$@"

vifnum=${vifnum:-$(ip route list | awk '/^default / { print $NF }' | sed 's/^[^0-9]*//')}
vifnum=${vifnum:-0}
bridge=${bridge:-xenbr${vifnum}}
antispoof=${antispoof:-no}

vif0="vif0.${vifnum}"


##
# link_exists interface
#
# Returns 0 if the interface named exists (whether up or down), 1 otherwise.
#
link_exists()
{
    if ip link show "$1" >/dev/null 2>/dev/null
    then
        return 0
    else
        return 1
    fi
}

# Set the default forwarding policy for $dev to drop.
# Allow forwarding to the bridge.
antispoofing () {
    iptables -P FORWARD DROP
    iptables -F FORWARD
    iptables -A FORWARD -m physdev --physdev-in ${vif0} -j ACCEPT
}

# Usage: show_status bridge
# Print ifconfig and routes.
show_status () {
    local bridge=$1

    echo '============================================================'
    ip addr show ${bridge}
    echo ' '
    brctl show ${bridge}
    echo ' '
    ip route list
    echo ' '
    route -n
    echo '============================================================'
}

op_start () {
    if [ "${bridge}" = "null" ] ; then
        return
    fi
    if ! link_exists "$bridge"; then
        return
    fi

    # FIXME: Check wheter the device is already up.

    ip link set ${bridge} up
    add_to_bridge2 ${bridge} ${vif0}

    if [ ${antispoof} = 'yes' ] ; then
        antispoofing
    fi
}

op_stop () {
    if [ "${bridge}" = "null" ]; then
        return
    fi
    if ! link_exists "$bridge"; then
        return
    fi

    ip link set ${vif0} down
    ip addr flush ${vif0}

    brctl delif ${bridge} ${vif0}
}

# adds $dev to $bridge but waits for $dev to be in running state first
add_to_bridge2() {
    local bridge=$1
    local dev=$2
    local maxtries=10

    echo -n "Waiting for ${dev} to negotiate link."
    ip link set ${dev} up
    for i in `seq ${maxtries}` ; do
        if ifconfig ${dev} | grep -q RUNNING ; then
            break
        else
            echo -n '.'
            sleep 1
        fi
    done

    if [ ${i} -eq ${maxtries} ] ; then echo '(link isnt in running state)' ; fi

    add_to_bridge ${bridge} ${dev}
}

case "$command" in
    start)
        op_start
        ;;

    stop)
        op_stop
        ;;

    status)
        show_status ${bridge}
        ;;

    *)
        echo "Unknown command: $command" >&2
        echo 'Valid commands are: start, stop, status' >&2
        exit 1
esac


xendの設定ファイル:
/etc/xend-config.sxp

(network-script 'network-bridge-additional bridge=eth0')
(vif-script 'vif-bridge bridge=eth0')


ゲストドメインの設定ファイルでは、vif = [ 'type=ioemu, bridge=eth0' ] とブリッジ先を明示するようにする。