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