diff options
Diffstat (limited to 'src/devices/team')
| -rw-r--r-- | src/devices/team/Makefile.in | 30 | ||||
| -rw-r--r-- | src/devices/team/nm-device-team.c | 333 |
2 files changed, 226 insertions, 137 deletions
diff --git a/src/devices/team/Makefile.in b/src/devices/team/Makefile.in index 4ee30e66..29ad0598 100644 --- a/src/devices/team/Makefile.in +++ b/src/devices/team/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.13.4 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -15,7 +15,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -81,8 +91,6 @@ host_triplet = @host@ @WITH_TEAMDCTL_TRUE@am__append_1 = ${LIBTEAMDCTL_CFLAGS} @WITH_TEAMDCTL_TRUE@am__append_2 = $(LIBTEAMDCTL_LIBS) subdir = src/devices/team -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/build-aux/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/compiler_warnings.m4 \ @@ -99,6 +107,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -211,6 +220,8 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/build-aux/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ @@ -237,7 +248,6 @@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ -DATADIRNAME = @DATADIRNAME@ DBUS_CFLAGS = @DBUS_CFLAGS@ DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@ DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@ @@ -272,6 +282,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ GNUTLS_LIBS = @GNUTLS_LIBS@ GREP = @GREP@ GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@ GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ GTKDOC_MKPDF = @GTKDOC_MKPDF@ @@ -523,7 +534,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/team/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/devices/team/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -595,14 +605,14 @@ distclean-compile: @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -830,6 +840,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-pkglibLTLIBRARIES +.PRECIOUS: Makefile + include $(GLIB_MAKEFILE) @GNOME_CODE_COVERAGE_RULES@ diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c index 16f1fcc2..49202c36 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -41,6 +41,7 @@ #include "nm-team-enum-types.h" #include "nm-posix-signals.h" #include "nm-core-internal.h" +#include "gsystem-local-alloc.h" #include "nm-device-team-glue.h" @@ -51,8 +52,6 @@ G_DEFINE_TYPE (NMDeviceTeam, nm_device_team, NM_TYPE_DEVICE) #define NM_DEVICE_TEAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_TEAM, NMDeviceTeamPrivate)) -static gboolean teamd_start (NMDevice *device, NMSettingTeam *s_team); - typedef struct { struct teamdctl *tdc; GPid teamd_pid; @@ -68,6 +67,8 @@ enum { LAST_PROP }; +static gboolean teamd_start (NMDevice *device, NMSettingTeam *s_team); + /******************************************************************/ static guint32 @@ -77,7 +78,7 @@ get_generic_capabilities (NMDevice *device) } static gboolean -is_available (NMDevice *device) +is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) { if (NM_DEVICE_GET_CLASS (device)->is_up) return NM_DEVICE_GET_CLASS (device)->is_up (device); @@ -87,6 +88,7 @@ is_available (NMDevice *device) static gboolean check_connection_available (NMDevice *device, NMConnection *connection, + NMDeviceCheckConAvailableFlags flags, const char *specific_object) { /* Connections are always available because the carrier state is determined @@ -171,6 +173,7 @@ update_connection (NMDevice *device, NMConnection *connection) { NMDeviceTeam *self = NM_DEVICE_TEAM (device); NMSettingTeam *s_team = nm_connection_get_setting_team (connection); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); if (!s_team) { s_team = (NMSettingTeam *) nm_setting_team_new (); @@ -178,8 +181,7 @@ update_connection (NMDevice *device, NMConnection *connection) } g_object_set (G_OBJECT (s_team), NM_SETTING_TEAM_CONFIG, NULL, NULL); - teamd_start (device, s_team); - if (NM_DEVICE_TEAM_GET_PRIVATE (device)->teamd_pid > 0 && ensure_teamd_connection (device)) { + if (priv->tdc) { const char *config = NULL; int err; @@ -261,49 +263,30 @@ master_update_slave_connection (NMDevice *self, /******************************************************************/ static void -teamd_timeout_remove (NMDevice *device) +teamd_cleanup (NMDevice *device, gboolean free_tdc) { NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (device); - if (priv->teamd_timeout) { - g_source_remove (priv->teamd_timeout); - priv->teamd_timeout = 0; - } -} - -static void -teamd_cleanup (NMDevice *device, gboolean device_state_failed) -{ - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (device); - - if (priv->teamd_dbus_watch) { - g_bus_unwatch_name (priv->teamd_dbus_watch); - priv->teamd_dbus_watch = 0; - } - if (priv->teamd_process_watch) { g_source_remove (priv->teamd_process_watch); priv->teamd_process_watch = 0; } + if (priv->teamd_timeout) { + g_source_remove (priv->teamd_timeout); + priv->teamd_timeout = 0; + } + if (priv->teamd_pid > 0) { nm_utils_kill_child_async (priv->teamd_pid, SIGTERM, LOGD_TEAM, "teamd", 2000, NULL, NULL); priv->teamd_pid = 0; } - if (priv->tdc) { + if (priv->tdc && free_tdc) { teamdctl_disconnect (priv->tdc); teamdctl_free (priv->tdc); priv->tdc = NULL; } - - teamd_timeout_remove (device); - - if (device_state_failed) { - if (nm_device_is_activating (device) || - (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED)) - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); - } } static gboolean @@ -314,11 +297,18 @@ teamd_timeout_cb (gpointer user_data) NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (device); g_return_val_if_fail (priv->teamd_timeout, FALSE); + priv->teamd_timeout = 0; - _LOGI (LOGD_TEAM, "teamd timed out."); - teamd_cleanup (device, TRUE); + if (priv->teamd_pid && !priv->tdc) { + /* Timed out launching our own teamd process */ + _LOGW (LOGD_TEAM, "teamd timed out."); + teamd_cleanup (device, TRUE); - return FALSE; + g_warn_if_fail (nm_device_is_activating (device)); + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); + } + + return G_SOURCE_REMOVE; } static void @@ -335,43 +325,77 @@ teamd_dbus_appeared (GDBusConnection *connection, g_return_if_fail (priv->teamd_dbus_watch); _LOGI (LOGD_TEAM, "teamd appeared on D-Bus"); - teamd_timeout_remove (device); + nm_device_queue_recheck_assume (device); + + /* If another teamd grabbed the bus name while our teamd was starting, + * just ignore the death of our teamd and run with the existing one. + */ + if (priv->teamd_process_watch) { + gs_unref_variant GVariant *ret = NULL; + guint32 pid; + + ret = g_dbus_connection_call_sync (connection, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "GetConnectionUnixProcessID", + g_variant_new ("(s)", name_owner), + NULL, + G_DBUS_CALL_FLAGS_NO_AUTO_START, + 2000, + NULL, + NULL); + g_variant_get (ret, "(u)", &pid); + + if (pid != priv->teamd_pid) + teamd_cleanup (device, FALSE); + } + /* Grab a teamd control handle even if we aren't going to use it + * immediately. But if we are, and grabbing it failed, fail the + * device activation. + */ success = ensure_teamd_connection (device); if (nm_device_get_state (device) == NM_DEVICE_STATE_PREPARE) { if (success) nm_device_activate_schedule_stage2_device_config (device); else if (!nm_device_uses_assumed_connection (device)) nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); - return; } } static void -teamd_dbus_vanished (GDBusConnection *connection, +teamd_dbus_vanished (GDBusConnection *dbus_connection, const gchar *name, gpointer user_data) { NMDeviceTeam *self = NM_DEVICE_TEAM (user_data); NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); + NMDeviceState state = nm_device_get_state (device); g_return_if_fail (priv->teamd_dbus_watch); - if (priv->teamd_timeout) { + if (!priv->tdc) { /* g_bus_watch_name will always raise an initial signal, to indicate whether the - * name exists/not exists initially. Do not take this as a failure, until the - * startup timeout is over. - * - * Note that g_bus_watch_name is guaranteed to alternate vanished/appeared signals, - * so we won't hit this condition again (because the next signal is either 'appeared' - * or 'timeout'). */ - _LOGD (LOGD_TEAM, "teamd vanished from D-Bus (ignored)"); + * name exists/not exists initially. Do not take this as a failure if it hadn't + * previously appeared. + */ + _LOGD (LOGD_TEAM, "teamd not on D-Bus (ignored)"); return; } _LOGI (LOGD_TEAM, "teamd vanished from D-Bus"); teamd_cleanup (device, TRUE); + + /* Attempt to respawn teamd */ + if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_ACTIVATED) { + NMConnection *connection = nm_device_get_connection (device); + + g_assert (connection); + if (!teamd_start (device, nm_connection_get_setting_team (connection))) + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); + } } static void @@ -380,13 +404,24 @@ teamd_process_watch_cb (GPid pid, gint status, gpointer user_data) NMDeviceTeam *self = NM_DEVICE_TEAM (user_data); NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); + NMDeviceState state = nm_device_get_state (device); g_return_if_fail (priv->teamd_process_watch); - _LOGI (LOGD_TEAM, "teamd died with status %d", status); - priv->teamd_process_watch = 0; + _LOGD (LOGD_TEAM, "teamd died with status %d", status); priv->teamd_pid = 0; - teamd_cleanup (device, TRUE); + priv->teamd_process_watch = 0; + + /* If teamd quit within 5 seconds of starting, it's probably hosed + * and will just die again, so fail the activation. + */ + if (priv->teamd_timeout && + (state >= NM_DEVICE_STATE_PREPARE) && + (state <= NM_DEVICE_STATE_ACTIVATED)) { + _LOGW (LOGD_TEAM, "teamd process quit unexpectedly; failing activation"); + teamd_cleanup (device, TRUE); + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); + } } static void @@ -407,28 +442,41 @@ teamd_child_setup (gpointer user_data G_GNUC_UNUSED) } static gboolean +teamd_kill (NMDeviceTeam *self, const char *teamd_binary, GError **error) +{ + gs_unref_ptrarray GPtrArray *argv = NULL; + gs_free char *tmp_str = NULL; + + if (!teamd_binary) { + teamd_binary = nm_utils_find_helper ("teamd", NULL, NULL); + if (!teamd_binary) { + _LOGW (LOGD_TEAM, "Activation: (team) failed to start teamd: teamd binary not found"); + return FALSE; + } + } + + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (gpointer) teamd_binary); + g_ptr_array_add (argv, (gpointer) "-k"); + g_ptr_array_add (argv, (gpointer) "-t"); + g_ptr_array_add (argv, (gpointer) nm_device_get_iface (NM_DEVICE (self))); + g_ptr_array_add (argv, NULL); + + _LOGD (LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv (" ", (gchar **) argv->pdata))); + return g_spawn_sync ("/", (char **) argv->pdata, NULL, 0, nm_unblock_posix_signals, NULL, NULL, NULL, NULL, error); +} + +static gboolean teamd_start (NMDevice *device, NMSettingTeam *s_team) { NMDeviceTeam *self = NM_DEVICE_TEAM (device); NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); const char *iface = nm_device_get_ip_iface (device); - char *tmp_str = NULL; - const char *config; + gs_unref_ptrarray GPtrArray *argv = NULL; + gs_free_error GError *error = NULL; + gs_free char *tmp_str = NULL; const char *teamd_binary; - GPtrArray *argv; - GError *error = NULL; - gboolean ret; - int status; - - if (priv->teamd_dbus_watch || - priv->teamd_process_watch || - priv->teamd_pid > 0 || - priv->tdc || - priv->teamd_timeout) - { - /* Just return if teamd_start() was already called */ - return TRUE; - } + const char *config; teamd_binary = nm_utils_find_helper ("teamd", NULL, NULL); if (!teamd_binary) { @@ -436,20 +484,12 @@ teamd_start (NMDevice *device, NMSettingTeam *s_team) return FALSE; } - /* Kill teamd for same named device first if it is there */ - argv = g_ptr_array_new (); - g_ptr_array_add (argv, (gpointer) teamd_binary); - g_ptr_array_add (argv, (gpointer) "-k"); - g_ptr_array_add (argv, (gpointer) "-t"); - g_ptr_array_add (argv, (gpointer) iface); - g_ptr_array_add (argv, NULL); - - _LOGD (LOGD_TEAM, "running: %s", - (tmp_str = g_strjoinv (" ", (gchar **) argv->pdata))); - g_clear_pointer (&tmp_str, g_free); - - ret = g_spawn_sync ("/", (char **) argv->pdata, NULL, 0, nm_unblock_posix_signals, NULL, NULL, NULL, &status, &error); - g_ptr_array_free (argv, TRUE); + if (priv->teamd_process_watch || priv->teamd_pid > 0 || priv->tdc) { + g_warn_if_reached (); + if (!priv->teamd_pid) + teamd_kill (self, teamd_binary, NULL); + teamd_cleanup (device, TRUE); + } /* Start teamd now */ argv = g_ptr_array_new (); @@ -472,83 +512,90 @@ teamd_start (NMDevice *device, NMSettingTeam *s_team) g_ptr_array_add (argv, (gpointer) "-gg"); g_ptr_array_add (argv, NULL); - _LOGD (LOGD_TEAM, "running: %s", - (tmp_str = g_strjoinv (" ", (gchar **) argv->pdata))); - g_clear_pointer (&tmp_str, g_free); - - /* Start a timeout for teamd to appear at D-Bus */ - priv->teamd_timeout = g_timeout_add_seconds (5, teamd_timeout_cb, device); - - /* Register D-Bus name watcher */ - tmp_str = g_strdup_printf ("org.libteam.teamd.%s", iface); - priv->teamd_dbus_watch = g_bus_watch_name (G_BUS_TYPE_SYSTEM, - tmp_str, - G_BUS_NAME_WATCHER_FLAGS_NONE, - teamd_dbus_appeared, - teamd_dbus_vanished, - device, - NULL); - g_free (tmp_str); - - ret = g_spawn_async ("/", (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD, - &teamd_child_setup, NULL, &priv->teamd_pid, &error); - g_ptr_array_free (argv, TRUE); - if (!ret) { + _LOGD (LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv (" ", (gchar **) argv->pdata))); + if (!g_spawn_async ("/", (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD, + teamd_child_setup, NULL, &priv->teamd_pid, &error)) { _LOGW (LOGD_TEAM, "Activation: (team) failed to start teamd: %s", error->message); - g_clear_error (&error); - teamd_cleanup (device, FALSE); + teamd_cleanup (device, TRUE); return FALSE; } + /* Start a timeout for teamd to appear at D-Bus */ + if (!priv->teamd_timeout) + priv->teamd_timeout = g_timeout_add_seconds (5, teamd_timeout_cb, device); + /* Monitor the child process so we know when it dies */ priv->teamd_process_watch = g_child_watch_add (priv->teamd_pid, teamd_process_watch_cb, device); - _LOGI (LOGD_TEAM, "Activation: (team) started teamd..."); + _LOGI (LOGD_TEAM, "Activation: (team) started teamd [pid %u]...", (guint) priv->teamd_pid); return TRUE; } -static void -teamd_stop (NMDevice *device) -{ - NMDeviceTeam *self = NM_DEVICE_TEAM (device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); - - if (priv->teamd_pid > 0) - _LOGI (LOGD_TEAM, "Deactivation: stopping teamd..."); - else - _LOGD (LOGD_TEAM, "Deactivation: stopping teamd (not started)..."); - teamd_cleanup (device, FALSE); -} - static NMActStageReturn act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) { + NMDeviceTeam *self = NM_DEVICE_TEAM (device); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + gs_free_error GError *error = NULL; NMConnection *connection; NMSettingTeam *s_team; + const char *cfg; g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); ret = NM_DEVICE_CLASS (nm_device_team_parent_class)->act_stage1_prepare (device, reason); - if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { - connection = nm_device_get_connection (device); - g_assert (connection); - s_team = nm_connection_get_setting_team (connection); - g_assert (s_team); - if (teamd_start (device, s_team)) - ret = NM_ACT_STAGE_RETURN_POSTPONE; - else - ret = NM_ACT_STAGE_RETURN_FAILURE; + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) + return ret; + + connection = nm_device_get_connection (device); + g_assert (connection); + s_team = nm_connection_get_setting_team (connection); + g_assert (s_team); + + if (priv->tdc) { + /* If the existing teamd config is the same as we're about to use, + * then we can proceed. If it's not the same, and we have a PID, + * kill it so we can respawn it with the right config. If we don't + * have a PID, then we must fail. + */ + cfg = teamdctl_config_get_raw (priv->tdc); + if (cfg && strcmp (cfg, nm_setting_team_get_config (s_team)) == 0) { + _LOGD (LOGD_TEAM, "using existing matching teamd config"); + return NM_ACT_STAGE_RETURN_SUCCESS; + } + + if (!priv->teamd_pid) { + _LOGD (LOGD_TEAM, "existing teamd config mismatch; killing existing via teamdctl"); + if (!teamd_kill (self, NULL, &error)) { + _LOGW (LOGD_TEAM, "existing teamd config mismatch; failed to kill existing teamd: %s", error->message); + *reason = NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED; + return NM_ACT_STAGE_RETURN_FAILURE; + } + } + + _LOGD (LOGD_TEAM, "existing teamd config mismatch; respawning..."); + teamd_cleanup (device, TRUE); } - return ret; + + return teamd_start (device, s_team) ? + NM_ACT_STAGE_RETURN_POSTPONE : NM_ACT_STAGE_RETURN_FAILURE; } static void deactivate (NMDevice *device) { - teamd_stop (device); + NMDeviceTeam *self = NM_DEVICE_TEAM (device); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); + + if (priv->teamd_pid || priv->tdc) + _LOGI (LOGD_TEAM, "deactivation: stopping teamd..."); + + if (!priv->teamd_pid) + teamd_kill (self, NULL, NULL); + teamd_cleanup (device, TRUE); } static gboolean @@ -694,6 +741,27 @@ nm_device_team_init (NMDeviceTeam * self) } static void +constructed (GObject *object) +{ + NMDevice *device = NM_DEVICE (object); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (object); + char *tmp_str = NULL; + + G_OBJECT_CLASS (nm_device_team_parent_class)->constructed (object); + + /* Register D-Bus name watcher */ + tmp_str = g_strdup_printf ("org.libteam.teamd.%s", nm_device_get_ip_iface (device)); + priv->teamd_dbus_watch = g_bus_watch_name (G_BUS_TYPE_SYSTEM, + tmp_str, + G_BUS_NAME_WATCHER_FLAGS_NONE, + teamd_dbus_appeared, + teamd_dbus_vanished, + NM_DEVICE (device), + NULL); + g_free (tmp_str); +} + +static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { @@ -730,7 +798,15 @@ set_property (GObject *object, guint prop_id, static void dispose (GObject *object) { - teamd_cleanup (NM_DEVICE (object), FALSE); + NMDevice *device = NM_DEVICE (object); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (object); + + if (priv->teamd_dbus_watch) { + g_bus_unwatch_name (priv->teamd_dbus_watch); + priv->teamd_dbus_watch = 0; + } + + teamd_cleanup (device, TRUE); G_OBJECT_CLASS (nm_device_team_parent_class)->dispose (object); } @@ -746,6 +822,7 @@ nm_device_team_class_init (NMDeviceTeamClass *klass) parent_class->connection_type = NM_SETTING_TEAM_SETTING_NAME; /* virtual methods */ + object_class->constructed = constructed; object_class->get_property = get_property; object_class->set_property = set_property; object_class->dispose = dispose; |