From 2e8a4c31abe39ce4443d046d86c595fd73351900 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 26 Apr 2010 14:18:32 -0700 Subject: [PATCH] xenserver: Gracefully refresh network UUIDs on pool join or leave. The vswitch database is supposed to maintain an up-to-date UUID for the system's networks in the Bridge table as external-ids:network-uuids. On XenServer systems, /opt/xensource/libexec/interface-reconfigure updates these fields as bridges are brought up and down. Most of the time, that is sufficient. However, this is one exception: when a XenServer host enters or leaves a pool, interface-reconfigure is not invoked, and neither is any other script. So this commit introduces a new, XenServer-specific daemon that monitors the XenServer's pool membership status and refreshes the network UUIDs (by invoking the refresh-network-uuids script) if it changes. Bug #2097. --- lib/vlog-modules.def | 1 + xenserver/automake.mk | 8 + xenserver/etc_init.d_openvswitch | 30 ++- xenserver/openvswitch-xen.spec | 3 + xenserver/ovs-xenserverd.8.in | 40 +++ xenserver/ovs-xenserverd.c | 228 ++++++++++++++++++ ...are_openvswitch_scripts_sysconfig.template | 8 + 7 files changed, 317 insertions(+), 1 deletion(-) create mode 100644 xenserver/ovs-xenserverd.8.in create mode 100644 xenserver/ovs-xenserverd.c diff --git a/lib/vlog-modules.def b/lib/vlog-modules.def index 6c2be7b3..5c836d6b 100644 --- a/lib/vlog-modules.def +++ b/lib/vlog-modules.def @@ -97,5 +97,6 @@ VLOG_MODULE(wcelim) VLOG_MODULE(vswitchd) VLOG_MODULE(vt) VLOG_MODULE(xenserver) +VLOG_MODULE(xenserverd) #undef VLOG_MODULE diff --git a/xenserver/automake.mk b/xenserver/automake.mk index b451bbb8..1340b0d1 100644 --- a/xenserver/automake.mk +++ b/xenserver/automake.mk @@ -25,3 +25,11 @@ EXTRA_DIST += \ xenserver/usr_sbin_xen-bugtool \ xenserver/usr_share_openvswitch_scripts_refresh-network-uuids \ xenserver/usr_share_openvswitch_scripts_sysconfig.template + +noinst_PROGRAMS += xenserver/ovs-xenserverd +xenserver_ovs_xenserverd_SOURCES = xenserver/ovs-xenserverd.c +xenserver_ovs_xenserverd_LDADD = lib/libopenvswitch.a + +man_MANS += xenserver/ovs-xenserverd.8 +DISTCLEANFILES += xenserver/ovs-xenserverd.8 +EXTRA_DIST += xenserver/ovs-xenserverd.8.in diff --git a/xenserver/etc_init.d_openvswitch b/xenserver/etc_init.d_openvswitch index 51b1d508..5adf3987 100755 --- a/xenserver/etc_init.d_openvswitch +++ b/xenserver/etc_init.d_openvswitch @@ -81,11 +81,16 @@ fi : ${BRCOMPATD_VALGRIND_LOG:=} : ${BRCOMPATD_VALGRIND_OPT:=} +# Config variables specific to ovs-xenserverd +: ${XENSERVERD_PIDFILE:=/var/run/openvswitch/ovs-xenserverd.pid} +: ${XENSERVERD_RUN_DIR:=/var/xen/openvswitch} + # Full paths to executables & modules ovsdb_server="/usr/sbin/ovsdb-server" ovsdb_tool="/usr/bin/ovsdb-tool" vswitchd="/usr/sbin/ovs-vswitchd" brcompatd="/usr/sbin/ovs-brcompatd" +xenserverd="/usr/sbin/ovs-xenserverd" dpctl="/usr/bin/ovs-dpctl" appctl="/usr/bin/ovs-appctl" ofctl="/usr/bin/ovs-ofctl" @@ -293,6 +298,17 @@ function start_brcompatd { fi } +function start_xenserverd { + if [ ! -d "$XENSERVERD_RUN_DIR" ]; then + install -d -m 755 -o root -g root "$XENSERVERD_RUN_DIR" + fi + cd "$XENSERVERD_RUN_DIR" + + install -d -m 755 -o root -g root `dirname $XENSERVERD_PIDFILE` + action "Starting ovs-xenserverd" "$xenserverd" --no-chdir --pidfile=$XENSERVERD_PIDFILE --detach $monitor_opt -vANY:CONSOLE:EMER + fi +} + function stop_ovsdb_server { if [ -f "$OVSDB_SERVER_PIDFILE" ]; then local pid=$(cat "$OVSDB_SERVER_PIDFILE") @@ -317,6 +333,14 @@ function stop_brcompatd { fi } +function stop_xenserverd { + if [ -f "$XENSERVERD_PIDFILE" ]; then + local pid=$(cat "$XENSERVERD_PIDFILE") + action "Killing ovs-xenserverd ($pid)" kill -TERM $pid + rm -f "$XENSERVERD_PIDFILE" + fi +} + function restart_approval { if test ! -t 0; then # Don't prompt if invoked non-interactively. @@ -391,10 +415,12 @@ function start { if [ "${ENABLE_BRCOMPAT}" = "y" ] ; then start_brcompatd fi + start_xenserverd touch /var/lock/subsys/openvswitch } function stop { + stop_xenserverd stop_brcompatd stop_vswitchd stop_ovsdb_server @@ -430,12 +456,14 @@ case "$1" in status -p "$OVSDB_SERVER_PIDFILE" ovsdb-server && status -p "$VSWITCHD_PIDFILE" ovs-vswitchd && (test "$ENABLE_BRCOMPAT" != "y" || - status -p "$BRCOMPATD_PIDFILE" ovs-brcompatd) + status -p "$BRCOMPATD_PIDFILE" ovs-brcompatd) && + status -p "$XENSERVERD_PIDFILE" ovs-xenserverd ;; version) /usr/sbin/ovsdb-server -V /usr/sbin/ovs-vswitchd -V /usr/sbin/ovs-brcompatd -V + /usr/sbin/ovs-xenserverd -V ;; help) printf "openvswitch [start|stop|restart|unload|status|version]\n" diff --git a/xenserver/openvswitch-xen.spec b/xenserver/openvswitch-xen.spec index c796a1be..bd9d27a4 100644 --- a/xenserver/openvswitch-xen.spec +++ b/xenserver/openvswitch-xen.spec @@ -79,6 +79,7 @@ install -m 755 xenserver/usr_sbin_xen-bugtool \ $RPM_BUILD_ROOT/usr/share/openvswitch/scripts/xen-bugtool install -m 755 xenserver/usr_sbin_brctl \ $RPM_BUILD_ROOT/usr/share/openvswitch/scripts/brctl +install -m 755 xenserver/ovs-xenserverd $RPM_BUILD_ROOT/usr/sbin/ install -m 755 xenserver/usr_share_openvswitch_scripts_sysconfig.template \ $RPM_BUILD_ROOT/usr/share/openvswitch/scripts/sysconfig.template install -d -m 755 $RPM_BUILD_ROOT/usr/lib/xsconsole/plugins-base @@ -351,6 +352,7 @@ fi /usr/share/openvswitch/vswitch.ovsschema /usr/sbin/ovs-brcompatd /usr/sbin/ovs-vswitchd +/usr/sbin/ovs-xenserverd /usr/sbin/ovsdb-server /usr/bin/ovs-appctl /usr/bin/ovs-dpctl @@ -369,6 +371,7 @@ fi /usr/share/man/man8/ovs-ofctl.8.gz /usr/share/man/man8/ovs-vsctl.8.gz /usr/share/man/man8/ovs-vswitchd.8.gz +/usr/share/man/man8/ovs-xenserverd.8.gz /var/lib/openvswitch %exclude /usr/lib/xsconsole/plugins-base/*.pyc %exclude /usr/lib/xsconsole/plugins-base/*.pyo diff --git a/xenserver/ovs-xenserverd.8.in b/xenserver/ovs-xenserverd.8.in new file mode 100644 index 00000000..87e76d8c --- /dev/null +++ b/xenserver/ovs-xenserverd.8.in @@ -0,0 +1,40 @@ +.\" -*- nroff -*- +.de IQ +. br +. ns +. IP "\\$1" +.. +.TH ovs\-xenserverd 8 "April 2010" "Open vSwitch" "Open vSwitch Manual" +.ds PN ovs\-xenserverd +. +.SH NAME +ovs\-xenserverd \- Open vSwitch daemon for XenServer-specific functionality +. +.SH SYNOPSIS +\fBovs\-xenserverd \fR[\fIoptions\fR] +. +.SH DESCRIPTION +A daemon that provides XenServer-specific functionality for Open +vSwitch. Currently, its only purpose is to ensure that network UUIDs +in the Open vSwitch database are kept up-to-date when the XenServer +host joins or leaves a pool. It does so by running +\fB@pkgdatadir@/scripts/refresh-network-uuids\fR. +.PP +\fBovs\-xenserverd\fR is useful only on Citrix XenServer hosts. +Running it on any other kind of host is harmless but not useful. +.SH OPTIONS +.so lib/daemon.man +.SS "Public Key Infrastructure Options" +.so lib/vlog.man +.so lib/common.man +. +.SH "RUNTIME MANAGEMENT COMMANDS" +\fBovs\-appctl\fR(8) can send commands to a running +\fBovs\-xenserverd\fR process. The currently supported commands are +described below. +.so lib/vlog-unixctl.man +.SH "SEE ALSO" +.BR ovs\-appctl (8), +.BR ovs\-vswitchd (8), +.BR ovsdb\-server (1), +\fBINSTALL.Linux\fR in the Open vSwitch distribution. diff --git a/xenserver/ovs-xenserverd.c b/xenserver/ovs-xenserverd.c new file mode 100644 index 00000000..72617ae1 --- /dev/null +++ b/xenserver/ovs-xenserverd.c @@ -0,0 +1,228 @@ +/* Copyright (c) 2010 Nicira Networks + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include +#include + +#include "command-line.h" +#include "daemon.h" +#include "dirs.h" +#include "poll-loop.h" +#include "process.h" +#include "socket-util.h" +#include "timeval.h" +#include "unixctl.h" +#include "util.h" + +#define THIS_MODULE VLM_xenserverd +#include "vlog.h" + +static void parse_options(int argc, char *argv[]); +static void usage(void) NO_RETURN; + +static void network_uuid_refresh_run(void); +static void network_uuid_refresh_wait(void); + +int +main(int argc, char *argv[]) +{ + struct unixctl_server *unixctl; + int retval; + + proctitle_init(argc, argv); + set_program_name(argv[0]); + time_init(); + vlog_init(); + parse_options(argc, argv); + signal(SIGPIPE, SIG_IGN); + process_init(); + + die_if_already_running(); + daemonize_start(); + + retval = unixctl_server_create(NULL, &unixctl); + if (retval) { + exit(EXIT_FAILURE); + } + + daemonize_complete(); + + for (;;) { + network_uuid_refresh_run(); + unixctl_server_run(unixctl); + + network_uuid_refresh_wait(); + unixctl_server_wait(unixctl); + + poll_block(); + } + + return 0; +} + + +static void +parse_options(int argc, char *argv[]) +{ + enum { + VLOG_OPTION_ENUMS + }; + static struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + DAEMON_LONG_OPTIONS, + VLOG_LONG_OPTIONS, + {0, 0, 0, 0}, + }; + char *short_options = long_options_to_short_options(long_options); + + for (;;) { + int c; + + c = getopt_long(argc, argv, short_options, long_options, NULL); + if (c == -1) { + break; + } + + switch (c) { + case 'H': + case 'h': + usage(); + + case 'V': + OVS_PRINT_VERSION(0, 0); + exit(EXIT_SUCCESS); + + VLOG_OPTION_HANDLERS + DAEMON_OPTION_HANDLERS + + case '?': + exit(EXIT_FAILURE); + + default: + abort(); + } + } + free(short_options); + + if (optind != argc) { + ovs_fatal(0, "no non-option arguments accepted"); + } +} + +static void +usage(void) +{ + printf("%s: Open vSwitch daemon for XenServer-specific functionality\n" + "usage: %s [OPTIONS]\n", program_name, program_name); + daemon_usage(); + vlog_usage(); + printf("\nOther options:\n" + " -h, --help display this help message\n" + " -V, --version display version information\n"); + exit(EXIT_SUCCESS); +} + +/* Network UUID refreshing. + * + * The vswitch database is supposed to maintain an up-to-date UUID for the + * system's networks in the Bridge table as external-ids:network-uuids. On + * XenServer systems, /opt/xensource/libexec/interface-reconfigure updates + * these fields as bridges are brought up and down. Most of the time, that is + * sufficient. However, this is one exception: when a XenServer host enters or + * leaves a pool, interface-reconfigure is not invoked, and neither is any + * other script. So we need to monitor the XenServer's pool membership status + * and refresh the network UUIDs (by invoking the refresh-network-uuids script) + * if it changes. + * + * This functionality should be harmless on non-XenServer systems, since they + * will have neither /etc/xensource/pool.conf nor refresh-network-uuids. + */ + +/* Timestamp of /etc/xensource/pool.conf, or zeros if it does not exist. */ +static struct timespec pool_conf_mtime; + +/* The executing instance of refresh-network-uuids, or NULL if none. */ +static struct process *refresh_script; + +static void +network_uuid_refresh_run(void) +{ + struct timespec new_mtime; + + /* If a script is running, don't do anything until it finishes. */ + if (refresh_script) { + char *s; + + if (!process_exited(refresh_script)) { + return; + } + + s = process_status_msg(process_status(refresh_script)); + VLOG_INFO("refresh-network-uuids exited, %s", s); + free(s); + + process_destroy(refresh_script); + refresh_script = NULL; + } + + /* Otherwise, check for a change in timestamp. + * + * (We will always detect a change in timestamp when we start up. That's + * good, since it means that the refresh-network-uuids script gets + * thoroughly tested and we can't miss pool changes that happen when + * ovs-vswitchd isn't running.) */ + get_mtime("/etc/xensource/pool.conf", &new_mtime); + if (new_mtime.tv_sec != pool_conf_mtime.tv_sec + || new_mtime.tv_nsec != pool_conf_mtime.tv_nsec) { + struct stat s; + char *argv[2]; + + argv[0] = xasprintf("%s/scripts/refresh-network-uuids", + ovs_pkgdatadir); + argv[1] = NULL; + + if (!stat(argv[0], &s)) { + int error = process_start(argv, NULL, 0, NULL, 0, &refresh_script); + if (error) { + VLOG_ERR("failed to refresh network UUIDs: %s could " + "not be started (%s)", argv[0], strerror(error)); + } else { + VLOG_INFO("refreshing network UUIDs: started %s", argv[0]); + } + } else { + VLOG_ERR("failed to refresh network UUIDs: could not stat %s (%s)", + argv[0], strerror(errno)); + } + + pool_conf_mtime = new_mtime; + free(argv[0]); + } +} + +void +network_uuid_refresh_wait(void) +{ + if (refresh_script) { + process_wait(refresh_script); + } else if (pool_conf_mtime.tv_sec) { + poll_timer_wait(1000); + } +} diff --git a/xenserver/usr_share_openvswitch_scripts_sysconfig.template b/xenserver/usr_share_openvswitch_scripts_sysconfig.template index c639df81..6492931b 100644 --- a/xenserver/usr_share_openvswitch_scripts_sysconfig.template +++ b/xenserver/usr_share_openvswitch_scripts_sysconfig.template @@ -236,3 +236,11 @@ # This option's value is honored only when BRCOMPATD_VALGRIND_LOG is # set to a nonempty string. # BRCOMPATD_VALGRIND_OPT="" + +# XENSERVERD_PIDFILE: File in which to store the pid of the running +# ovs-xenserved. +# XENSERVERD_PIDFILE=/var/run/openvswitch/ovs-xenserverd.pid + +# XENSERVERD_RUN_DIR: Set the directory in which ovs-xenserverd should be +# run. This mainly affects where core files will be placed. +# XENSERVERD_RUN_DIR=/var/xen/openvswitch -- 2.30.2