#! /bin/sh # Copyright (C) 2009, 2010, 2011, 2012 Nicira Networks, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. case $0 in */*) dir0=`echo "$0" | sed 's,/[^/]*$,,'` ;; *) dir0=./ ;; esac . "$dir0/ovs-lib" || exit 1 for dir in "$sbindir" "$bindir" /sbin /bin /usr/sbin /usr/bin; do case :$PATH: in *:$dir:*) ;; *) PATH=$PATH:$dir ;; esac done ## ----- ## ## start ## ## ----- ## insert_openvswitch_mod_if_required () { # If openvswitch_mod is already loaded then we're done. test -e /sys/module/openvswitch_mod && return 0 # Load openvswitch_mod. If that's successful then we're done. action "Inserting openvswitch module" modprobe openvswitch_mod && return 0 # If the bridge module is loaded, then that might be blocking # openvswitch_mod. Try to unload it, if there are no bridges. test -e /sys/module/bridge || return 1 bridges=`echo /sys/class/net/*/bridge | sed 's,/sys/class/net/,,g;s,/bridge,,g'` if test "$bridges" != "*"; then log_warning_msg "not removing bridge module because bridges exist ($bridges)" return 1 fi action "removing bridge module" rmmod bridge || return 1 # Try loading openvswitch_mod again. action "Inserting openvswitch module" modprobe openvswitch_mod } insert_brcompat_mod_if_required () { test -e /sys/module/brcompat_mod && return 0 action "Inserting brcompat module" modprobe brcompat_mod } insert_mod_if_required () { insert_openvswitch_mod_if_required || return 1 if test X"$BRCOMPAT" = Xyes; then insert_brcompat_mod_if_required || return 1 fi } ovs_vsctl () { ovs-vsctl --no-wait --timeout=5 "$@" } ovsdb_tool () { ovsdb-tool -vANY:console:off "$@" } create_db () { action "Creating empty database $DB_FILE" ovsdb_tool create "$DB_FILE" "$DB_SCHEMA" } upgrade_db () { schemaver=`ovsdb_tool schema-version "$DB_SCHEMA"` if test ! -e "$DB_FILE"; then log_warning_msg "$DB_FILE does not exist" install -d -m 755 -o root -g root `dirname $DB_FILE` create_db elif test X"`ovsdb_tool needs-conversion "$DB_FILE" "$DB_SCHEMA"`" != Xno; then # Back up the old version. version=`ovsdb_tool db-version "$DB_FILE"` cksum=`ovsdb_tool db-cksum "$DB_FILE" | awk '{print $1}'` backup=$DB_FILE.backup$version-$cksum action "Backing up database to $backup" cp "$DB_FILE" "$backup" || return 1 # Compact database. This is important if the old schema did not enable # garbage collection (i.e. if it did not have any tables with "isRoot": # true) but the new schema does. In that situation the old database # may contain a transaction that creates a record followed by a # transaction that creates the first use of the record. Replaying that # series of transactions against the new database schema (as "convert" # does) would cause the record to be dropped by the first transaction, # then the second transaction would cause a referential integrity # failure (for a strong reference). # # Errors might occur on an Open vSwitch downgrade if ovsdb-tool doesn't # understand some feature of the schema used in the OVSDB version that # we're downgrading from, so we don't give up on error. action "Compacting database" ovsdb_tool compact "$DB_FILE" # Upgrade or downgrade schema. if action "Converting database schema" ovsdb_tool convert "$DB_FILE" "$DB_SCHEMA"; then : else log_warning_msg "Schema conversion failed, using empty database instead" rm -f "$DB_FILE" create_db fi fi } set_system_ids () { set ovs_vsctl set Open_vSwitch . OVS_VERSION=`ovs-vswitchd --version | sed 's/.*) //;1q'` set "$@" ovs-version="$OVS_VERSION" case $SYSTEM_ID in random) id_file=$etcdir/system-id.conf uuid_file=$etcdir/install_uuid.conf if test -e "$id_file"; then SYSTEM_ID=`cat "$id_file"` elif test -e "$uuid_file"; then # Migrate from old file name. . "$uuid_file" SYSTEM_ID=$INSTALLATION_UUID echo "$SYSTEM_ID" > "$id_file" elif SYSTEM_ID=`uuidgen`; then echo "$SYSTEM_ID" > "$id_file" else log_failure_msg "missing uuidgen, could not generate system ID" fi ;; '') log_failure_msg "system ID not configured, please use --system-id" ;; *) ;; esac set "$@" external-ids:system-id="\"$SYSTEM_ID\"" if test X"$SYSTEM_TYPE" != X; then set "$@" system-type="\"$SYSTEM_TYPE\"" else log_failure_msg "no default system type, please use --system-type" fi if test X"$SYSTEM_VERSION" != X; then set "$@" system-version="\"$SYSTEM_VERSION\"" else log_failure_msg "no default system version, please use --system-version" fi action "Configuring Open vSwitch system IDs" "$@" $extra_ids } start () { if test X"$FORCE_COREFILES" = Xyes; then ulimit -Sc 67108864 fi insert_mod_if_required || return 1 if daemon_is_running ovsdb-server; then log_success_msg "ovsdb-server is already running" else # Create initial database or upgrade database schema. upgrade_db || return 1 # Start ovsdb-server. set ovsdb-server "$DB_FILE" set "$@" -vANY:CONSOLE:EMER -vANY:SYSLOG:ERR -vANY:FILE:INFO set "$@" --remote=punix:"$DB_SOCK" set "$@" --remote=db:Open_vSwitch,manager_options set "$@" --private-key=db:SSL,private_key set "$@" --certificate=db:SSL,certificate set "$@" --bootstrap-ca-cert=db:SSL,ca_cert start_daemon "$OVSDB_SERVER_PRIORITY" "$@" || return 1 # Initialize database settings. ovs_vsctl -- init -- set Open_vSwitch . db-version="$schemaver" \ || return 1 set_system_ids || return 1 if test X"$DELETE_BRIDGES" = Xyes; then for bridge in `ovs_vsctl list-br`; do ovs_vsctl del-br $bridge done fi fi if daemon_is_running ovs-vswitchd; then log_success_msg "ovs-vswitchd is already running" else # Increase the limit on the number of open file descriptors. # ovs-vswitchd needs 16 per datapath, plus a few extra, so this # should allow for 256 (or more) bridges. ulimit -n 5000 # Start ovs-vswitchd. set ovs-vswitchd unix:"$DB_SOCK" set "$@" -vANY:CONSOLE:EMER -vANY:SYSLOG:ERR -vANY:FILE:INFO if test X"$MLOCKALL" != Xno; then set "$@" --mlockall fi start_daemon "$OVS_VSWITCHD_PRIORITY" "$@" fi if daemon_is_running ovs-brcompatd; then log_success_msg "ovs-brcompatd is already running" elif test X"$BRCOMPAT" = Xyes; then set ovs-brcompatd set "$@" -vANY:CONSOLE:EMER -vANY:SYSLOG:ERR -vANY:FILE:INFO start_daemon "$OVS_BRCOMPATD_PRIORITY" "$@" fi } ## ---- ## ## stop ## ## ---- ## stop () { stop_daemon ovs-brcompatd stop_daemon ovs-vswitchd stop_daemon ovsdb-server } ## ----------------- ## ## force-reload-kmod ## ## ----------------- ## internal_interfaces () { # Outputs a list of internal interfaces: # # - There is an internal interface for every bridge, whether it # has an Interface record or not and whether the Interface # record's 'type' is properly set or not. # # - There is an internal interface for each Interface record whose # 'type' is 'internal'. # # But ignore interfaces that don't really exist. for d in `(ovs_vsctl --bare \ -- --columns=name find Interface type=internal \ -- list-br) | sort -u` do if test -e "/sys/class/net/$d"; then printf "%s " "$d" fi done } save_interfaces () { "$datadir/scripts/ovs-save" $ifaces > "$script" } force_reload_kmod () { ifaces=`internal_interfaces` action "Detected internal interfaces: $ifaces" true stop script=`mktemp` trap 'rm -f "$script"' 0 1 2 13 15 if action "Saving interface configuration" save_interfaces; then : else log_warning_msg "Failed to save configuration, not replacing kernel module" start exit 1 fi chmod +x "$script" for dp in `ovs-dpctl dump-dps`; do action "Removing datapath: $dp" ovs-dpctl del-dp "$dp" done if test -e /sys/module/brcompat_mod; then action "Removing brcompat module" rmmod brcompat_mod fi if test -e /sys/module/openvswitch_mod; then action "Removing openvswitch module" rmmod openvswitch_mod fi start action "Restoring interface configuration" "$script" rc=$? if test $rc = 0; then level=debug else level=err fi log="logger -p daemon.$level -t ovs-save" $log "force-reload-kmod interface restore script exited with status $rc:" $log -f "$script" } ## --------------- ## ## enable-protocol ## ## --------------- ## enable_protocol () { # Translate the protocol name to a number, because "iptables -n -L" prints # some protocols by name (despite the -n) and therefore we need to look for # both forms. # # (iptables -S output is more uniform but old iptables doesn't have it.) protonum=`grep "^$PROTOCOL[ ]" /etc/protocols | awk '{print $2}'` if expr X"$protonum" : X'[0-9]\{1,\}$' > /dev/null; then :; else log_failure_msg "unknown protocol $PROTOCOL" return 1 fi name=$PROTOCOL match="(\$2 == \"$PROTOCOL\" || \$2 == $protonum)" insert="iptables -I INPUT -p $PROTOCOL" if test X"$DPORT" != X; then name="$name to port $DPORT" match="$match && /dpt:$DPORT/" insert="$insert --dport $DPORT" fi if test X"$SPORT" != X; then name="$name from port $SPORT" match="$match && /spt:$SPORT/" insert="$insert --sport $SPORT" fi insert="$insert -j ACCEPT" if (iptables -n -L INPUT) >/dev/null 2>&1; then if iptables -n -L INPUT | awk "$match { n++ } END { exit n == 0 }" then # There's already a rule for this protocol. Don't override it. log_success_msg "iptables already has a rule for $name, not explicitly enabling" else action "Enabling $name with iptables" $insert fi elif (iptables --version) >/dev/null 2>&1; then action "cannot list iptables rules, not adding a rule for $name" else action "iptables binary not installed, not adding a rule for $name" fi } ## ---- ## ## main ## ## ---- ## set_defaults () { SYSTEM_ID= DELETE_BRIDGES=no BRCOMPAT=no DAEMON_CWD=/ FORCE_COREFILES=yes MLOCKALL=yes OVSDB_SERVER_PRIORITY=-10 OVS_VSWITCHD_PRIORITY=-10 OVS_BRCOMPATD_PRIORITY=-10 DB_FILE=$etcdir/conf.db DB_SOCK=$rundir/db.sock DB_SCHEMA=$datadir/vswitch.ovsschema PROTOCOL=gre DPORT= SPORT= type_file=$etcdir/system-type.conf version_file=$etcdir/system-version.conf if test -e "$type_file" ; then SYSTEM_TYPE=`cat $type_file` SYSTEM_VERSION=`cat $version_file` elif (lsb_release --id) >/dev/null 2>&1; then SYSTEM_TYPE=`lsb_release --id -s` system_release=`lsb_release --release -s` system_codename=`lsb_release --codename -s` SYSTEM_VERSION="${system_release}-${system_codename}" else SYSTEM_TYPE=unknown SYSTEM_VERSION=unknown fi } usage () { set_defaults cat <&2 "$0: unknown option \"$arg\" (use --help for help)" return fi eval $var=\$value } daemons () { echo ovsdb-server ovs-vswitchd if test X"$BRCOMPAT" = Xyes; then echo ovs-brcompatd fi } set_defaults extra_ids= command= for arg do case $arg in -h | --help) usage ;; -V | --version) echo "$0 (Open vSwitch) $VERSION$BUILDNR" exit 0 ;; --external-id=*) value=`expr X"$arg" : 'X[^=]*=\(.*\)'` case $value in *=*) extra_ids="$extra_ids external-ids:$value" ;; *) echo >&2 "$0: --external-id argument not in the form \"key=value\"" exit 1 ;; esac ;; --[a-z]*=*) option=`expr X"$arg" : 'X--\([^=]*\)'` value=`expr X"$arg" : 'X[^=]*=\(.*\)'` type=string set_option ;; --no-[a-z]*) option=`expr X"$arg" : 'X--no-\(.*\)'` value=no type=bool set_option ;; --[a-z]*) option=`expr X"$arg" : 'X--\(.*\)'` value=yes type=bool set_option ;; -*) echo >&2 "$0: unknown option \"$arg\" (use --help for help)" exit 1 ;; *) if test X"$command" = X; then command=$arg else echo >&2 "$0: exactly one non-option argument required (use --help for help)" exit 1 fi ;; esac done case $command in start) start ;; stop) stop ;; status) rc=0 for daemon in `daemons`; do daemon_status $daemon || rc=$? done exit $rc ;; version) for daemon in `daemons`; do $daemon --version done ;; force-reload-kmod) force_reload_kmod ;; load-kmod) insert_mod_if_required ;; enable-protocol) enable_protocol ;; help) usage ;; '') echo >&2 "$0: missing command name (use --help for help)" exit 1 ;; *) echo >&2 "$0: unknown command \"$command\" (use --help for help)" exit 1 ;; esac