#!/bin/bash # -*-shell-mode-*- ### expected to be run as root COMMAND=$0 #################### global vars RUN_DIR=/var/run/openvswitch DB_CONF_FILE=/etc/openvswitch/conf.db DB_SCHEMA=/usr/share/openvswitch/vswitch.ovsschema DB_PID_FILE=/var/run/openvswitch/db.pid DB_LOG=/var/log/ovs-db.log DB_CTL_PATTERN='ovsdb-server.*.ctl' ## DB_SOCKET=/var/run/openvswitch/db.sock ## SWITCH_PID_FILE=/var/run/openvswitch/switch.pid SWITCH_LOG=/var/log/ovs-switch.log SWITCH_SOCKET=/var/run/openvswitch/switch.sock #################### helper functions function kill_pltap_ovs () { killall pltap-ovs 2>/dev/null || : } function error { echo "$@" >&2 exit 1 } function is_switch_running { ovs-appctl --target=$SWITCH_SOCKET version >& /dev/null } function tapname () { IP=$1; shift echo $(ip addr show to "$IP/32" | perl -ne '/^\s*\d+:\s*([\w-]+):/ && print $1') } function wait_server () { pid_file=$1; shift server_name=$1; shift timeout=$1; shift expire=$(($(date +%s) + $timeout)) ## wait for it to be up - xxx todo - could use a timeout of some kind while [ ! -f "$pid_file" ]; do echo "Waiting for $server_name to start... $(($expire - $(date +%s)))s left" >&2 sleep 1; [ $(date +%s) -ge $expire ] && return 1 done cat "$pid_file" } function wait_device () { tapname=$1; shift timeout=$1; shift expire=$(($(date +%s) + $timeout)) while ! ip link show up | egrep -q "^[0-9]+: +$tapname:"; do echo "Waiting for $tapname to come UP...$(($expire - $(date +%s)))s left" >&2 sleep 1 [ $(date +%s) -ge $expire ] && return 1 done return 0 } ######################################## startup function start_db () { [[ -n "$@" ]] && error "Usage: $COMMAND start-db" ## init conf conf_dir=$(dirname $DB_CONF_FILE) [ -d $conf_dir ] || mkdir -p $conf_dir [ -f $DB_CONF_FILE ] || ovsdb-tool create $DB_CONF_FILE $DB_SCHEMA ## init run [ -d $RUN_DIR ] || mkdir -p $RUN_DIR ## check [ -f $DB_CONF_FILE ] || { echo "Could not initialize $DB_CONF_FILE - exiting" ; exit 1 ; } [ -d $RUN_DIR ] || { echo "Could not initialize $RUN_DIR - exiting" ; exit 1 ; } ## run the stuff if [ ! -f "$DB_PID_FILE" ]; then ovsdb-server --remote=punix:$DB_SOCKET \ --remote=db:Open_vSwitch,manager_options \ --private-key=db:SSL,private_key \ --certificate=db:SSL,certificate \ --bootstrap-ca-cert=db:SSL,ca_cert \ --pidfile=$DB_PID_FILE \ --log-file=$DB_LOG \ --detach >& /dev/null else echo 'ovsdb-server appears to be running already, *not* starting' fi wait_server $DB_PID_FILE ovsdb-server 30 echo $DB_PID_FILE } function start_switch () { [[ -n "$@" ]] && error "Usage: $COMMAND start-switch" if [ ! -f "$SWITCH_PID_FILE" ] ; then ovs-vswitchd \ --pidfile=$SWITCH_PID_FILE \ --log-file=$SWITCH_LOG \ --unixctl=$SWITCH_SOCKET \ --detach \ unix:$DB_SOCKET >& /dev/null else echo 'ovs-vswitchd appears to be running already, *not* starting' fi wait_server $SWITCH_PID_FILE ovs-vswitchd 30 } # first dumb stab just read "pkill ovsdb-server" and "pkill ovs-vswitchd" # quick and dirty : we locate the control file through a search in /var/run # caller should be requested to remember and provide this pid instead function stop_db () { controlfile=$(ls $RUN_DIR/$DB_CTL_PATTERN) [ -f $controlfile ] && ovs-appctl --target=$controlfile exit } function stop_switch () { ovs-appctl --target=$SWITCH_SOCKET exit || : } function status () { pids=$(pgrep '^ovs') [ -n "$pids" ] && ps $pids } function start () { start_db start_switch } function stop () { stop_switch stop_db } #################### create functions function create_bridge () { [[ -z "$@" ]] && error "Usage: ${COMMAND} create-bridge " ip_prefix=$1; shift [[ -n "$@" ]] && error "Usage: ${COMMAND} create-bridge " IP=${ip_prefix%/*} PREFIX=${ip_prefix#*/} set -e # ensure ovs-vswitchd is running is_switch_running || { echo "ovs-vswitchd not running" >&2 ; exit 1 ; } # check whether the address is already assigned TAPNAME=$(tapname $IP) if [ ! -z "$TAPNAME" ]; then if ovs-vsctl --db=unix:$DB_SOCKET br-exists "$TAPNAME"; then echo $TAPNAME exit 0 fi kill_pltap_ovs error "$IP already assigned to $TAPNAME" fi # we're clear TAPNAME=$(pltap-ovs) # xxx wouldn't that be safer if left-aligned ? vsysc vif_up << EOF $TAPNAME $IP $PREFIX EOF wait_device $TAPNAME 60 && \ ovs-vsctl --db=unix:$DB_SOCKET add-br $TAPNAME -- set bridge $TAPNAME datapath_type=planetlab echo $TAPNAME return 0 } function create_port () { [[ -z "$@" ]] && error "$COMMAND create-port " bridge=$1; shift [[ -z "$@" ]] && error "$COMMAND create-port " port=$1; shift [[ -n "$@" ]] && error "$COMMAND create-port " set -e if ! ovs-vsctl --db=unix:$DB_SOCKET list-ports "$bridge" | grep -q "^$port\$"; then ovs-vsctl --db=unix:$DB_SOCKET add-port "$bridge" "$port" -- set interface "$port" type=tunnel fi ovs-appctl --target=$SWITCH_SOCKET netdev-tunnel/get-port "$port" return 0 } #################### del functions function del_bridge () { [[ -z "$@" ]] && error "Usage: ${COMMAND} del-bridge " bridge_name=$1; shift [[ -n "$@" ]] && error "Usage: ${COMMAND} del-bridge " W= is_switch_running || W="--no-wait" if ovs-vsctl --db=unix:$DB_SOCKET br-exists "$bridge_name"; then ovs-vsctl --db=unix:$DB_SOCKET $W del-br $bridge_name fi return 0 } function del_port () { [[ -z "$@" ]] && error "Usage: ${COMMAND} del-port " bridge_name=$1; shift [[ -n "$@" ]] && error "Usage: ${COMMAND} del-port " set -e if ovs-vsctl --db=unix:$DB_SOCKET port-to-br "$1" >/dev/null 2>&1; then ovs-vsctl --db=unix:$DB_SOCKET del-port "$1" fi return 0 } #################### SUPPORTED_SUBCOMMANDS="start stop status start_db stop_db start_switch stop_switch create_bridge create_port del_bridge del_port" function main () { message="Usage: $COMMAND ... Supported subcommands are (dash or underscore is the same): $SUPPORTED_SUBCOMMANDS" [[ -z "$@" ]] && error "$message" subcommand=$1; shift # support dashes instead of underscores subcommand=$(echo $subcommand | sed -e s,-,_,) found="" for supported in $SUPPORTED_SUBCOMMANDS; do [ "$subcommand" = "$supported" ] && found=yes; done [ -z "$found" ] && error $message $subcommand "$@" } main "$@"