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