ovs-ctl.in: Clean up code for the next commit.
[sliver-openvswitch.git] / utilities / ovs-ctl.in
1 #! /bin/sh
2 # Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicira, 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" || 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_openvswitch_mod_if_required () {
34     # If openvswitch is already loaded then we're done.
35     test -e /sys/module/openvswitch -o -e /sys/module/openvswitch_mod && \
36      return 0
37
38     # Load openvswitch.  If that's successful then we're done.
39     action "Inserting openvswitch module" modprobe openvswitch && return 0
40
41     # If the bridge module is loaded, then that might be blocking
42     # openvswitch.  Try to unload it, if there are no bridges.
43     test -e /sys/module/bridge || return 1
44     bridges=`echo /sys/class/net/*/bridge | sed 's,/sys/class/net/,,g;s,/bridge,,g'`
45     if test "$bridges" != "*"; then
46         log_warning_msg "not removing bridge module because bridges exist ($bridges)"
47         return 1
48     fi
49     action "removing bridge module" rmmod bridge || return 1
50
51     # Try loading openvswitch again.
52     action "Inserting openvswitch module" modprobe openvswitch
53 }
54
55 insert_mod_if_required () {
56     insert_openvswitch_mod_if_required || return 1
57 }
58
59 ovs_vsctl () {
60     ovs-vsctl --no-wait --timeout=5 "$@"
61 }
62
63 ovsdb_tool () {
64     ovsdb-tool -vconsole:off "$@"
65 }
66
67 create_db () {
68     action "Creating empty database $DB_FILE" ovsdb_tool create "$DB_FILE" "$DB_SCHEMA"
69 }
70
71 upgrade_db () {
72     schemaver=`ovsdb_tool schema-version "$DB_SCHEMA"`
73     if test ! -e "$DB_FILE"; then
74         log_warning_msg "$DB_FILE does not exist"
75         install -d -m 755 -o root -g root `dirname $DB_FILE`
76         create_db
77     elif test X"`ovsdb_tool needs-conversion "$DB_FILE" "$DB_SCHEMA"`" != Xno; then
78         # Back up the old version.
79         version=`ovsdb_tool db-version "$DB_FILE"`
80         cksum=`ovsdb_tool db-cksum "$DB_FILE" | awk '{print $1}'`
81         backup=$DB_FILE.backup$version-$cksum
82         action "Backing up database to $backup" cp "$DB_FILE" "$backup" || return 1
83
84         # Compact database.  This is important if the old schema did not enable
85         # garbage collection (i.e. if it did not have any tables with "isRoot":
86         # true) but the new schema does.  In that situation the old database
87         # may contain a transaction that creates a record followed by a
88         # transaction that creates the first use of the record.  Replaying that
89         # series of transactions against the new database schema (as "convert"
90         # does) would cause the record to be dropped by the first transaction,
91         # then the second transaction would cause a referential integrity
92         # failure (for a strong reference).
93         #
94         # Errors might occur on an Open vSwitch downgrade if ovsdb-tool doesn't
95         # understand some feature of the schema used in the OVSDB version that
96         # we're downgrading from, so we don't give up on error.
97         action "Compacting database" ovsdb_tool compact "$DB_FILE"
98
99         # Upgrade or downgrade schema.
100         if action "Converting database schema" ovsdb_tool convert "$DB_FILE" "$DB_SCHEMA"; then
101             :
102         else
103             log_warning_msg "Schema conversion failed, using empty database instead"
104             rm -f "$DB_FILE"
105             create_db
106         fi
107     fi
108 }
109
110 set_system_ids () {
111     set ovs_vsctl set Open_vSwitch .
112
113     OVS_VERSION=`ovs-vswitchd --version | sed 's/.*) //;1q'`
114     set "$@" ovs-version="$OVS_VERSION"
115
116     case $SYSTEM_ID in
117         random)
118             id_file=$etcdir/system-id.conf
119             uuid_file=$etcdir/install_uuid.conf
120             if test -e "$id_file"; then
121                 SYSTEM_ID=`cat "$id_file"`
122             elif test -e "$uuid_file"; then
123                 # Migrate from old file name.
124                 . "$uuid_file"
125                 SYSTEM_ID=$INSTALLATION_UUID
126                 echo "$SYSTEM_ID" > "$id_file"
127             elif SYSTEM_ID=`uuidgen`; then
128                 echo "$SYSTEM_ID" > "$id_file"
129             else
130                 log_failure_msg "missing uuidgen, could not generate system ID"
131             fi
132             ;;
133
134         '')
135             log_failure_msg "system ID not configured, please use --system-id"
136             ;;
137
138         *)
139             ;;
140     esac
141     set "$@" external-ids:system-id="\"$SYSTEM_ID\""
142
143     if test X"$SYSTEM_TYPE" != X; then
144         set "$@" system-type="\"$SYSTEM_TYPE\""
145     else
146         log_failure_msg "no default system type, please use --system-type"
147     fi
148
149     if test X"$SYSTEM_VERSION" != X; then
150         set "$@" system-version="\"$SYSTEM_VERSION\""
151     else
152         log_failure_msg "no default system version, please use --system-version"
153     fi
154
155     action "Configuring Open vSwitch system IDs" "$@" $extra_ids
156 }
157
158 check_force_cores () {
159     if test X"$FORCE_COREFILES" = Xyes; then
160         ulimit -Sc 67108864
161     fi
162 }
163
164 start_ovsdb () {
165     check_force_cores
166
167     if daemon_is_running ovsdb-server; then
168         log_success_msg "ovsdb-server is already running"
169     else
170         # Create initial database or upgrade database schema.
171         upgrade_db || return 1
172
173         # Start ovsdb-server.
174         set ovsdb-server "$DB_FILE"
175         for db in $EXTRA_DBS; do
176             case $db in
177                 /*) ;;
178                 *) db=$dbdir/$db ;;
179             esac
180
181             if test ! -f "$db"; then
182                 log_warning_msg "$db (from \$EXTRA_DBS) does not exist."
183             elif ovsdb-tool db-version "$db" >/dev/null; then
184                 set "$@" "$db"
185             else
186                 log_warning_msg "$db (from \$EXTRA_DBS) cannot be read as a database (see error message above)"
187             fi
188         done
189         set "$@" -vconsole:emer -vsyslog:err -vfile:info
190         set "$@" --remote=punix:"$DB_SOCK"
191         set "$@" --remote=db:Open_vSwitch,Open_vSwitch,manager_options
192         set "$@" --private-key=db:Open_vSwitch,SSL,private_key
193         set "$@" --certificate=db:Open_vSwitch,SSL,certificate
194         set "$@" --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert
195         start_daemon "$OVSDB_SERVER_PRIORITY" "$OVSDB_SERVER_WRAPPER" "$@" \
196             || return 1
197
198         # Initialize database settings.
199         ovs_vsctl -- init -- set Open_vSwitch . db-version="$schemaver" \
200             || return 1
201         set_system_ids || return 1
202         if test X"$DELETE_BRIDGES" = Xyes; then
203             for bridge in `ovs_vsctl list-br`; do
204         ovs_vsctl del-br $bridge
205             done
206         fi
207     fi
208 }
209
210 start_forwarding () {
211     check_force_cores
212
213     insert_mod_if_required || return 1
214
215     if daemon_is_running ovs-vswitchd; then
216         log_success_msg "ovs-vswitchd is already running"
217     else
218         # Increase the limit on the number of open file descriptors.
219         # On Linux, ovs-vswitchd needs about one file descriptor per
220         # switch port, so this allows a very large number of switch
221         # ports.
222         ulimit -n 5000
223
224             # Start ovs-vswitchd.
225             set ovs-vswitchd unix:"$DB_SOCK"
226             set "$@" -vconsole:emer -vsyslog:err -vfile:info
227             if test X"$MLOCKALL" != Xno; then
228                 set "$@" --mlockall
229             fi
230             start_daemon "$OVS_VSWITCHD_PRIORITY" "$OVS_VSWITCHD_WRAPPER" "$@"
231     fi
232 }
233
234 ## ---- ##
235 ## stop ##
236 ## ---- ##
237
238 stop_ovsdb () {
239     stop_daemon ovsdb-server
240 }
241
242 stop_forwarding () {
243     stop_daemon ovs-vswitchd
244 }
245
246 ## ----------------- ##
247 ## force-reload-kmod ##
248 ## ----------------- ##
249
250 internal_interfaces () {
251     # Outputs a list of internal interfaces:
252     #
253     #   - There is an internal interface for every bridge, whether it
254     #     has an Interface record or not and whether the Interface
255     #     record's 'type' is properly set or not.
256     #
257     #   - There is an internal interface for each Interface record whose
258     #     'type' is 'internal'.
259     #
260     # But ignore interfaces that don't really exist.
261     for d in `(ovs_vsctl --bare \
262                 -- --columns=name find Interface type=internal \
263                     -- list-br) | sort -u`
264     do
265         if test -e "/sys/class/net/$d"; then
266                 printf "%s " "$d"
267             fi
268     done
269 }
270
271 ovs_save () {
272     bridges=`ovs_vsctl -- --real list-br`
273     if [ -n "${bridges}" ] && \
274         "$datadir/scripts/ovs-save" "$1" ${bridges} > "$2"; then
275         chmod +x "$2"
276         return 0
277     fi
278     [ -z "${bridges}" ] && return 0
279 }
280
281 save_ofports_if_required () {
282     # Save ofports if we are upgrading from a pre-1.10 branch.
283     case `ovs-appctl version | sed 1q` in
284         "ovs-vswitchd (Open vSwitch) 1."[0-9].*)
285             action "Saving ofport values" ovs_save save-ofports \
286                 "${script_ofports}"
287             ;;
288         *)
289             ;;
290     esac
291 }
292
293 save_interfaces () {
294     "$datadir/scripts/ovs-save" save-interfaces ${ifaces} \
295         > "${script_interfaces}"
296 }
297
298 restore_ofports () {
299     [ -x "${script_ofports}" ] && \
300         action "Restoring ofport values" "${script_ofports}"
301 }
302
303 restore_flows () {
304     [ -x "${script_flows}" ] && \
305         action "Restoring saved flows" "${script_flows}"
306 }
307
308 restore_interfaces () {
309     [ ! -x "${script_interfaces}" ] && return 0
310     action "Restoring interface configuration" "${script_interfaces}"
311     rc=$?
312     if test $rc = 0; then
313         level=debug
314     else
315         level=err
316     fi
317     log="logger -p daemon.$level -t ovs-save"
318     $log "force-reload-kmod interface restore script exited with status $rc:"
319     $log -f "$script_interfaces"
320 }
321
322 init_restore_scripts () {
323     script_interfaces=`mktemp`
324     script_flows=`mktemp`
325     script_ofports=`mktemp`
326     trap 'rm -f "${script_interfaces}" "${script_flows}" "${script_ofports}"' 0
327 }
328
329 force_reload_kmod () {
330     ifaces=`internal_interfaces`
331     action "Detected internal interfaces: $ifaces" true
332
333     init_restore_scripts
334
335     action "Saving flows" ovs_save save-flows "${script_flows}"
336
337     save_ofports_if_required
338
339     # Restart the database first, since a large database may take a
340     # while to load, and we want to minimize forwarding disruption.
341     stop_ovsdb
342     start_ovsdb
343
344     # Restore of ofports should happen before vswitchd is restarted.
345     restore_ofports
346
347     stop_forwarding
348
349     if action "Saving interface configuration" save_interfaces; then
350         :
351     else
352         log_warning_msg "Failed to save configuration, not replacing kernel module"
353         start_forwarding
354         exit 1
355     fi
356     chmod +x "$script_interfaces"
357
358     for dp in `ovs-dpctl dump-dps`; do
359         action "Removing datapath: $dp" ovs-dpctl del-dp "$dp"
360     done
361
362     # try both old and new names in case this is post upgrade
363     if test -e /sys/module/openvswitch_mod; then
364         action "Removing openvswitch module" rmmod openvswitch_mod
365     elif test -e /sys/module/openvswitch; then
366         action "Removing openvswitch module" rmmod openvswitch
367     fi
368
369     start_forwarding
370
371     restore_flows
372
373     restore_interfaces
374
375     "$datadir/scripts/ovs-check-dead-ifs"
376 }
377
378 ## ------- ##
379 ## restart ##
380 ## ------- ##
381
382 restart () {
383     if daemon_is_running ovsdb-server && daemon_is_running ovs-vswitchd; then
384         script_flows=`mktemp`
385         trap 'rm -f "${script_flows}"' 0
386
387         action "Saving flows" ovs_save save-flows "${script_flows}" \
388             script_flows
389     fi
390
391     # Restart the database first, since a large database may take a
392     # while to load, and we want to minimize forwarding disruption.
393     stop_ovsdb
394     start_ovsdb
395
396     stop_forwarding
397     start_forwarding
398
399     # Restore the saved flows. Do not return error if restore fails.
400     restore_flows || true
401 }
402
403 ## --------------- ##
404 ## enable-protocol ##
405 ## --------------- ##
406
407 enable_protocol () {
408     # Translate the protocol name to a number, because "iptables -n -L" prints
409     # some protocols by name (despite the -n) and therefore we need to look for
410     # both forms.
411     #
412     # (iptables -S output is more uniform but old iptables doesn't have it.)
413     protonum=`grep "^$PROTOCOL[         ]" /etc/protocols | awk '{print $2}'`
414     if expr X"$protonum" : X'[0-9]\{1,\}$' > /dev/null; then :; else
415         log_failure_msg "unknown protocol $PROTOCOL"
416         return 1
417     fi
418
419     name=$PROTOCOL
420     match="(\$2 == \"$PROTOCOL\" || \$2 == $protonum)"
421     insert="iptables -I INPUT -p $PROTOCOL"
422     if test X"$DPORT" != X; then
423         name="$name to port $DPORT"
424         match="$match && /dpt:$DPORT/"
425         insert="$insert --dport $DPORT"
426     fi
427     if test X"$SPORT" != X; then
428         name="$name from port $SPORT"
429         match="$match && /spt:$SPORT/"
430         insert="$insert --sport $SPORT"
431     fi
432     insert="$insert -j ACCEPT"
433
434     if (iptables -n -L INPUT) >/dev/null 2>&1; then
435         if iptables -n -L INPUT | awk "$match { n++ } END { exit n == 0 }"
436         then
437             # There's already a rule for this protocol.  Don't override it.
438             log_success_msg "iptables already has a rule for $name, not explicitly enabling"
439         else
440             action "Enabling $name with iptables" $insert
441         fi
442     elif (iptables --version) >/dev/null 2>&1; then
443         action "cannot list iptables rules, not adding a rule for $name"
444     else
445         action "iptables binary not installed, not adding a rule for $name"
446     fi
447 }
448
449 ## ---- ##
450 ## main ##
451 ## ---- ##
452
453 set_defaults () {
454     SYSTEM_ID=
455
456     DELETE_BRIDGES=no
457
458     DAEMON_CWD=/
459     FORCE_COREFILES=yes
460     MLOCKALL=yes
461     OVSDB_SERVER_PRIORITY=-10
462     OVS_VSWITCHD_PRIORITY=-10
463     OVSDB_SERVER_WRAPPER=
464     OVS_VSWITCHD_WRAPPER=
465
466     DB_FILE=$dbdir/conf.db
467     DB_SOCK=$rundir/db.sock
468     DB_SCHEMA=$datadir/vswitch.ovsschema
469     EXTRA_DBS=
470
471     PROTOCOL=gre
472     DPORT=
473     SPORT=
474
475     type_file=$etcdir/system-type.conf
476     version_file=$etcdir/system-version.conf
477
478     if test -e "$type_file" ; then
479         SYSTEM_TYPE=`cat $type_file`
480         SYSTEM_VERSION=`cat $version_file`
481     elif (lsb_release --id) >/dev/null 2>&1; then
482         SYSTEM_TYPE=`lsb_release --id -s`
483         system_release=`lsb_release --release -s`
484         system_codename=`lsb_release --codename -s`
485         SYSTEM_VERSION="${system_release}-${system_codename}"
486     else
487         SYSTEM_TYPE=unknown
488         SYSTEM_VERSION=unknown
489     fi
490 }
491
492 usage () {
493     set_defaults
494     cat <<EOF
495 $0: controls Open vSwitch daemons
496 usage: $0 [OPTIONS] COMMAND
497
498 This program is intended to be invoked internally by Open vSwitch startup
499 scripts.  System administrators should not normally invoke it directly.
500
501 Commands:
502   start              start Open vSwitch daemons
503   stop               stop Open vSwitch daemons
504   restart            stop and start Open vSwitch daemons
505   status             check whether Open vSwitch daemons are running
506   version            print versions of Open vSwitch daemons
507   load-kmod          insert modules if not already present
508   force-reload-kmod  save OVS network device state, stop OVS, unload kernel
509                      module, reload kernel module, start OVS, restore state
510   enable-protocol    enable protocol specified in options with iptables
511   help               display this help message
512
513 One of the following options is required for "start", "restart" and "force-reload-kmod":
514   --system-id=UUID   set specific ID to uniquely identify this system
515   --system-id=random  use a random but persistent UUID to identify this system
516
517 Other important options for "start", "restart" and "force-reload-kmod":
518   --system-type=TYPE  set system type (e.g. "XenServer")
519   --system-version=VERSION  set system version (e.g. "5.6.100-39265p")
520   --external-id="key=value"
521                      add given key-value pair to Open_vSwitch external-ids
522   --delete-bridges   delete all bridges just before starting ovs-vswitchd
523
524 Less important options for "start", "restart" and "force-reload-kmod":
525   --daemon-cwd=DIR               set working dir for OVS daemons (default: $DAEMON_CWD)
526   --no-force-corefiles           do not force on core dumps for OVS daemons
527   --no-mlockall                  do not lock all of ovs-vswitchd into memory
528   --ovsdb-server-priority=NICE   set ovsdb-server's niceness (default: $OVSDB_SERVER_PRIORITY)
529   --ovs-vswitchd-priority=NICE   set ovs-vswitchd's niceness (default: $OVS_VSWITCHD_PRIORITY)
530
531 Debugging options for "start", "restart" and "force-reload-kmod":
532   --ovsdb-server-wrapper=WRAPPER
533   --ovs-vswitchd-wrapper=WRAPPER
534   --ovs-vswitchd-wrapper=WRAPPER
535      run specified daemon under WRAPPER (either 'valgrind' or 'strace')
536
537 File location options:
538   --db-file=FILE     database file name (default: $DB_FILE)
539   --db-sock=SOCKET   JSON-RPC socket name (default: $DB_SOCK)
540   --db-schema=FILE   database schema file name (default: $DB_SCHEMA)
541
542 Options for "enable-protocol":
543   --protocol=PROTOCOL  protocol to enable with iptables (default: gre)
544   --sport=PORT       source port to match (for tcp or udp protocol)
545   --dport=PORT       ddestination port to match (for tcp or udp protocol)
546
547 Other options:
548   -h, --help                  display this help message
549   -V, --version               display version information
550
551 Default directories with "configure" option and environment variable override:
552   logs: @LOGDIR@ (--with-logdir, OVS_LOGDIR)
553   pidfiles and sockets: @RUNDIR@ (--with-rundir, OVS_RUNDIR)
554   conf.db: @DBDIR@ (--with-dbdir, OVS_DBDIR)
555   system configuration: @sysconfdir@ (--sysconfdir, OVS_SYSCONFDIR)
556   data files: @pkgdatadir@ (--pkgdatadir, OVS_PKGDATADIR)
557   user binaries: @bindir@ (--bindir, OVS_BINDIR)
558   system binaries: @sbindir@ (--sbindir, OVS_SBINDIR)
559
560 Please report bugs to bugs@openvswitch.org (see REPORTING-BUGS for details).
561 EOF
562
563     exit 0
564 }
565
566 set_option () {
567     var=`echo "$option" | tr abcdefghijklmnopqrstuvwxyz- ABCDEFGHIJKLMNOPQRSTUVWXYZ_`
568     eval set=\${$var+yes}
569     eval old_value=\$$var
570     if test X$set = X || \
571         (test $type = bool && \
572         test X"$old_value" != Xno && test X"$old_value" != Xyes); then
573         echo >&2 "$0: unknown option \"$arg\" (use --help for help)"
574         return
575     fi
576     eval $var=\$value
577 }
578
579 daemons () {
580     echo ovsdb-server ovs-vswitchd
581 }
582
583 set_defaults
584 extra_ids=
585 command=
586 for arg
587 do
588     case $arg in
589         -h | --help)
590             usage
591             ;;
592         -V | --version)
593             echo "$0 (Open vSwitch) $VERSION"
594             exit 0
595             ;;
596         --external-id=*)
597             value=`expr X"$arg" : 'X[^=]*=\(.*\)'`
598             case $value in
599                 *=*)
600                     extra_ids="$extra_ids external-ids:$value"
601                     ;;
602                 *)
603                     echo >&2 "$0: --external-id argument not in the form \"key=value\""
604                     exit 1
605                     ;;
606             esac
607             ;;
608         --[a-z]*=*)
609             option=`expr X"$arg" : 'X--\([^=]*\)'`
610             value=`expr X"$arg" : 'X[^=]*=\(.*\)'`
611             type=string
612             set_option
613             ;;
614         --no-[a-z]*)
615             option=`expr X"$arg" : 'X--no-\(.*\)'`
616             value=no
617             type=bool
618             set_option
619             ;;
620         --[a-z]*)
621             option=`expr X"$arg" : 'X--\(.*\)'`
622             value=yes
623             type=bool
624             set_option
625             ;;
626         -*)
627             echo >&2 "$0: unknown option \"$arg\" (use --help for help)"
628             exit 1
629             ;;
630         *)
631             if test X"$command" = X; then
632                 command=$arg
633             else
634                 echo >&2 "$0: exactly one non-option argument required (use --help for help)"
635                 exit 1
636             fi
637             ;;
638     esac
639 done
640 case $command in
641     start)
642         start_ovsdb
643         start_forwarding
644         ;;
645     stop)
646         stop_forwarding
647         stop_ovsdb
648         ;;
649     restart)
650         restart
651         ;;
652     status)
653         rc=0
654         for daemon in `daemons`; do
655             daemon_status $daemon || rc=$?
656         done
657         exit $rc
658         ;;
659     version)
660         for daemon in `daemons`; do
661             $daemon --version
662         done
663         ;;
664     force-reload-kmod)
665             force_reload_kmod
666         ;;
667     load-kmod)
668         insert_mod_if_required
669         ;;
670     enable-protocol)
671         enable_protocol
672         ;;
673     help)
674         usage
675         ;;
676     '')
677         echo >&2 "$0: missing command name (use --help for help)"
678         exit 1
679         ;;
680     *)
681         echo >&2 "$0: unknown command \"$command\" (use --help for help)"
682         exit 1
683         ;;
684 esac