int
cfg_lock(uint8_t *cookie, int timeout)
{
- long long int start = time_msec();
+ long long int start;
long long int elapsed = 0;
int fd;
uint8_t curr_cookie[CFG_COOKIE_LEN];
assert(lock_fd < 0);
COVERAGE_INC(cfg_lock);
+
+ time_refresh();
+ start = time_msec();
for (;;) {
int error;
return rc->last_connected;
}
+/* Returns the time at which the last OpenFlow message was received by 'rc'.
+ * If no packets have been received on 'rc', returns the time at which 'rc'
+ * was created. */
+time_t
+rconn_get_last_received(const struct rconn *rc)
+{
+ return rc->last_received;
+}
+
/* Returns the time at which 'rc' was created. */
time_t
rconn_get_creation_time(const struct rconn *rc)
unsigned int rconn_get_attempted_connections(const struct rconn *);
unsigned int rconn_get_successful_connections(const struct rconn *);
time_t rconn_get_last_connection(const struct rconn *);
+time_t rconn_get_last_received(const struct rconn *);
time_t rconn_get_creation_time(const struct rconn *);
unsigned long int rconn_get_total_time_connected(const struct rconn *);
int rconn_get_backoff(const struct rconn *);
status_reply_put(sr, "name=%s", rconn_get_name(rconn));
status_reply_put(sr, "state=%s", rconn_get_state(rconn));
status_reply_put(sr, "backoff=%d", rconn_get_backoff(rconn));
+ status_reply_put(sr, "probe-interval=%d", rconn_get_probe_interval(rconn));
status_reply_put(sr, "is-connected=%s",
rconn_is_connected(rconn) ? "true" : "false");
status_reply_put(sr, "sent-msgs=%u", rconn_packets_sent(rconn));
rconn_get_successful_connections(rconn));
status_reply_put(sr, "last-connection=%ld",
(long int) (now - rconn_get_last_connection(rconn)));
+ status_reply_put(sr, "last-received=%ld",
+ (long int) (now - rconn_get_last_received(rconn)));
status_reply_put(sr, "time-connected=%lu",
rconn_get_total_time_connected(rconn));
status_reply_put(sr, "state-elapsed=%u", rconn_get_state_elapsed(rconn));
#include <strings.h>
#include <sys/stat.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include <unistd.h>
#include "bitmap.h"
#include "cfg.h"
static char *private_key_file;
static char *certificate_file;
static char *cacert_file;
+ struct stat s;
if (config_string_change("ssl.private-key", &private_key_file)) {
vconn_ssl_set_private_key_file(private_key_file);
vconn_ssl_set_certificate_file(certificate_file);
}
- if (config_string_change("ssl.ca-cert", &cacert_file)) {
+ /* We assume that even if the filename hasn't changed, if the CA cert
+ * file has been removed, that we want to move back into
+ * boot-strapping mode. This opens a small security hole, because
+ * the old certificate will still be trusted until vSwitch is
+ * restarted. We may want to address this in vconn's SSL library. */
+ if (config_string_change("ssl.ca-cert", &cacert_file)
+ || (stat(cacert_file, &s) && errno == ENOENT)) {
vconn_ssl_set_ca_cert_file(cacert_file,
cfg_get_bool(0, "ssl.bootstrap-ca-cert"));
}
|| !strcmp(fail_mode, "open")));
probe = cfg_get_int(0, "%s.inactivity-probe", pfx);
- ofproto_set_probe_interval(br->ofproto,
- probe ? probe : cfg_get_int(0, "mgmt.inactivity-probe"));
+ if (probe < 5) {
+ probe = cfg_get_int(0, "mgmt.inactivity-probe");
+ if (probe < 5) {
+ probe = 15;
+ }
+ }
+ ofproto_set_probe_interval(br->ofproto, probe);
max_backoff = cfg_get_int(0, "%s.max-backoff", pfx);
if (!max_backoff) {
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/types.h>
#include "bridge.h"
#include "cfg.h"
static struct svec mgmt_cfg;
static uint8_t cfg_cookie[CFG_COOKIE_LEN];
+static bool need_reconfigure = false;
static struct rconn *mgmt_rconn;
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
static struct svec capabilities;
static char *private_key_file;
static char *certificate_file;
static char *cacert_file;
+ struct stat s;
/* XXX SSL should be configurable separate from the bridges.
* XXX should be possible to de-configure SSL. */
vconn_ssl_set_certificate_file(certificate_file);
}
- if (config_string_change("ssl.ca-cert", &cacert_file)) {
+ /* We assume that even if the filename hasn't changed, if the CA cert
+ * file has been removed, that we want to move back into
+ * boot-strapping mode. This opens a small security hole, because
+ * the old certificate will still be trusted until vSwitch is
+ * restarted. We may want to address this in vconn's SSL library. */
+ if (config_string_change("ssl.ca-cert", &cacert_file)
+ || (stat(cacert_file, &s) && errno == ENOENT)) {
vconn_ssl_set_ca_cert_file(cacert_file,
cfg_get_bool(0, "ssl.bootstrap-ca-cert"));
}
int retval;
if (!cfg_has_section("mgmt")) {
+ svec_clear(&mgmt_cfg);
if (mgmt_rconn) {
rconn_destroy(mgmt_rconn);
mgmt_rconn = NULL;
* connection settings may have changed. */
send_config_update_ack(xid, true);
- reconfigure();
-
+ need_reconfigure = true;
return 0;
}
return handler(xid, msg);
}
-void
+bool
mgmt_run(void)
{
int i;
if (!mgmt_rconn) {
- return;
+ return false;
}
+ need_reconfigure = false;
rconn_run(mgmt_rconn);
/* Do some processing, but cap it at a reasonable amount so that
VLOG_WARN_RL(&rl, "received too-short OpenFlow message");
}
}
+
+ return need_reconfigure;
}
void
void mgmt_init(void);
void mgmt_reconfigure(void);
-void mgmt_run(void);
+bool mgmt_run(void);
void mgmt_wait(void);
uint64_t mgmt_get_mgmt_id(void);
error = netdev_nodev_get_flags(iface_name, &flags);
if (error == ENODEV) {
- VLOG_DBG_RL(&rl, "removing dead interface %s from %s",
- iface_name, br_name);
+ VLOG_INFO_RL(&rl, "removing dead interface %s from %s",
+ iface_name, br_name);
svec_add(&delete, iface_name);
} else if (error) {
- VLOG_DBG_RL(&rl, "unknown error %d on interface %s from %s",
- error, iface_name, br_name);
+ VLOG_INFO_RL(&rl, "unknown error %d on interface %s from %s",
+ error, iface_name, br_name);
}
}
svec_destroy(&ifaces);
* context, since ovs-vswitchd.conf may cause vswitchd to create or destroy
* network devices based on iface.*.internal settings.
*
- * XXX may want to move this to lib/netdev. */
+ * XXX may want to move this to lib/netdev.
+ *
+ * XXX why not just use netdev_nodev_get_flags() or similar function? */
static bool
netdev_exists(const char *name)
{
char br_name[IFNAMSIZ];
uint32_t br_idx = nl_attr_get_u32(attrs[IFLA_MASTER]);
struct svec ports;
+ enum netdev_flags flags;
if (!if_indextoname(br_idx, br_name)) {
ofpbuf_delete(buf);
return;
}
- svec_init(&ports);
- cfg_get_all_keys(&ports, "bridge.%s.port", br_name);
- svec_sort(&ports);
- if (svec_contains(&ports, port_name)) {
- del_port(br_name, port_name);
- rewrite_and_reload_config();
+ if (netdev_nodev_get_flags(port_name, &flags) == ENODEV) {
+ /* Network device is really gone. */
+ VLOG_INFO("network device %s destroyed, "
+ "removing from bridge %s", port_name, br_name);
+ svec_init(&ports);
+ cfg_get_all_keys(&ports, "bridge.%s.port", br_name);
+ svec_sort(&ports);
+ if (svec_contains(&ports, port_name)) {
+ del_port(br_name, port_name);
+ rewrite_and_reload_config();
+ }
+ } else {
+ /* A network device by that name exists even though the kernel
+ * told us it had disappeared. Probably, what happened was
+ * this:
+ *
+ * 1. Device destroyed.
+ * 2. Notification sent to us.
+ * 3. New device created with same name as old one.
+ * 4. ovs-brcompatd notified, removes device from bridge.
+ *
+ * There's no a priori reason that in this situation that the
+ * new device with the same name should remain in the bridge;
+ * on the contrary, that would be unexpected. *But* there is
+ * one important situation where, if we do this, bad things
+ * happen. This is the case of XenServer Tools version 5.0.0,
+ * which on boot of a Windows VM cause something like this to
+ * happen on the Xen host:
+ *
+ * i. Create tap1.0 and vif1.0.
+ * ii. Delete tap1.0.
+ * iii. Delete vif1.0.
+ * iv. Re-create vif1.0.
+ *
+ * (XenServer Tools 5.5.0 does not exhibit this behavior, and
+ * neither does a VM without Tools installed at all.@.)
+ *
+ * Steps iii and iv happen within a few seconds of each other.
+ * Step iv causes /etc/xensource/scripts/vif to run, which in
+ * turn calls ovs-cfg-mod to add the new device to the bridge.
+ * If step iv happens after step 4 (in our first list of
+ * steps), then all is well, but if it happens between 3 and 4
+ * (which can easily happen if ovs-brcompatd has to wait to
+ * lock the configuration file), then we will remove the new
+ * incarnation from the bridge instead of the old one!
+ *
+ * So, to avoid this problem, we do nothing here. This is
+ * strictly incorrect except for this one particular case, and
+ * perhaps that will bite us someday. If that happens, then we
+ * will have to somehow track network devices by ifindex, since
+ * a new device will have a new ifindex even if it has the same
+ * name as an old device.
+ */
+ VLOG_INFO("kernel reported network device %s removed but "
+ "a device by that name exists (XS Tools 5.0.0?)",
+ port_name);
}
cfg_unlock();
}
vlog_reopen_log_file();
reconfigure();
}
- mgmt_run();
+ if (mgmt_run()) {
+ need_reconfigure = true;
+ }
if (bridge_run()) {
need_reconfigure = true;
}
BRCOMPATD_PRIORITY="${BRCOMPATD_PRIORITY:--5}"
BRCOMPATD_LOGFILE="${BRCOMPATD_LOGFILE:-/var/log/ovs-brcompatd.log}"
BRCOMPATD_FILE_LOGLEVEL="${BRCOMPATD_FILE_LOGLEVEL:-}"
-BRCOMPATD_SYSLOG_LOGLEVEL="${BRCOMPATD_SYSLOG_LOGLEVEL:-WARN}"
+BRCOMPATD_SYSLOG_LOGLEVEL="${BRCOMPATD_SYSLOG_LOGLEVEL:-INFO}"
BRCOMPATD_MEMLEAK_LOGFILE="${BRCOMPATD_MEMLEAK_LOGFILE:-}"
BRCOMPATD_STRACE_LOG="${BRCOMPATD_STRACE_LOG:-}"
BRCOMPATD_STRACE_OPT="${BRCOMPATD_STRACE_OPT:-}"
import XenAPIPlugin
import XenAPI
+import os
import subprocess
cfg_mod="/root/vswitch/bin/ovs-cfg-mod"
vswitchd_cfg_filename="/etc/ovs-vswitchd.conf"
+cacert_filename="/etc/ovs-vswitchd.cacert"
+
+# Delete the CA certificate, so that we go back to boot-strapping mode
+def delete_cacert():
+ try:
+ os.remove(cacert_filename)
+ except OSError:
+ # Ignore error if file doesn't exist
+ pass
def update(session, args):
pools = session.xenapi.pool.get_all()
currentController = vswitchCurrentController()
if controller == "" and currentController != "":
log.debug("Removing controller configuration.")
+ delete_cacert()
removeControllerCfg()
return "Successfully removed controller config"
elif controller != currentController:
log.debug("Setting controller to: %s" % (controller))
else:
log.debug("Changing controller from %s to %s" % (currentController, controller))
+ delete_cacert()
setControllerCfg(controller)
return "Successfully set controller to " + controller
else:
xenstore-rm "${HOTPLUG}/hotplug"
vif=vif${DOMID}.${DEVID}
logger -t scripts-vif "${vif} has been removed"
- $cfg_mod -vANY:console:emer -F /etc/ovs-vswitchd.conf \
- --del-match="bridge.*.port=${vif}" \
+ $cfg_mod -vANY:console:emer -F /etc/ovs-vswitchd.conf \
+ --del-match="bridge.*.port=${vif}" \
--del-match="vlan.${vif}.[!0-9]*" \
--del-match="port.${vif}.[!0-9]*" -c
+ $service vswitch reload
;;
esac
logging.basicConfig(filename="/var/log/vswitch-xsplugin.log", level=logging.DEBUG)
import os
+import socket
import subprocess
cfg_mod="/root/vswitch/bin/ovs-cfg-mod"
self.hostsInPool = 0
self.hostsUpdated = 0
- self.controller = data.GetPoolForThisHost().get("other_config", {}).get("vSwitchController", "")
+ pool = data.GetPoolForThisHost()
+ if pool is not None:
+ self.controller = pool.get("other_config", {}).get("vSwitchController", "")
+ else:
+ self.controller = ""
choiceDefs = [
ChoiceDef(Lang("Set pool-wide controller"),
inputValues = pane.GetFieldValues()
self.controller = inputValues['address']
Layout.Inst().PopDialogue()
+
+ # Make sure the controller is specified as a valid dotted quad
+ try:
+ socket.inet_aton(self.controller)
+ except socket.error:
+ Layout.Inst().PushDialogue(InfoDialogue(Lang("Please enter in dotted quad format")))
+ return True
+
Layout.Inst().TransientBanner(Lang("Setting controller..."))
try:
self.SetController(self.controller)
inPane.AddStatusField(Lang("Version", 20), versionStr)
inPane.NewLine()
- dbController = data.GetPoolForThisHost().get("other_config", {}).get("vSwitchController", "")
+
+ pool = data.GetPoolForThisHost()
+ if pool is not None:
+ dbController = pool.get("other_config", {}).get("vSwitchController", "")
+ else:
+ dbController = ""
+
if dbController == "":
dbController = Lang("<None>")
inPane.AddStatusField(Lang("Controller (config)", 20), dbController)
$RPM_BUILD_ROOT%{_prefix}/scripts/vif
install -m 755 xenserver/root_vswitch_scripts_dump-vif-details \
$RPM_BUILD_ROOT%{_prefix}/scripts/dump-vif-details
-install -m 755 \
+install -m 644 \
xenserver/usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py \
$RPM_BUILD_ROOT%{_prefix}/scripts/XSFeatureVSwitch.py