ovs-ctl: Drop back to an empty database if schema conversion fails.
[sliver-openvswitch.git] / utilities / ovs-ctl.in
1 #! /bin/sh
2 # Copyright (C) 2009, 2010, 2011 Nicira Networks, Inc.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 case $0 in
17     */*) dir0=`echo "$0" | sed 's,/[^/]*$,,'` ;;
18     *) dir0=./ ;;
19 esac
20 . "$dir0/ovs-lib.sh" || exit 1
21
22 for dir in "$sbindir" "$bindir" /sbin /bin /usr/sbin /usr/bin; do
23     case :$PATH: in
24         *:$dir:*) ;;
25         *) PATH=$PATH:$dir ;;
26     esac
27 done
28
29 ## ----- ##
30 ## start ##
31 ## ----- ##
32
33 insert_modules_if_required () {
34     # If openvswitch_mod is already loaded then we're done.
35     test -e /sys/module/openvswitch_mod && return 0
36
37     # Load openvswitch_mod.  If that's successful then we're done.
38     action "Inserting openvswitch module" modprobe openvswitch_mod && return 0
39
40     # If the bridge module is loaded, then that might be blocking
41     # openvswitch_mod.  Try to unload it, if there are no bridges.
42     test -e /sys/module/bridge || return 1
43     bridges=`echo /sys/class/net/*/bridge | sed 's,/sys/class/net/,,g;s,/bridge,,g'`
44     if test "$bridges" != "*"; then
45         log_warning_msg "not removing bridge module because bridges exist ($bridges)"
46         return 1
47     fi
48     action "removing bridge module" rmmod bridge || return 1
49
50     # Try loading openvswitch_mod again.
51     action "Inserting openvswitch module" modprobe openvswitch_mod
52 }
53
54 ovs_vsctl () {
55     ovs-vsctl --no-wait --timeout=5 "$@"
56 }
57
58 ovsdb_tool () {
59     ovsdb-tool -vANY:console:emer "$@"
60 }
61
62 create_db () {
63     action "Creating empty database $DB_FILE" ovsdb_tool create "$DB_FILE" "$DB_SCHEMA"
64 }
65
66 upgrade_db () {
67     schemaver=`ovsdb_tool schema-version "$DB_SCHEMA"`
68     if test ! -e "$DB_FILE"; then
69         log_warning_msg "$DB_FILE does not exist"
70         install -d -m 755 -o root -g root `dirname $DB_FILE`
71         create_db
72     elif test X"`ovsdb_tool needs-conversion "$DB_FILE" "$DB_SCHEMA"`" != Xno; then
73         # Back up the old version.
74         version=`ovsdb_tool db-version "$DB_FILE"`
75         cksum=`ovsdb_tool db-cksum "$DB_FILE" | awk '{print $1}'`
76         backup=$DB_FILE.backup$version-$cksum
77         action "Backing up database to $backup" cp "$DB_FILE" "$backup" || return 1
78
79         # Compact database.  This is important if the old schema did not enable
80         # garbage collection (i.e. if it did not have any tables with "isRoot":
81         # true) but the new schema does.  In that situation the old database
82         # may contain a transaction that creates a record followed by a
83         # transaction that creates the first use of the record.  Replaying that
84         # series of transactions against the new database schema (as "convert"
85         # does) would cause the record to be dropped by the first transaction,
86         # then the second transaction would cause a referential integrity
87         # failure (for a strong reference).
88         #
89         # Errors might occur on an Open vSwitch downgrade if ovsdb-tool doesn't
90         # understand some feature of the schema used in the OVSDB version that
91         # we're downgrading from, so we don't give up on error.
92         action "Compacting database" ovsdb_tool compact "$DB_FILE"
93
94         # Upgrade or downgrade schema.
95         if action "Converting database schema" ovsdb_tool convert "$DB_FILE" "$DB_SCHEMA"; then
96             :
97         else
98             log_warning_msg "Schema conversion failed, using empty database instead"
99             rm -f "$DB_FILE"
100             create_db
101         fi
102     fi
103 }
104
105 set_system_ids () {
106     set ovs_vsctl set Open_vSwitch .
107
108     OVS_VERSION=`ovs-vswitchd --version | sed 's/.*) //;1q'`
109     set "$@" ovs-version="$OVS_VERSION"
110
111     case $SYSTEM_ID in
112         random)
113             id_file=$etcdir/system-id.conf
114             uuid_file=$etcdir/install_uuid.conf
115             if test -e "$id_file"; then
116                 SYSTEM_ID=`cat "$id_file"`
117             elif test -e "$uuid_file"; then
118                 # Migrate from old file name.
119                 . "$uuid_file"
120                 SYSTEM_ID=$INSTALLATION_UUID
121                 echo "$SYSTEM_ID" > "$id_file"
122             elif SYSTEM_ID=`uuidgen`; then
123                 echo "$SYSTEM_ID" > "$id_file"
124             else
125                 log_failure_msg "missing uuidgen, could not generate system ID"
126             fi
127             ;;
128
129         '')
130             log_failure_msg "system ID not configured, please use --system-id"
131             ;;
132
133         *)
134             ;;
135     esac
136     set "$@" external-ids:system-id="\"$SYSTEM_ID\""
137
138     if test X"$SYSTEM_TYPE" != X; then
139         set "$@" system-type="\"$SYSTEM_TYPE\""
140     else
141         log_failure_msg "no default system type, please use --system-type"
142     fi
143
144     if test X"$SYSTEM_VERSION" != X; then
145         set "$@" system-version="\"$SYSTEM_VERSION\""
146     else
147         log_failure_msg "no default system version, please use --system-version"
148     fi
149
150     action "Configuring Open vSwitch system IDs" "$@" $extra_ids
151 }
152
153 start () {
154     if test X"$FORCE_COREFILES" = Xyes; then
155         ulimit -Sc 67108864
156     fi
157
158     insert_modules_if_required || return 1
159
160     if daemon_is_running ovsdb-server; then
161         log_success_msg "ovsdb-server is already running"
162     else
163         # Create initial database or upgrade database schema.
164         upgrade_db || return 1
165
166         # Start ovsdb-server.
167         set ovsdb-server "$DB_FILE"
168         set "$@" -vANY:CONSOLE:EMER -vANY:SYSLOG:ERR -vANY:FILE:INFO
169         set "$@" --remote=punix:"$DB_SOCK"
170         set "$@" --remote=db:Open_vSwitch,manager_options
171         set "$@" --private-key=db:SSL,private_key
172         set "$@" --certificate=db:SSL,certificate
173         set "$@" --bootstrap-ca-cert=db:SSL,ca_cert
174         start_daemon "$OVSDB_SERVER_PRIORITY" "$@" || return 1
175
176         # Initialize database settings.
177         ovs_vsctl -- init -- set Open_vSwitch . db-version="$schemaver" \
178             || return 1
179         set_system_ids || return 1
180         if test X"$DELETE_BRIDGES" = Xyes; then
181             for bridge in `ovs_vsctl list-br`; do
182                 ovs_vsctl del-br $bridge
183             done
184         fi
185     fi
186
187     if daemon_is_running ovs-vswitchd; then
188         log_success_msg "ovs-vswitchd is already running"
189     else
190         # Increase the limit on the number of open file descriptors since
191         # ovs-vswitchd needs a few per bridge
192         ulimit -n 4096
193
194         # Start ovs-vswitchd.
195         set ovs-vswitchd unix:"$DB_SOCK"
196         set "$@" -vANY:CONSOLE:EMER -vANY:SYSLOG:ERR -vANY:FILE:INFO
197         if test X"$MLOCKALL" != Xno; then
198             set "$@" --mlockall
199         fi
200         start_daemon "$OVS_VSWITCHD_PRIORITY" "$@"
201     fi
202 }
203
204 ## ---- ##
205 ## stop ##
206 ## ---- ##
207
208 stop () {
209     stop_daemon ovs-vswitchd
210     stop_daemon ovsdb-server
211 }
212
213 ## ----------------- ##
214 ## force-reload-kmod ##
215 ## ----------------- ##
216
217 internal_interfaces () {
218     # Outputs a list of internal interfaces:
219     #
220     #   - There is an internal interface for every bridge, whether it
221     #     has an Interface record or not and whether the Interface
222     #     record's 'type' is properly set or not.
223     #
224     #   - There is an internal interface for each Interface record whose
225     #     'type' is 'internal'.
226     #
227     # But ignore interfaces that don't really exist.
228     for d in `(ovs_vsctl --bare \
229                 -- --columns=name find Interface type=internal \
230                 -- list-br) | sort -u`
231     do
232         if test -e "/sys/class/net/$d"; then
233             printf "%s " "$d"
234         fi
235     done
236 }
237
238 save_interfaces () {
239     "$datadir/scripts/ovs-save" $ifaces > "$script"
240 }
241
242 force_reload_kmod () {
243     ifaces=`internal_interfaces`
244     action "Detected internal interfaces: $ifaces" true
245
246     stop
247
248     script=`mktemp`
249     trap 'rm -f "$script"' 0 1 2 13 15
250     if action "Saving interface configuration" save_interfaces; then
251         :
252     else
253         log_warning_msg "Failed to save configuration, not replacing kernel module"
254         start
255         exit 1
256     fi
257     chmod +x "$script"
258
259     for dp in `ovs-dpctl dump-dps`; do
260         action "Removing datapath: $dp" ovs-dpctl del-dp "$dp"
261     done
262
263     if test -e /sys/module/openvswitch_mod; then
264         action "Removing openvswitch module" rmmod openvswitch_mod
265     fi
266
267     start
268
269     action "Restoring interface configuration" "$script"
270     rc=$?
271     if test $rc = 0; then
272         level=debug
273     else
274         level=err
275     fi
276     log="logger -p daemon.$level -t ovs-save"
277     $log "force-reload-kmod interface restore script exited with status $rc:"
278     $log -f "$script"
279 }
280
281 ## --------------- ##
282 ## enable-protocol ##
283 ## --------------- ##
284
285 enable_protocol () {
286     # Translate the protocol name to a number, because "iptables -n -L" prints
287     # some protocols by name (despite the -n) and therefore we need to look for
288     # both forms.
289     #
290     # (iptables -S output is more uniform but old iptables doesn't have it.)
291     protonum=`grep "^$PROTOCOL[         ]" /etc/protocols | awk '{print $2}'`
292     if expr X"$protonum" : X'[0-9]\{1,\}$' > /dev/null; then :; else
293         log_failure_msg "unknown protocol $PROTOCOL"
294         return 1
295     fi
296
297     name=$PROTOCOL
298     match="(\$2 == \"$PROTOCOL\" || \$2 == $protonum)"
299     insert="iptables -I INPUT -p $PROTOCOL"
300     if test X"$DPORT" != X; then
301         name="$name to port $DPORT"
302         match="$match && /dpt:$DPORT/"
303         insert="$insert --dport $DPORT"
304     fi
305     if test X"$SPORT" != X; then
306         name="$name from port $SPORT"
307         match="$match && /spt:$SPORT/"
308         insert="$insert --sport $SPORT"
309     fi
310     insert="$insert -j ACCEPT"
311
312     if (iptables -n -L INPUT) >/dev/null 2>&1; then
313         if iptables -n -L INPUT | awk "$match { n++ } END { exit n == 0 }"
314         then
315             # There's already a rule for this protocol.  Don't override it.
316             log_success_msg "iptables already has a rule for $name, not explicitly enabling"
317         else
318             action "Enabling $name with iptables" $insert
319         fi
320     elif (iptables --version) >/dev/null 2>&1; then
321         action "cannot list iptables rules, not adding a rule for $name"
322     else
323         action "iptables binary not installed, not adding a rule for $name"
324     fi
325 }
326
327 ## ---- ##
328 ## main ##
329 ## ---- ##
330
331 set_defaults () {
332     SYSTEM_ID=
333
334     DELETE_BRIDGES=no
335
336     DAEMON_CWD=/
337     FORCE_COREFILES=yes
338     MLOCKALL=yes
339     OVSDB_SERVER_PRIORITY=-10
340     OVS_VSWITCHD_PRIORITY=-10
341
342     DB_FILE=$etcdir/conf.db
343     DB_SOCK=$rundir/db.sock
344     DB_SCHEMA=$datadir/vswitch.ovsschema
345
346     PROTOCOL=gre
347     DPORT=
348     SPORT=
349
350     if (lsb_release --id) >/dev/null 2>&1; then
351         SYSTEM_TYPE=`lsb_release --id -s`
352         system_release=`lsb_release --release -s`
353         system_codename=`lsb_release --codename -s`
354         SYSTEM_VERSION="${system_release}-${system_codename}"
355     else
356         SYSTEM_TYPE=unknown
357         SYSTEM_VERSION=unknown
358     fi
359 }
360
361 usage () {
362     set_defaults
363     cat <<EOF
364 $0: controls Open vSwitch daemons
365 usage: $0 [OPTIONS] COMMAND
366
367 This program is intended to be invoked internally by Open vSwitch startup
368 scripts.  System administrators should not normally invoke it directly.
369
370 Commands:
371   start              start Open vSwitch daemons
372   stop               stop Open vSwitch daemons
373   status             check whether Open vSwitch daemons are running
374   version            print versions of Open vSwitch daemons
375   force-reload-kmod  save OVS network device state, stop OVS, unload kernel
376                      module, reload kernel module, start OVS, restore state
377   enable-protocol    enable protocol specified in options with iptables
378   help               display this help message
379
380 One of the following options should be specified when starting Open vSwitch:
381   --system-id=UUID   set specific ID to uniquely identify this system
382   --system-id=random  use a random but persistent UUID to identify this system
383
384 Other important options for starting Open vSwitch:
385   --system-type=TYPE  set system type (e.g. "XenServer")
386   --system-version=VERSION  set system version (e.g. "5.6.100-39265p")
387   --external-id="key=value"
388                      add given key-value pair to Open_vSwitch external-ids
389   --delete-bridges   delete all bridges just before starting ovs-vswitchd
390
391 Less important options for starting Open vSwitch:
392   --daemon-cwd=DIR   current working directory for OVS daemons (default: $DAEMON_CWD)
393   --no-force-corefiles
394                      do not forcibly enable core dumps for OVS daemons
395   --no-mlockall      do not lock all of ovs-vswitchd into memory
396   --ovsdb-server-priority=NICE
397                      set ovsdb-server's niceness (default: $OVSDB_SERVER_PRIORITY)
398   --ovs-vswitchd-priority=NICE
399                      set ovs-vswitchd's niceness (default: $OVS_VSWITCHD_PRIORITY)
400
401 File location options:
402   --db-file=FILE     database file name (default: $DB_FILE)
403   --db-sock=SOCKET   JSON-RPC socket name (default: $DB_SOCK)
404   --db-schema=FILE   database schema file name (default: $DB_SCHEMA)
405
406 Options for enable-protocol:
407   --protocol=PROTOCOL  protocol to enable with iptables (default: gre)
408   --sport=PORT       source port to match (for tcp or udp protocol)
409   --dport=PORT       ddestination port to match (for tcp or udp protocol)
410
411 Other options:
412   -h, --help                  display this help message
413   -V, --version               display version information
414
415 Default directories with "configure" option and environment variable override:
416   logs: @LOGDIR@ (--log-dir, OVS_LOGDIR)
417   pidfiles and sockets: @RUNDIR@ (--run-dir, OVS_RUNDIR)
418   system configuration: @sysconfdir@ (--sysconfdir, OVS_SYSCONFDIR)
419   data files: @pkgdatadir@ (--pkgdatadir, OVS_PKGDATADIR)
420   user binaries: @bindir@ (--bindir, OVS_BINDIR)
421   system binaries: @sbindir@ (--sbindir, OVS_SBINDIR)
422
423 Please report bugs to bugs@openvswitch.org (see REPORTING-BUGS for details).
424 EOF
425
426     exit 0
427 }
428
429 set_option () {
430     var=`echo "$option" | tr abcdefghijklmnopqrstuvwxyz- ABCDEFGHIJKLMNOPQRSTUVWXYZ_`
431     eval set=\${$var+yes}
432     eval old_value=\$$var
433     if test X$set = X || \
434         (test $type = bool && \
435         test X"$old_value" != Xno && test X"$old_value" != Xyes); then
436         echo >&2 "$0: unknown option \"$arg\" (use --help for help)"
437         return
438     fi
439     eval $var=\$value
440 }
441
442 set_defaults
443 extra_ids=
444 command=
445 for arg
446 do
447     case $arg in
448         -h | --help)
449             usage
450             ;;
451         -V | --version)
452             echo "$0 (Open vSwitch) $VERSION$BUILDNR"
453             exit 0
454             ;;
455         --external-id=*)
456             value=`expr X"$arg" : 'X[^=]*=\(.*\)'`
457             case $value in
458                 *=*)
459                     extra_ids="$extra_ids external-ids:$value"
460                     ;;
461                 *)
462                     echo >&2 "$0: --external-id argument not in the form \"key=value\""
463                     exit 1
464                     ;;
465             esac
466             ;;
467         --[a-z]*=*)
468             option=`expr X"$arg" : 'X--\([^=]*\)'`
469             value=`expr X"$arg" : 'X[^=]*=\(.*\)'`
470             type=string
471             set_option
472             ;;
473         --no-[a-z]*)
474             option=`expr X"$arg" : 'X--no-\(.*\)'`
475             value=no
476             type=bool
477             set_option
478             ;;
479         --[a-z]*)
480             option=`expr X"$arg" : 'X--\(.*\)'`
481             value=yes
482             type=bool
483             set_option
484             ;;
485         -*)
486             echo >&2 "$0: unknown option \"$arg\" (use --help for help)"
487             exit 1
488             ;;
489         *)
490             if test X"$command" = X; then
491                 command=$arg
492             else
493                 echo >&2 "$0: exactly one non-option argument required (use --help for help)"
494                 exit 1
495             fi
496             ;;
497     esac
498 done
499 case $command in
500     start)
501         start
502         ;;
503     stop)
504         stop
505         ;;
506     status)
507         daemon_status ovsdb-server && daemon_status ovs-vswitchd
508         ;;
509     version)
510         ovsdb-server --version && ovs-vswitchd --version
511         ;;
512     force-reload-kmod)
513         force_reload_kmod
514         ;;
515     enable-protocol)
516         enable_protocol
517         ;;
518     help)
519         usage
520         ;;
521     '')
522         echo >&2 "$0: missing command name (use --help for help)"
523         exit 1
524         ;;
525     *)
526         echo >&2 "$0: unknown command \"$command\" (use --help for help)"
527         exit 1
528         ;;
529 esac
530