ovs-ctl.in: Restore ofport values across force-reload-kmod.
[sliver-openvswitch.git] / utilities / ovs-ctl.in
1 #! /bin/sh
2 # Copyright (C) 2009, 2010, 2011, 2012 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         # ovs-vswitchd needs 16 per datapath, plus a few extra, so this
220         # should allow for 256 (or more) bridges.
221         ulimit -n 5000
222
223             # Start ovs-vswitchd.
224             set ovs-vswitchd unix:"$DB_SOCK"
225             set "$@" -vconsole:emer -vsyslog:err -vfile:info
226             if test X"$MLOCKALL" != Xno; then
227                 set "$@" --mlockall
228             fi
229             start_daemon "$OVS_VSWITCHD_PRIORITY" "$OVS_VSWITCHD_WRAPPER" "$@"
230     fi
231 }
232
233 ## ---- ##
234 ## stop ##
235 ## ---- ##
236
237 stop_ovsdb () {
238     stop_daemon ovsdb-server
239 }
240
241 stop_forwarding () {
242     stop_daemon ovs-vswitchd
243 }
244
245 ## ----------------- ##
246 ## force-reload-kmod ##
247 ## ----------------- ##
248
249 internal_interfaces () {
250     # Outputs a list of internal interfaces:
251     #
252     #   - There is an internal interface for every bridge, whether it
253     #     has an Interface record or not and whether the Interface
254     #     record's 'type' is properly set or not.
255     #
256     #   - There is an internal interface for each Interface record whose
257     #     'type' is 'internal'.
258     #
259     # But ignore interfaces that don't really exist.
260     for d in `(ovs_vsctl --bare \
261                 -- --columns=name find Interface type=internal \
262                     -- list-br) | sort -u`
263     do
264         if test -e "/sys/class/net/$d"; then
265                 printf "%s " "$d"
266             fi
267     done
268 }
269
270 ovs_save () {
271     bridges=`ovs_vsctl -- --real list-br`
272     if [ -n "${bridges}" ] && \
273         "$datadir/scripts/ovs-save" "$1" ${bridges} > "$2"; then
274         chmod +x "$2"
275         return 0
276     fi
277     eval $3=""
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}" 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     [ -n "${script_ofports}" ] && \
300         action "Restoring ofport values" "${script_ofports}"
301 }
302
303 restore_flows () {
304     [ -n "${script_flows}" ] && \
305         action "Restoring saved flows" "${script_flows}"
306 }
307
308 force_reload_kmod () {
309     ifaces=`internal_interfaces`
310     action "Detected internal interfaces: $ifaces" true
311
312     script_interfaces=`mktemp`
313     script_flows=`mktemp`
314     script_ofports=`mktemp`
315     trap 'rm -f "${script_interfaces}" "${script_flows}" "${script_ofports}"' 0
316
317     action "Saving flows" ovs_save save-flows "${script_flows}" script_flows
318
319     save_ofports_if_required
320
321     # Restart the database first, since a large database may take a
322     # while to load, and we want to minimize forwarding disruption.
323     stop_ovsdb
324     start_ovsdb
325
326     # Restore of ofports should happen before vswitchd is restarted.
327     restore_ofports
328
329     stop_forwarding
330
331     if action "Saving interface configuration" save_interfaces; then
332         :
333     else
334         log_warning_msg "Failed to save configuration, not replacing kernel module"
335         start_forwarding
336         exit 1
337     fi
338     chmod +x "$script_interfaces"
339
340     for dp in `ovs-dpctl dump-dps`; do
341         action "Removing datapath: $dp" ovs-dpctl del-dp "$dp"
342     done
343
344     # try both old and new names in case this is post upgrade
345     if test -e /sys/module/openvswitch_mod; then
346         action "Removing openvswitch module" rmmod openvswitch_mod
347     elif test -e /sys/module/openvswitch; then
348         action "Removing openvswitch module" rmmod openvswitch
349     fi
350
351     start_forwarding
352
353     restore_flows
354
355     action "Restoring interface configuration" "$script_interfaces"
356     rc=$?
357     if test $rc = 0; then
358         level=debug
359     else
360         level=err
361     fi
362     log="logger -p daemon.$level -t ovs-save"
363     $log "force-reload-kmod interface restore script exited with status $rc:"
364     $log -f "$script_interfaces"
365
366     "$datadir/scripts/ovs-check-dead-ifs"
367 }
368
369 ## ------- ##
370 ## restart ##
371 ## ------- ##
372
373 restart () {
374     if daemon_is_running ovsdb-server && daemon_is_running ovs-vswitchd; then
375         script_flows=`mktemp`
376         trap 'rm -f "${script_flows}"' 0
377
378         action "Saving flows" ovs_save save-flows "${script_flows}" \
379             script_flows
380     fi
381
382     # Restart the database first, since a large database may take a
383     # while to load, and we want to minimize forwarding disruption.
384     stop_ovsdb
385     start_ovsdb
386
387     stop_forwarding
388     start_forwarding
389
390     # Restore the saved flows. Do not return error if restore fails.
391     restore_flows || true
392 }
393
394 ## --------------- ##
395 ## enable-protocol ##
396 ## --------------- ##
397
398 enable_protocol () {
399     # Translate the protocol name to a number, because "iptables -n -L" prints
400     # some protocols by name (despite the -n) and therefore we need to look for
401     # both forms.
402     #
403     # (iptables -S output is more uniform but old iptables doesn't have it.)
404     protonum=`grep "^$PROTOCOL[         ]" /etc/protocols | awk '{print $2}'`
405     if expr X"$protonum" : X'[0-9]\{1,\}$' > /dev/null; then :; else
406         log_failure_msg "unknown protocol $PROTOCOL"
407         return 1
408     fi
409
410     name=$PROTOCOL
411     match="(\$2 == \"$PROTOCOL\" || \$2 == $protonum)"
412     insert="iptables -I INPUT -p $PROTOCOL"
413     if test X"$DPORT" != X; then
414         name="$name to port $DPORT"
415         match="$match && /dpt:$DPORT/"
416         insert="$insert --dport $DPORT"
417     fi
418     if test X"$SPORT" != X; then
419         name="$name from port $SPORT"
420         match="$match && /spt:$SPORT/"
421         insert="$insert --sport $SPORT"
422     fi
423     insert="$insert -j ACCEPT"
424
425     if (iptables -n -L INPUT) >/dev/null 2>&1; then
426         if iptables -n -L INPUT | awk "$match { n++ } END { exit n == 0 }"
427         then
428             # There's already a rule for this protocol.  Don't override it.
429             log_success_msg "iptables already has a rule for $name, not explicitly enabling"
430         else
431             action "Enabling $name with iptables" $insert
432         fi
433     elif (iptables --version) >/dev/null 2>&1; then
434         action "cannot list iptables rules, not adding a rule for $name"
435     else
436         action "iptables binary not installed, not adding a rule for $name"
437     fi
438 }
439
440 ## ---- ##
441 ## main ##
442 ## ---- ##
443
444 set_defaults () {
445     SYSTEM_ID=
446
447     DELETE_BRIDGES=no
448
449     DAEMON_CWD=/
450     FORCE_COREFILES=yes
451     MLOCKALL=yes
452     OVSDB_SERVER_PRIORITY=-10
453     OVS_VSWITCHD_PRIORITY=-10
454     OVSDB_SERVER_WRAPPER=
455     OVS_VSWITCHD_WRAPPER=
456
457     DB_FILE=$dbdir/conf.db
458     DB_SOCK=$rundir/db.sock
459     DB_SCHEMA=$datadir/vswitch.ovsschema
460     EXTRA_DBS=
461
462     PROTOCOL=gre
463     DPORT=
464     SPORT=
465
466     type_file=$etcdir/system-type.conf
467     version_file=$etcdir/system-version.conf
468
469     if test -e "$type_file" ; then
470         SYSTEM_TYPE=`cat $type_file`
471         SYSTEM_VERSION=`cat $version_file`
472     elif (lsb_release --id) >/dev/null 2>&1; then
473         SYSTEM_TYPE=`lsb_release --id -s`
474         system_release=`lsb_release --release -s`
475         system_codename=`lsb_release --codename -s`
476         SYSTEM_VERSION="${system_release}-${system_codename}"
477     else
478         SYSTEM_TYPE=unknown
479         SYSTEM_VERSION=unknown
480     fi
481 }
482
483 usage () {
484     set_defaults
485     cat <<EOF
486 $0: controls Open vSwitch daemons
487 usage: $0 [OPTIONS] COMMAND
488
489 This program is intended to be invoked internally by Open vSwitch startup
490 scripts.  System administrators should not normally invoke it directly.
491
492 Commands:
493   start              start Open vSwitch daemons
494   stop               stop Open vSwitch daemons
495   restart            stop and start Open vSwitch daemons
496   status             check whether Open vSwitch daemons are running
497   version            print versions of Open vSwitch daemons
498   load-kmod          insert modules if not already present
499   force-reload-kmod  save OVS network device state, stop OVS, unload kernel
500                      module, reload kernel module, start OVS, restore state
501   enable-protocol    enable protocol specified in options with iptables
502   help               display this help message
503
504 One of the following options is required for "start", "restart" and "force-reload-kmod":
505   --system-id=UUID   set specific ID to uniquely identify this system
506   --system-id=random  use a random but persistent UUID to identify this system
507
508 Other important options for "start", "restart" and "force-reload-kmod":
509   --system-type=TYPE  set system type (e.g. "XenServer")
510   --system-version=VERSION  set system version (e.g. "5.6.100-39265p")
511   --external-id="key=value"
512                      add given key-value pair to Open_vSwitch external-ids
513   --delete-bridges   delete all bridges just before starting ovs-vswitchd
514
515 Less important options for "start", "restart" and "force-reload-kmod":
516   --daemon-cwd=DIR               set working dir for OVS daemons (default: $DAEMON_CWD)
517   --no-force-corefiles           do not force on core dumps for OVS daemons
518   --no-mlockall                  do not lock all of ovs-vswitchd into memory
519   --ovsdb-server-priority=NICE   set ovsdb-server's niceness (default: $OVSDB_SERVER_PRIORITY)
520   --ovs-vswitchd-priority=NICE   set ovs-vswitchd's niceness (default: $OVS_VSWITCHD_PRIORITY)
521
522 Debugging options for "start", "restart" and "force-reload-kmod":
523   --ovsdb-server-wrapper=WRAPPER
524   --ovs-vswitchd-wrapper=WRAPPER
525   --ovs-vswitchd-wrapper=WRAPPER
526      run specified daemon under WRAPPER (either 'valgrind' or 'strace')
527
528 File location options:
529   --db-file=FILE     database file name (default: $DB_FILE)
530   --db-sock=SOCKET   JSON-RPC socket name (default: $DB_SOCK)
531   --db-schema=FILE   database schema file name (default: $DB_SCHEMA)
532
533 Options for "enable-protocol":
534   --protocol=PROTOCOL  protocol to enable with iptables (default: gre)
535   --sport=PORT       source port to match (for tcp or udp protocol)
536   --dport=PORT       ddestination port to match (for tcp or udp protocol)
537
538 Other options:
539   -h, --help                  display this help message
540   -V, --version               display version information
541
542 Default directories with "configure" option and environment variable override:
543   logs: @LOGDIR@ (--with-logdir, OVS_LOGDIR)
544   pidfiles and sockets: @RUNDIR@ (--with-rundir, OVS_RUNDIR)
545   conf.db: @DBDIR@ (--with-dbdir, OVS_DBDIR)
546   system configuration: @sysconfdir@ (--sysconfdir, OVS_SYSCONFDIR)
547   data files: @pkgdatadir@ (--pkgdatadir, OVS_PKGDATADIR)
548   user binaries: @bindir@ (--bindir, OVS_BINDIR)
549   system binaries: @sbindir@ (--sbindir, OVS_SBINDIR)
550
551 Please report bugs to bugs@openvswitch.org (see REPORTING-BUGS for details).
552 EOF
553
554     exit 0
555 }
556
557 set_option () {
558     var=`echo "$option" | tr abcdefghijklmnopqrstuvwxyz- ABCDEFGHIJKLMNOPQRSTUVWXYZ_`
559     eval set=\${$var+yes}
560     eval old_value=\$$var
561     if test X$set = X || \
562         (test $type = bool && \
563         test X"$old_value" != Xno && test X"$old_value" != Xyes); then
564         echo >&2 "$0: unknown option \"$arg\" (use --help for help)"
565         return
566     fi
567     eval $var=\$value
568 }
569
570 daemons () {
571     echo ovsdb-server ovs-vswitchd
572 }
573
574 set_defaults
575 extra_ids=
576 command=
577 for arg
578 do
579     case $arg in
580         -h | --help)
581             usage
582             ;;
583         -V | --version)
584             echo "$0 (Open vSwitch) $VERSION"
585             exit 0
586             ;;
587         --external-id=*)
588             value=`expr X"$arg" : 'X[^=]*=\(.*\)'`
589             case $value in
590                 *=*)
591                     extra_ids="$extra_ids external-ids:$value"
592                     ;;
593                 *)
594                     echo >&2 "$0: --external-id argument not in the form \"key=value\""
595                     exit 1
596                     ;;
597             esac
598             ;;
599         --[a-z]*=*)
600             option=`expr X"$arg" : 'X--\([^=]*\)'`
601             value=`expr X"$arg" : 'X[^=]*=\(.*\)'`
602             type=string
603             set_option
604             ;;
605         --no-[a-z]*)
606             option=`expr X"$arg" : 'X--no-\(.*\)'`
607             value=no
608             type=bool
609             set_option
610             ;;
611         --[a-z]*)
612             option=`expr X"$arg" : 'X--\(.*\)'`
613             value=yes
614             type=bool
615             set_option
616             ;;
617         -*)
618             echo >&2 "$0: unknown option \"$arg\" (use --help for help)"
619             exit 1
620             ;;
621         *)
622             if test X"$command" = X; then
623                 command=$arg
624             else
625                 echo >&2 "$0: exactly one non-option argument required (use --help for help)"
626                 exit 1
627             fi
628             ;;
629     esac
630 done
631 case $command in
632     start)
633         start_ovsdb
634         start_forwarding
635         ;;
636     stop)
637         stop_forwarding
638         stop_ovsdb
639         ;;
640     restart)
641         restart
642         ;;
643     status)
644         rc=0
645         for daemon in `daemons`; do
646             daemon_status $daemon || rc=$?
647         done
648         exit $rc
649         ;;
650     version)
651         for daemon in `daemons`; do
652             $daemon --version
653         done
654         ;;
655     force-reload-kmod)
656             force_reload_kmod
657         ;;
658     load-kmod)
659         insert_mod_if_required
660         ;;
661     enable-protocol)
662         enable_protocol
663         ;;
664     help)
665         usage
666         ;;
667     '')
668         echo >&2 "$0: missing command name (use --help for help)"
669         exit 1
670         ;;
671     *)
672         echo >&2 "$0: unknown command \"$command\" (use --help for help)"
673         exit 1
674         ;;
675 esac