diff options
| author | Michael Biebl <biebl@debian.org> | 2020-10-05 22:27:18 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2020-10-05 22:27:18 +0200 |
| commit | aafc1dbe4712c86189bbc1d4d54ad8cb4c69be7e (patch) | |
| tree | a2a9bb4d007339a0b1304540388230ccedac32bd /src/devices/team/nm-device-team.c | |
| parent | e7b44ef4c80907346ec7492a09c45277459924fc (diff) | |
New upstream version 1.27.90 upstream/1.27.90
Diffstat (limited to 'src/devices/team/nm-device-team.c')
| -rw-r--r-- | src/devices/team/nm-device-team.c | 1763 |
1 files changed, 894 insertions, 869 deletions
diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c index 7ba30342..27aa3004 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2013 Jiri Pirko <jiri@resnulli.us> * Copyright (C) 2018 Red Hat, Inc. @@ -30,1042 +30,1067 @@ _LOG_DECLARE_SELF(NMDeviceTeam); /*****************************************************************************/ -NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceTeam, - PROP_CONFIG, -); +NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceTeam, PROP_CONFIG, ); typedef struct { - struct teamdctl *tdc; - char *config; - GPid teamd_pid; - guint teamd_process_watch; - guint teamd_timeout; - guint teamd_read_timeout; - guint teamd_dbus_watch; - bool kill_in_progress:1; - GFileMonitor *usock_monitor; - NMDeviceStageState stage1_state:3; + struct teamdctl * tdc; + char * config; + GPid teamd_pid; + guint teamd_process_watch; + guint teamd_timeout; + guint teamd_read_timeout; + guint teamd_dbus_watch; + bool kill_in_progress : 1; + GFileMonitor * usock_monitor; + NMDeviceStageState stage1_state : 3; } NMDeviceTeamPrivate; struct _NMDeviceTeam { - NMDevice parent; - NMDeviceTeamPrivate _priv; + NMDevice parent; + NMDeviceTeamPrivate _priv; }; struct _NMDeviceTeamClass { - NMDeviceClass parent; + NMDeviceClass parent; }; -G_DEFINE_TYPE (NMDeviceTeam, nm_device_team, NM_TYPE_DEVICE) +G_DEFINE_TYPE(NMDeviceTeam, nm_device_team, NM_TYPE_DEVICE) -#define NM_DEVICE_TEAM_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceTeam, NM_IS_DEVICE_TEAM, NMDevice) +#define NM_DEVICE_TEAM_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMDeviceTeam, NM_IS_DEVICE_TEAM, NMDevice) /*****************************************************************************/ -static gboolean teamd_start (NMDeviceTeam *self); +static gboolean teamd_start(NMDeviceTeam *self); /*****************************************************************************/ static NMDeviceCapabilities -get_generic_capabilities (NMDevice *device) +get_generic_capabilities(NMDevice *device) { - return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; + return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; } static gboolean -complete_connection (NMDevice *device, - NMConnection *connection, - const char *specific_object, - NMConnection *const*existing_connections, - GError **error) +complete_connection(NMDevice * device, + NMConnection * connection, + const char * specific_object, + NMConnection *const *existing_connections, + GError ** error) { - NMSettingTeam *s_team; - - nm_utils_complete_generic (nm_device_get_platform (device), - connection, - NM_SETTING_TEAM_SETTING_NAME, - existing_connections, - NULL, - _("Team connection"), - "team", - NULL, - TRUE); - - s_team = nm_connection_get_setting_team (connection); - if (!s_team) { - s_team = (NMSettingTeam *) nm_setting_team_new (); - nm_connection_add_setting (connection, NM_SETTING (s_team)); - } - - return TRUE; + NMSettingTeam *s_team; + + nm_utils_complete_generic(nm_device_get_platform(device), + connection, + NM_SETTING_TEAM_SETTING_NAME, + existing_connections, + NULL, + _("Team connection"), + "team", + NULL, + TRUE); + + s_team = nm_connection_get_setting_team(connection); + if (!s_team) { + s_team = (NMSettingTeam *) nm_setting_team_new(); + nm_connection_add_setting(connection, NM_SETTING(s_team)); + } + + return TRUE; } static gboolean -ensure_teamd_connection (NMDevice *device) +ensure_teamd_connection(NMDevice *device) { - NMDeviceTeam *self = NM_DEVICE_TEAM (device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); - int err; - - if (priv->tdc) - return TRUE; - - priv->tdc = teamdctl_alloc (); - g_assert (priv->tdc); - err = teamdctl_connect (priv->tdc, nm_device_get_iface (device), NULL, NULL); - if (err != 0) { - _LOGE (LOGD_TEAM, "failed to connect to teamd (err=%d)", err); - teamdctl_free (priv->tdc); - priv->tdc = NULL; - } - - return !!priv->tdc; + NMDeviceTeam * self = NM_DEVICE_TEAM(device); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + int err; + + if (priv->tdc) + return TRUE; + + priv->tdc = teamdctl_alloc(); + g_assert(priv->tdc); + err = teamdctl_connect(priv->tdc, nm_device_get_iface(device), NULL, NULL); + if (err != 0) { + _LOGE(LOGD_TEAM, "failed to connect to teamd (err=%d)", err); + teamdctl_free(priv->tdc); + priv->tdc = NULL; + } + + return !!priv->tdc; } static const char * -_get_config (NMDeviceTeam *self) +_get_config(NMDeviceTeam *self) { - return nm_str_not_empty (NM_DEVICE_TEAM_GET_PRIVATE (self)->config); + return nm_str_not_empty(NM_DEVICE_TEAM_GET_PRIVATE(self)->config); } static gboolean -teamd_read_config (NMDeviceTeam *self) +teamd_read_config(NMDeviceTeam *self) { - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); - const char *config = NULL; - int err; - - if (priv->tdc) { - err = teamdctl_config_actual_get_raw_direct (priv->tdc, (char **) &config); - if (err) - return FALSE; - if (!config) { - /* set "" to distinguish an empty result from no config at all. */ - config = ""; - } - } - - if (!nm_streq0 (config, priv->config)) { - g_free (priv->config); - priv->config = g_strdup (config); - _notify (self, PROP_CONFIG); - } - - return TRUE; + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + const char * config = NULL; + int err; + + if (priv->tdc) { + err = teamdctl_config_actual_get_raw_direct(priv->tdc, (char **) &config); + if (err) + return FALSE; + if (!config) { + /* set "" to distinguish an empty result from no config at all. */ + config = ""; + } + } + + if (!nm_streq0(config, priv->config)) { + g_free(priv->config); + priv->config = g_strdup(config); + _notify(self, PROP_CONFIG); + } + + return TRUE; } static gboolean -teamd_read_timeout_cb (gpointer user_data) +teamd_read_timeout_cb(gpointer user_data) { - NMDeviceTeam *self = user_data; - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); + NMDeviceTeam * self = user_data; + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - priv->teamd_read_timeout = 0; - teamd_read_config (self); - return G_SOURCE_REMOVE; + priv->teamd_read_timeout = 0; + teamd_read_config(self); + return G_SOURCE_REMOVE; } static void -update_connection (NMDevice *device, NMConnection *connection) +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); - struct teamdctl *tdc = priv->tdc; - - if (!s_team) { - s_team = (NMSettingTeam *) nm_setting_team_new (); - nm_connection_add_setting (connection, (NMSetting *) s_team); - } - - /* Read the configuration only if not already set */ - if ( !priv->config - && ensure_teamd_connection (device)) - teamd_read_config (self); - - /* Restore previous tdc state */ - if (priv->tdc && !tdc) { - teamdctl_disconnect (priv->tdc); - teamdctl_free (priv->tdc); - priv->tdc = NULL; - } - - g_object_set (G_OBJECT (s_team), NM_SETTING_TEAM_CONFIG, _get_config (self), NULL); + NMDeviceTeam * self = NM_DEVICE_TEAM(device); + NMSettingTeam * s_team = nm_connection_get_setting_team(connection); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + struct teamdctl * tdc = priv->tdc; + + if (!s_team) { + s_team = (NMSettingTeam *) nm_setting_team_new(); + nm_connection_add_setting(connection, (NMSetting *) s_team); + } + + /* Read the configuration only if not already set */ + if (!priv->config && ensure_teamd_connection(device)) + teamd_read_config(self); + + /* Restore previous tdc state */ + if (priv->tdc && !tdc) { + teamdctl_disconnect(priv->tdc); + teamdctl_free(priv->tdc); + priv->tdc = NULL; + } + + g_object_set(G_OBJECT(s_team), NM_SETTING_TEAM_CONFIG, _get_config(self), NULL); } /*****************************************************************************/ static gboolean -master_update_slave_connection (NMDevice *self, - NMDevice *slave, - NMConnection *connection, - GError **error) +master_update_slave_connection(NMDevice * self, + NMDevice * slave, + NMConnection *connection, + GError ** error) { - NMSettingTeamPort *s_port; - char *port_config = NULL; - int err = 0; - struct teamdctl *tdc; - const char *team_port_config = NULL; - const char *iface = nm_device_get_iface (self); - const char *iface_slave = nm_device_get_iface (slave); - - tdc = teamdctl_alloc (); - if (!tdc) { - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "update slave connection for slave '%s' failed to connect to teamd for master %s (out of memory?)", - iface_slave, iface); - g_return_val_if_reached (FALSE); - } - - err = teamdctl_connect (tdc, iface, NULL, NULL); - if (err) { - teamdctl_free (tdc); - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "update slave connection for slave '%s' failed to connect to teamd for master %s (err=%d)", - iface_slave, iface, err); - return FALSE; - } - - err = teamdctl_port_config_get_raw_direct (tdc, iface_slave, (char **)&team_port_config); - port_config = g_strdup (team_port_config); - teamdctl_disconnect (tdc); - teamdctl_free (tdc); - if (err) { - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "update slave connection for slave '%s' failed to get configuration from teamd master %s (err=%d)", - iface_slave, iface, err); - g_free (port_config); - return FALSE; - } - - s_port = nm_connection_get_setting_team_port (connection); - if (!s_port) { - s_port = (NMSettingTeamPort *) nm_setting_team_port_new (); - nm_connection_add_setting (connection, NM_SETTING (s_port)); - } - - g_object_set (G_OBJECT (s_port), NM_SETTING_TEAM_PORT_CONFIG, port_config, NULL); - g_free (port_config); - - g_object_set (nm_connection_get_setting_connection (connection), - NM_SETTING_CONNECTION_MASTER, iface, - NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_TEAM_SETTING_NAME, - NULL); - return TRUE; + NMSettingTeamPort *s_port; + char * port_config = NULL; + int err = 0; + struct teamdctl * tdc; + const char * team_port_config = NULL; + const char * iface = nm_device_get_iface(self); + const char * iface_slave = nm_device_get_iface(slave); + + tdc = teamdctl_alloc(); + if (!tdc) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "update slave connection for slave '%s' failed to connect to teamd for master " + "%s (out of memory?)", + iface_slave, + iface); + g_return_val_if_reached(FALSE); + } + + err = teamdctl_connect(tdc, iface, NULL, NULL); + if (err) { + teamdctl_free(tdc); + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "update slave connection for slave '%s' failed to connect to teamd for master " + "%s (err=%d)", + iface_slave, + iface, + err); + return FALSE; + } + + err = teamdctl_port_config_get_raw_direct(tdc, iface_slave, (char **) &team_port_config); + port_config = g_strdup(team_port_config); + teamdctl_disconnect(tdc); + teamdctl_free(tdc); + if (err) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "update slave connection for slave '%s' failed to get configuration from teamd " + "master %s (err=%d)", + iface_slave, + iface, + err); + g_free(port_config); + return FALSE; + } + + s_port = nm_connection_get_setting_team_port(connection); + if (!s_port) { + s_port = (NMSettingTeamPort *) nm_setting_team_port_new(); + nm_connection_add_setting(connection, NM_SETTING(s_port)); + } + + g_object_set(G_OBJECT(s_port), NM_SETTING_TEAM_PORT_CONFIG, port_config, NULL); + g_free(port_config); + + g_object_set(nm_connection_get_setting_connection(connection), + NM_SETTING_CONNECTION_MASTER, + iface, + NM_SETTING_CONNECTION_SLAVE_TYPE, + NM_SETTING_TEAM_SETTING_NAME, + NULL); + return TRUE; } /*****************************************************************************/ static void -teamd_kill_cb (pid_t pid, gboolean success, int child_status, void *user_data) +teamd_kill_cb(pid_t pid, gboolean success, int child_status, void *user_data) { - gs_unref_object NMDeviceTeam *self = user_data; - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); - - priv->kill_in_progress = FALSE; - - if (nm_device_get_state (NM_DEVICE (self)) != NM_DEVICE_STATE_PREPARE) { - _LOGT (LOGD_TEAM, "kill terminated"); - return; - } - - _LOGT (LOGD_TEAM, "kill terminated, starting teamd..."); - if (!teamd_start (self)) { - nm_device_state_changed (NM_DEVICE (self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); - } + gs_unref_object NMDeviceTeam *self = user_data; + NMDeviceTeamPrivate * priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + + priv->kill_in_progress = FALSE; + + if (nm_device_get_state(NM_DEVICE(self)) != NM_DEVICE_STATE_PREPARE) { + _LOGT(LOGD_TEAM, "kill terminated"); + return; + } + + _LOGT(LOGD_TEAM, "kill terminated, starting teamd..."); + if (!teamd_start(self)) { + nm_device_state_changed(NM_DEVICE(self), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); + } } static void -teamd_cleanup (NMDeviceTeam *self, gboolean free_tdc) +teamd_cleanup(NMDeviceTeam *self, gboolean free_tdc) { - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); - - nm_clear_g_source (&priv->teamd_process_watch); - nm_clear_g_source (&priv->teamd_timeout); - nm_clear_g_source (&priv->teamd_read_timeout); - - if (priv->teamd_pid > 0) { - priv->kill_in_progress = TRUE; - nm_utils_kill_child_async (priv->teamd_pid, - SIGTERM, - LOGD_TEAM, - "teamd", - 2000, - teamd_kill_cb, - g_object_ref (self)); - priv->teamd_pid = 0; - } - - if ( priv->tdc - && free_tdc) { - teamdctl_disconnect (priv->tdc); - teamdctl_free (priv->tdc); - priv->tdc = NULL; - } + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + + nm_clear_g_source(&priv->teamd_process_watch); + nm_clear_g_source(&priv->teamd_timeout); + nm_clear_g_source(&priv->teamd_read_timeout); + + if (priv->teamd_pid > 0) { + priv->kill_in_progress = TRUE; + nm_utils_kill_child_async(priv->teamd_pid, + SIGTERM, + LOGD_TEAM, + "teamd", + 2000, + teamd_kill_cb, + g_object_ref(self)); + priv->teamd_pid = 0; + } + + if (priv->tdc && free_tdc) { + teamdctl_disconnect(priv->tdc); + teamdctl_free(priv->tdc); + priv->tdc = NULL; + } } static gboolean -teamd_timeout_cb (gpointer user_data) +teamd_timeout_cb(gpointer user_data) { - NMDeviceTeam *self = NM_DEVICE_TEAM (user_data); - NMDevice *device = NM_DEVICE (self); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); - - g_return_val_if_fail (priv->teamd_timeout, FALSE); - priv->teamd_timeout = 0; - - if (priv->teamd_pid && !priv->tdc) { - /* Timed out launching our own teamd process */ - _LOGW (LOGD_TEAM, "teamd timed out"); - teamd_cleanup (self, TRUE); - - 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); - } else { - /* Read again the configuration after the timeout since it might - * have changed. - */ - if (!teamd_read_config (self)) { - _LOGW (LOGD_TEAM, "failed to read teamd configuration"); - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); - } - } - - return G_SOURCE_REMOVE; + NMDeviceTeam * self = NM_DEVICE_TEAM(user_data); + NMDevice * device = NM_DEVICE(self); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + + g_return_val_if_fail(priv->teamd_timeout, FALSE); + priv->teamd_timeout = 0; + + if (priv->teamd_pid && !priv->tdc) { + /* Timed out launching our own teamd process */ + _LOGW(LOGD_TEAM, "teamd timed out"); + teamd_cleanup(self, TRUE); + + 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); + } else { + /* Read again the configuration after the timeout since it might + * have changed. + */ + if (!teamd_read_config(self)) { + _LOGW(LOGD_TEAM, "failed to read teamd configuration"); + nm_device_state_changed(device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); + } + } + + return G_SOURCE_REMOVE; } static void -teamd_ready (NMDeviceTeam *self) +teamd_ready(NMDeviceTeam *self) { - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); - NMDevice *device = NM_DEVICE (self); - gboolean success; - - if (priv->kill_in_progress) { - /* If we are currently killing teamd, we are not - * interested in knowing when it becomes ready. */ - return; - } - - nm_device_queue_recheck_assume (device); - - /* 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 - || priv->stage1_state != NM_DEVICE_STAGE_STATE_PENDING) - return; - - if (success) - success = teamd_read_config (self); - - if (!success) { - teamd_cleanup (self, TRUE); - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); - return; - } - - priv->stage1_state = NM_DEVICE_STAGE_STATE_COMPLETED; - nm_device_activate_schedule_stage1_device_prepare (device, FALSE); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + NMDevice * device = NM_DEVICE(self); + gboolean success; + + if (priv->kill_in_progress) { + /* If we are currently killing teamd, we are not + * interested in knowing when it becomes ready. */ + return; + } + + nm_device_queue_recheck_assume(device); + + /* 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 + || priv->stage1_state != NM_DEVICE_STAGE_STATE_PENDING) + return; + + if (success) + success = teamd_read_config(self); + + if (!success) { + teamd_cleanup(self, TRUE); + nm_device_state_changed(device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); + return; + } + + priv->stage1_state = NM_DEVICE_STAGE_STATE_COMPLETED; + nm_device_activate_schedule_stage1_device_prepare(device, FALSE); } static void -teamd_gone (NMDeviceTeam *self) +teamd_gone(NMDeviceTeam *self) { - NMDevice *device = NM_DEVICE (self); - NMDeviceState state; - - teamd_cleanup (self, TRUE); - state = nm_device_get_state (device); - - /* Attempt to respawn teamd */ - if ( state >= NM_DEVICE_STATE_PREPARE - && state <= NM_DEVICE_STATE_ACTIVATED) { - if (!teamd_start (self)) { - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); - } - } + NMDevice * device = NM_DEVICE(self); + NMDeviceState state; + + teamd_cleanup(self, TRUE); + state = nm_device_get_state(device); + + /* Attempt to respawn teamd */ + if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_ACTIVATED) { + if (!teamd_start(self)) { + nm_device_state_changed(device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); + } + } } static void -teamd_dbus_appeared (GDBusConnection *connection, - const char *name, - const char *name_owner, - gpointer user_data) +teamd_dbus_appeared(GDBusConnection *connection, + const char * name, + const char * name_owner, + gpointer user_data) { - NMDeviceTeam *self = NM_DEVICE_TEAM (user_data); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); - - g_return_if_fail (priv->teamd_dbus_watch); - - _LOGI (LOGD_TEAM, "teamd appeared on D-Bus"); - - /* 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, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "GetConnectionUnixProcessID", - g_variant_new ("(s)", name_owner), - NULL, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - 2000, - NULL, - NULL); - - if (ret) { - g_variant_get (ret, "(u)", &pid); - if (pid != priv->teamd_pid) - teamd_cleanup (self, FALSE); - } else { - /* The process that registered on the bus died. If it's - * the teamd instance we just started, ignore the event - * as we already detect the failure through the process - * watch. If it's a previous instance that got killed, - * also ignore that as our new instance will register - * again. */ - _LOGD (LOGD_TEAM, "failed to determine D-Bus name owner, ignoring"); - return; - } - } - - teamd_ready (self); + NMDeviceTeam * self = NM_DEVICE_TEAM(user_data); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + + g_return_if_fail(priv->teamd_dbus_watch); + + _LOGI(LOGD_TEAM, "teamd appeared on D-Bus"); + + /* 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, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "GetConnectionUnixProcessID", + g_variant_new("(s)", name_owner), + NULL, + G_DBUS_CALL_FLAGS_NO_AUTO_START, + 2000, + NULL, + NULL); + + if (ret) { + g_variant_get(ret, "(u)", &pid); + if (pid != priv->teamd_pid) + teamd_cleanup(self, FALSE); + } else { + /* The process that registered on the bus died. If it's + * the teamd instance we just started, ignore the event + * as we already detect the failure through the process + * watch. If it's a previous instance that got killed, + * also ignore that as our new instance will register + * again. */ + _LOGD(LOGD_TEAM, "failed to determine D-Bus name owner, ignoring"); + return; + } + } + + teamd_ready(self); } static void -teamd_dbus_vanished (GDBusConnection *dbus_connection, - const char *name, - gpointer user_data) +teamd_dbus_vanished(GDBusConnection *dbus_connection, const char *name, gpointer user_data) { - NMDeviceTeam *self = NM_DEVICE_TEAM (user_data); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); + NMDeviceTeam * self = NM_DEVICE_TEAM(user_data); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - g_return_if_fail (priv->teamd_dbus_watch); + g_return_if_fail(priv->teamd_dbus_watch); - 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 if it hadn't - * previously appeared. - */ - _LOGD (LOGD_TEAM, "teamd not on D-Bus (ignored)"); - return; - } + 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 if it hadn't + * previously appeared. + */ + _LOGD(LOGD_TEAM, "teamd not on D-Bus (ignored)"); + return; + } - _LOGI (LOGD_TEAM, "teamd vanished from D-Bus"); + _LOGI(LOGD_TEAM, "teamd vanished from D-Bus"); - teamd_gone (self); + teamd_gone(self); } - static void -monitor_changed_cb (GFileMonitor *monitor, - GFile *file, - GFile *other_file, - GFileMonitorEvent event_type, - gpointer user_data) +monitor_changed_cb(GFileMonitor * monitor, + GFile * file, + GFile * other_file, + GFileMonitorEvent event_type, + gpointer user_data) { - NMDeviceTeam *self = NM_DEVICE_TEAM (user_data); - - switch (event_type) { - case G_FILE_MONITOR_EVENT_CREATED: - _LOGI (LOGD_TEAM, "file %s was created", g_file_get_path (file)); - teamd_ready (self); - break; - case G_FILE_MONITOR_EVENT_DELETED: - _LOGI (LOGD_TEAM, "file %s was deleted", g_file_get_path (file)); - teamd_gone (self); - break; - default: - ; - } + NMDeviceTeam *self = NM_DEVICE_TEAM(user_data); + + switch (event_type) { + case G_FILE_MONITOR_EVENT_CREATED: + _LOGI(LOGD_TEAM, "file %s was created", g_file_get_path(file)); + teamd_ready(self); + break; + case G_FILE_MONITOR_EVENT_DELETED: + _LOGI(LOGD_TEAM, "file %s was deleted", g_file_get_path(file)); + teamd_gone(self); + break; + default:; + } } static void -teamd_process_watch_cb (GPid pid, int status, gpointer user_data) +teamd_process_watch_cb(GPid pid, int 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); - - _LOGD (LOGD_TEAM, "teamd %lld died with status %d", (long long) pid, status); - priv->teamd_pid = 0; - 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 %lld quit unexpectedly; failing activation", (long long) pid); - teamd_cleanup (self, TRUE); - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); - } + 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); + + _LOGD(LOGD_TEAM, "teamd %lld died with status %d", (long long) pid, status); + priv->teamd_pid = 0; + 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 %lld quit unexpectedly; failing activation", + (long long) pid); + teamd_cleanup(self, TRUE); + nm_device_state_changed(device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); + } } static void -teamd_child_setup (gpointer user_data) +teamd_child_setup(gpointer user_data) { - nm_utils_setpgid (NULL); - signal (SIGPIPE, SIG_IGN); + nm_utils_setpgid(NULL); + signal(SIGPIPE, SIG_IGN); } static const char ** -teamd_env (void) +teamd_env(void) { - const char **env = g_new0 (const char *, 2); + const char **env = g_new0(const char *, 2); - if (nm_config_get_is_debug (nm_config_get ())) - env[0] = "TEAM_LOG_OUTPUT=stderr"; - else - env[0] = "TEAM_LOG_OUTPUT=syslog"; + if (nm_config_get_is_debug(nm_config_get())) + env[0] = "TEAM_LOG_OUTPUT=stderr"; + else + env[0] = "TEAM_LOG_OUTPUT=syslog"; - return env; + return env; } static gboolean -teamd_kill (NMDeviceTeam *self, const char *teamd_binary, GError **error) +teamd_kill(NMDeviceTeam *self, const char *teamd_binary, GError **error) { - gs_unref_ptrarray GPtrArray *argv = NULL; - gs_free char *tmp_str = NULL; - gs_free const char **envp = NULL; - - if (!teamd_binary) { - teamd_binary = nm_utils_find_helper ("teamd", NULL, error); - 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); - - envp = teamd_env (); - - _LOGD (LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv (" ", (char **) argv->pdata))); - return g_spawn_sync ("/", (char **) argv->pdata, (char **) envp, 0, - teamd_child_setup, NULL, NULL, NULL, NULL, error); + gs_unref_ptrarray GPtrArray *argv = NULL; + gs_free char * tmp_str = NULL; + gs_free const char ** envp = NULL; + + if (!teamd_binary) { + teamd_binary = nm_utils_find_helper("teamd", NULL, error); + 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); + + envp = teamd_env(); + + _LOGD(LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv(" ", (char **) argv->pdata))); + return g_spawn_sync("/", + (char **) argv->pdata, + (char **) envp, + 0, + teamd_child_setup, + NULL, + NULL, + NULL, + NULL, + error); } static gboolean -teamd_start (NMDeviceTeam *self) +teamd_start(NMDeviceTeam *self) { - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); - const char *iface = nm_device_get_ip_iface (NM_DEVICE (self)); - NMConnection *connection; - gs_unref_ptrarray GPtrArray *argv = NULL; - gs_free_error GError *error = NULL; - gs_free char *tmp_str = NULL; - const char *teamd_binary; - const char *config; - nm_auto_free const char *config_free = NULL; - NMSettingTeam *s_team; - gs_free char *cloned_mac = NULL; - gs_free const char **envp = NULL; - - connection = nm_device_get_applied_connection (NM_DEVICE (self)); - - s_team = nm_connection_get_setting_team (connection); - if (!s_team) - g_return_val_if_reached (FALSE); - - nm_assert (iface); - - 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; - } - - 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 (self, TRUE); - } - - /* Start teamd now */ - argv = g_ptr_array_new (); - g_ptr_array_add (argv, (gpointer) teamd_binary); - g_ptr_array_add (argv, (gpointer) "-o"); - g_ptr_array_add (argv, (gpointer) "-n"); - g_ptr_array_add (argv, (gpointer) "-U"); - if (priv->teamd_dbus_watch) - g_ptr_array_add (argv, (gpointer) "-D"); - g_ptr_array_add (argv, (gpointer) "-N"); - g_ptr_array_add (argv, (gpointer) "-t"); - g_ptr_array_add (argv, (gpointer) iface); - - config = nm_setting_team_get_config (s_team); - if (!nm_device_hw_addr_get_cloned (NM_DEVICE (self), connection, FALSE, &cloned_mac, NULL, &error)) { - _LOGW (LOGD_DEVICE, "set-hw-addr: %s", error->message); - return FALSE; - } - - if (cloned_mac) { - json_t *json, *hwaddr; - json_error_t jerror; - - /* Inject the hwaddr property into the JSON configuration. - * While doing so, detect potential conflicts */ - - json = json_loads (config ?: "{}", JSON_REJECT_DUPLICATES, &jerror); - g_return_val_if_fail (json, FALSE); - - hwaddr = json_object_get (json, "hwaddr"); - if (hwaddr) { - if ( !json_is_string (hwaddr) - || !nm_streq0 (json_string_value (hwaddr), cloned_mac)) - _LOGW (LOGD_TEAM, "set-hw-addr: can't set team cloned-mac-address as the JSON configuration already contains \"hwaddr\""); - } else { - hwaddr = json_string (cloned_mac); - json_object_set (json, "hwaddr", hwaddr); - config = config_free = json_dumps (json, JSON_INDENT(0) | - JSON_ENSURE_ASCII | - JSON_SORT_KEYS); - _LOGD (LOGD_TEAM, "set-hw-addr: injected \"hwaddr\" \"%s\" into team configuration", cloned_mac); - json_decref (hwaddr); - } - json_decref (json); - } - - if (config) { - g_ptr_array_add (argv, (gpointer) "-c"); - g_ptr_array_add (argv, (gpointer) config); - } - - if (nm_logging_enabled (LOGL_DEBUG, LOGD_TEAM)) - g_ptr_array_add (argv, (gpointer) "-gg"); - g_ptr_array_add (argv, NULL); - - envp = teamd_env (); - - _LOGD (LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv (" ", (char **) argv->pdata))); - if (!g_spawn_async ("/", (char **) argv->pdata, (char **) envp, 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); - teamd_cleanup (self, 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, self); - - /* 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, - self); - - _LOGI (LOGD_TEAM, "Activation: (team) started teamd [pid %u]...", (guint) priv->teamd_pid); - return TRUE; + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + const char * iface = nm_device_get_ip_iface(NM_DEVICE(self)); + NMConnection * connection; + gs_unref_ptrarray GPtrArray *argv = NULL; + gs_free_error GError * error = NULL; + gs_free char * tmp_str = NULL; + const char * teamd_binary; + const char * config; + nm_auto_free const char *config_free = NULL; + NMSettingTeam * s_team; + gs_free char * cloned_mac = NULL; + gs_free const char ** envp = NULL; + + connection = nm_device_get_applied_connection(NM_DEVICE(self)); + + s_team = nm_connection_get_setting_team(connection); + if (!s_team) + g_return_val_if_reached(FALSE); + + nm_assert(iface); + + 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; + } + + 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(self, TRUE); + } + + /* Start teamd now */ + argv = g_ptr_array_new(); + g_ptr_array_add(argv, (gpointer) teamd_binary); + g_ptr_array_add(argv, (gpointer) "-o"); + g_ptr_array_add(argv, (gpointer) "-n"); + g_ptr_array_add(argv, (gpointer) "-U"); + if (priv->teamd_dbus_watch) + g_ptr_array_add(argv, (gpointer) "-D"); + g_ptr_array_add(argv, (gpointer) "-N"); + g_ptr_array_add(argv, (gpointer) "-t"); + g_ptr_array_add(argv, (gpointer) iface); + + config = nm_setting_team_get_config(s_team); + if (!nm_device_hw_addr_get_cloned(NM_DEVICE(self), + connection, + FALSE, + &cloned_mac, + NULL, + &error)) { + _LOGW(LOGD_DEVICE, "set-hw-addr: %s", error->message); + return FALSE; + } + + if (cloned_mac) { + json_t * json, *hwaddr; + json_error_t jerror; + + /* Inject the hwaddr property into the JSON configuration. + * While doing so, detect potential conflicts */ + + json = json_loads(config ?: "{}", JSON_REJECT_DUPLICATES, &jerror); + g_return_val_if_fail(json, FALSE); + + hwaddr = json_object_get(json, "hwaddr"); + if (hwaddr) { + if (!json_is_string(hwaddr) || !nm_streq0(json_string_value(hwaddr), cloned_mac)) + _LOGW(LOGD_TEAM, + "set-hw-addr: can't set team cloned-mac-address as the JSON configuration " + "already contains \"hwaddr\""); + } else { + hwaddr = json_string(cloned_mac); + json_object_set(json, "hwaddr", hwaddr); + config = config_free = + json_dumps(json, JSON_INDENT(0) | JSON_ENSURE_ASCII | JSON_SORT_KEYS); + _LOGD(LOGD_TEAM, + "set-hw-addr: injected \"hwaddr\" \"%s\" into team configuration", + cloned_mac); + json_decref(hwaddr); + } + json_decref(json); + } + + if (config) { + g_ptr_array_add(argv, (gpointer) "-c"); + g_ptr_array_add(argv, (gpointer) config); + } + + if (nm_logging_enabled(LOGL_DEBUG, LOGD_TEAM)) + g_ptr_array_add(argv, (gpointer) "-gg"); + g_ptr_array_add(argv, NULL); + + envp = teamd_env(); + + _LOGD(LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv(" ", (char **) argv->pdata))); + if (!g_spawn_async("/", + (char **) argv->pdata, + (char **) envp, + 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); + teamd_cleanup(self, 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, self); + + /* 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, self); + + _LOGI(LOGD_TEAM, "Activation: (team) started teamd [pid %u]...", (guint) priv->teamd_pid); + return TRUE; } static NMActStageReturn -act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) +act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) { - NMDeviceTeam *self = NM_DEVICE_TEAM (device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); - gs_free_error GError *error = NULL; - NMSettingTeam *s_team; - const char *cfg; - - if (nm_device_sys_iface_state_is_external (device)) - return NM_ACT_STAGE_RETURN_SUCCESS; - - if (nm_device_sys_iface_state_is_external_or_assume (device)) { - if (ensure_teamd_connection (device)) - return NM_ACT_STAGE_RETURN_SUCCESS; - } - - s_team = nm_device_get_applied_setting (device, NM_TYPE_SETTING_TEAM); - if (!s_team) - g_return_val_if_reached (NM_ACT_STAGE_RETURN_FAILURE); - - if (priv->stage1_state == NM_DEVICE_STAGE_STATE_PENDING) - return NM_ACT_STAGE_RETURN_POSTPONE; - - if (priv->stage1_state == NM_DEVICE_STAGE_STATE_COMPLETED) - return NM_ACT_STAGE_RETURN_SUCCESS; - - priv->stage1_state = NM_DEVICE_STAGE_STATE_PENDING; - - 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 - && nm_streq0 (cfg, nm_setting_team_get_config (s_team))) { - _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); - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - } - - _LOGD (LOGD_TEAM, "existing teamd config mismatch; respawning..."); - teamd_cleanup (self, TRUE); - } - - if (priv->kill_in_progress) { - _LOGT (LOGD_TEAM, "kill in progress, wait before starting teamd"); - return NM_ACT_STAGE_RETURN_POSTPONE; - } - - if (!teamd_start (self)) - return NM_ACT_STAGE_RETURN_FAILURE; - - return NM_ACT_STAGE_RETURN_POSTPONE; + NMDeviceTeam * self = NM_DEVICE_TEAM(device); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + gs_free_error GError *error = NULL; + NMSettingTeam * s_team; + const char * cfg; + + if (nm_device_sys_iface_state_is_external(device)) + return NM_ACT_STAGE_RETURN_SUCCESS; + + if (nm_device_sys_iface_state_is_external_or_assume(device)) { + if (ensure_teamd_connection(device)) + return NM_ACT_STAGE_RETURN_SUCCESS; + } + + s_team = nm_device_get_applied_setting(device, NM_TYPE_SETTING_TEAM); + if (!s_team) + g_return_val_if_reached(NM_ACT_STAGE_RETURN_FAILURE); + + if (priv->stage1_state == NM_DEVICE_STAGE_STATE_PENDING) + return NM_ACT_STAGE_RETURN_POSTPONE; + + if (priv->stage1_state == NM_DEVICE_STAGE_STATE_COMPLETED) + return NM_ACT_STAGE_RETURN_SUCCESS; + + priv->stage1_state = NM_DEVICE_STAGE_STATE_PENDING; + + 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 && nm_streq0(cfg, nm_setting_team_get_config(s_team))) { + _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); + NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); + return NM_ACT_STAGE_RETURN_FAILURE; + } + } + + _LOGD(LOGD_TEAM, "existing teamd config mismatch; respawning..."); + teamd_cleanup(self, TRUE); + } + + if (priv->kill_in_progress) { + _LOGT(LOGD_TEAM, "kill in progress, wait before starting teamd"); + return NM_ACT_STAGE_RETURN_POSTPONE; + } + + if (!teamd_start(self)) + return NM_ACT_STAGE_RETURN_FAILURE; + + return NM_ACT_STAGE_RETURN_POSTPONE; } static void -deactivate (NMDevice *device) +deactivate(NMDevice *device) { - NMDeviceTeam *self = NM_DEVICE_TEAM (device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); + NMDeviceTeam * self = NM_DEVICE_TEAM(device); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - priv->stage1_state = NM_DEVICE_STAGE_STATE_INIT; + priv->stage1_state = NM_DEVICE_STAGE_STATE_INIT; - if (nm_device_sys_iface_state_is_external (device)) - return; + if (nm_device_sys_iface_state_is_external(device)) + return; - if ( priv->teamd_pid - || priv->tdc) - _LOGI (LOGD_TEAM, "deactivation: stopping teamd..."); + if (priv->teamd_pid || priv->tdc) + _LOGI(LOGD_TEAM, "deactivation: stopping teamd..."); - if (!priv->teamd_pid) - teamd_kill (self, NULL, NULL); + if (!priv->teamd_pid) + teamd_kill(self, NULL, NULL); - teamd_cleanup (self, TRUE); + teamd_cleanup(self, TRUE); } static gboolean -enslave_slave (NMDevice *device, - NMDevice *slave, - NMConnection *connection, - gboolean configure) +enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure) { - NMDeviceTeam *self = NM_DEVICE_TEAM (device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); - gboolean success = TRUE; - const char *slave_iface = nm_device_get_ip_iface (slave); - NMSettingTeamPort *s_team_port; - - nm_device_master_check_slave_physical_port (device, slave, LOGD_TEAM); - - if (configure) { - nm_device_take_down (slave, TRUE); - - s_team_port = nm_connection_get_setting_team_port (connection); - if (s_team_port) { - const char *config = nm_setting_team_port_get_config (s_team_port); - - if (config) { - if (!priv->tdc) { - _LOGW (LOGD_TEAM, "enslaved team port %s config not changed, not connected to teamd", - slave_iface); - } else { - int err; - char *sanitized_config; - - sanitized_config = g_strdelimit (g_strdup (config), "\r\n", ' '); - err = teamdctl_port_config_update_raw (priv->tdc, slave_iface, sanitized_config); - g_free (sanitized_config); - if (err != 0) { - _LOGE (LOGD_TEAM, "failed to update config for port %s (err=%d)", - slave_iface, err); - return FALSE; - } - } - } - } - success = nm_platform_link_enslave (nm_device_get_platform (device), - nm_device_get_ip_ifindex (device), - nm_device_get_ip_ifindex (slave)); - nm_device_bring_up (slave, TRUE, NULL); - - if (!success) - return FALSE; - - nm_clear_g_source (&priv->teamd_read_timeout); - priv->teamd_read_timeout = g_timeout_add_seconds (5, - teamd_read_timeout_cb, - self); - - _LOGI (LOGD_TEAM, "enslaved team port %s", slave_iface); - } else - _LOGI (LOGD_TEAM, "team port %s was enslaved", slave_iface); - - return TRUE; + NMDeviceTeam * self = NM_DEVICE_TEAM(device); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + gboolean success = TRUE; + const char * slave_iface = nm_device_get_ip_iface(slave); + NMSettingTeamPort * s_team_port; + + nm_device_master_check_slave_physical_port(device, slave, LOGD_TEAM); + + if (configure) { + nm_device_take_down(slave, TRUE); + + s_team_port = nm_connection_get_setting_team_port(connection); + if (s_team_port) { + const char *config = nm_setting_team_port_get_config(s_team_port); + + if (config) { + if (!priv->tdc) { + _LOGW(LOGD_TEAM, + "enslaved team port %s config not changed, not connected to teamd", + slave_iface); + } else { + int err; + char *sanitized_config; + + sanitized_config = g_strdelimit(g_strdup(config), "\r\n", ' '); + err = teamdctl_port_config_update_raw(priv->tdc, slave_iface, sanitized_config); + g_free(sanitized_config); + if (err != 0) { + _LOGE(LOGD_TEAM, + "failed to update config for port %s (err=%d)", + slave_iface, + err); + return FALSE; + } + } + } + } + success = nm_platform_link_enslave(nm_device_get_platform(device), + nm_device_get_ip_ifindex(device), + nm_device_get_ip_ifindex(slave)); + nm_device_bring_up(slave, TRUE, NULL); + + if (!success) + return FALSE; + + nm_clear_g_source(&priv->teamd_read_timeout); + priv->teamd_read_timeout = g_timeout_add_seconds(5, teamd_read_timeout_cb, self); + + _LOGI(LOGD_TEAM, "enslaved team port %s", slave_iface); + } else + _LOGI(LOGD_TEAM, "team port %s was enslaved", slave_iface); + + return TRUE; } static void -release_slave (NMDevice *device, - NMDevice *slave, - gboolean configure) +release_slave(NMDevice *device, NMDevice *slave, gboolean configure) { - NMDeviceTeam *self = NM_DEVICE_TEAM (device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); - gboolean do_release, success; - NMSettingTeamPort *s_port; - int ifindex_slave; - int ifindex; - - do_release = configure; - if (do_release) { - ifindex = nm_device_get_ifindex (device); - if ( ifindex <= 0 - || !nm_platform_link_get (nm_device_get_platform (device), ifindex)) - do_release = FALSE; - } - - ifindex_slave = nm_device_get_ip_ifindex (slave); - - if (ifindex_slave <= 0) { - _LOGD (LOGD_TEAM, "team port %s is already released", nm_device_get_ip_iface (slave)); - } else if (do_release) { - success = nm_platform_link_release (nm_device_get_platform (device), - nm_device_get_ip_ifindex (device), - ifindex_slave); - if (success) - _LOGI (LOGD_TEAM, "released team port %s", nm_device_get_ip_iface (slave)); - else - _LOGW (LOGD_TEAM, "failed to release team port %s", nm_device_get_ip_iface (slave)); - - /* Kernel team code "closes" the port when releasing it, (which clears - * IFF_UP), so we must bring it back up here to ensure carrier changes and - * other state is noticed by the now-released port. - */ - if (!nm_device_bring_up (slave, TRUE, NULL)) { - _LOGW (LOGD_TEAM, "released team port %s could not be brought up", - nm_device_get_ip_iface (slave)); - } - - nm_clear_g_source (&priv->teamd_read_timeout); - priv->teamd_read_timeout = g_timeout_add_seconds (5, - teamd_read_timeout_cb, - self); - } else - _LOGI (LOGD_TEAM, "team port %s was released", nm_device_get_ip_iface (slave)); - - /* Delete any port configuration we previously set */ - if ( configure - && priv->tdc - && (s_port = nm_device_get_applied_setting (slave, NM_TYPE_SETTING_TEAM_PORT)) - && (nm_setting_team_port_get_config (s_port))) - teamdctl_port_config_update_raw (priv->tdc, nm_device_get_ip_iface (slave), "{}"); + NMDeviceTeam * self = NM_DEVICE_TEAM(device); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + gboolean do_release, success; + NMSettingTeamPort * s_port; + int ifindex_slave; + int ifindex; + + do_release = configure; + if (do_release) { + ifindex = nm_device_get_ifindex(device); + if (ifindex <= 0 || !nm_platform_link_get(nm_device_get_platform(device), ifindex)) + do_release = FALSE; + } + + ifindex_slave = nm_device_get_ip_ifindex(slave); + + if (ifindex_slave <= 0) { + _LOGD(LOGD_TEAM, "team port %s is already released", nm_device_get_ip_iface(slave)); + } else if (do_release) { + success = nm_platform_link_release(nm_device_get_platform(device), + nm_device_get_ip_ifindex(device), + ifindex_slave); + if (success) + _LOGI(LOGD_TEAM, "released team port %s", nm_device_get_ip_iface(slave)); + else + _LOGW(LOGD_TEAM, "failed to release team port %s", nm_device_get_ip_iface(slave)); + + /* Kernel team code "closes" the port when releasing it, (which clears + * IFF_UP), so we must bring it back up here to ensure carrier changes and + * other state is noticed by the now-released port. + */ + if (!nm_device_bring_up(slave, TRUE, NULL)) { + _LOGW(LOGD_TEAM, + "released team port %s could not be brought up", + nm_device_get_ip_iface(slave)); + } + + nm_clear_g_source(&priv->teamd_read_timeout); + priv->teamd_read_timeout = g_timeout_add_seconds(5, teamd_read_timeout_cb, self); + } else + _LOGI(LOGD_TEAM, "team port %s was released", nm_device_get_ip_iface(slave)); + + /* Delete any port configuration we previously set */ + if (configure && priv->tdc + && (s_port = nm_device_get_applied_setting(slave, NM_TYPE_SETTING_TEAM_PORT)) + && (nm_setting_team_port_get_config(s_port))) + teamdctl_port_config_update_raw(priv->tdc, nm_device_get_ip_iface(slave), "{}"); } static gboolean -create_and_realize (NMDevice *device, - NMConnection *connection, - NMDevice *parent, - const NMPlatformLink **out_plink, - GError **error) +create_and_realize(NMDevice * device, + NMConnection * connection, + NMDevice * parent, + const NMPlatformLink **out_plink, + GError ** error) { - const char *iface = nm_device_get_iface (device); - int r; - - r = nm_platform_link_team_add (nm_device_get_platform (device), iface, out_plink); - if (r < 0) { - g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create team master interface '%s' for '%s': %s", - iface, - nm_connection_get_id (connection), - nm_strerror (r)); - return FALSE; - } - - return TRUE; + const char *iface = nm_device_get_iface(device); + int r; + + r = nm_platform_link_team_add(nm_device_get_platform(device), iface, out_plink); + if (r < 0) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create team master interface '%s' for '%s': %s", + iface, + nm_connection_get_id(connection), + nm_strerror(r)); + return FALSE; + } + + return TRUE; } /*****************************************************************************/ static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) +get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMDeviceTeam *self = NM_DEVICE_TEAM (object); - - switch (prop_id) { - case PROP_CONFIG: - g_value_set_string (value, _get_config (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + NMDeviceTeam *self = NM_DEVICE_TEAM(object); + + switch (prop_id) { + case PROP_CONFIG: + g_value_set_string(value, _get_config(self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } } /*****************************************************************************/ static void -nm_device_team_init (NMDeviceTeam * self) +nm_device_team_init(NMDeviceTeam *self) { - nm_assert (nm_device_is_master (NM_DEVICE (self))); + nm_assert(nm_device_is_master(NM_DEVICE(self))); } static void -constructed (GObject *object) +constructed(GObject *object) { - NMDevice *device = NM_DEVICE (object); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (device); - gs_free char *tmp_str = NULL; - gs_unref_object GFile *file = NULL; - GError *error; - - G_OBJECT_CLASS (nm_device_team_parent_class)->constructed (object); - - if (nm_dbus_manager_get_dbus_connection (nm_dbus_manager_get ())) { - /* 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); - return; - } - - /* No D-Bus, watch unix socket */ - tmp_str = g_strdup_printf ("/run/teamd/%s.sock", - nm_device_get_ip_iface (device)); - file = g_file_new_for_path (tmp_str); - priv->usock_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, &error); - if (!priv->usock_monitor) { - nm_log_warn (LOGD_TEAM, "error monitoring %s: %s", tmp_str, error->message); - } else { - g_signal_connect (priv->usock_monitor, - "changed", - G_CALLBACK (monitor_changed_cb), - object); - } + NMDevice * device = NM_DEVICE(object); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(device); + gs_free char * tmp_str = NULL; + gs_unref_object GFile *file = NULL; + GError * error; + + G_OBJECT_CLASS(nm_device_team_parent_class)->constructed(object); + + if (nm_dbus_manager_get_dbus_connection(nm_dbus_manager_get())) { + /* 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); + return; + } + + /* No D-Bus, watch unix socket */ + tmp_str = g_strdup_printf("/run/teamd/%s.sock", nm_device_get_ip_iface(device)); + file = g_file_new_for_path(tmp_str); + priv->usock_monitor = g_file_monitor_file(file, G_FILE_MONITOR_NONE, NULL, &error); + if (!priv->usock_monitor) { + nm_log_warn(LOGD_TEAM, "error monitoring %s: %s", tmp_str, error->message); + } else { + g_signal_connect(priv->usock_monitor, "changed", G_CALLBACK(monitor_changed_cb), object); + } } NMDevice * -nm_device_team_new (const char *iface) +nm_device_team_new(const char *iface) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TEAM, - NM_DEVICE_IFACE, iface, - NM_DEVICE_DRIVER, "team", - NM_DEVICE_TYPE_DESC, "Team", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_TEAM, - NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_TEAM, - NULL); + return (NMDevice *) g_object_new(NM_TYPE_DEVICE_TEAM, + NM_DEVICE_IFACE, + iface, + NM_DEVICE_DRIVER, + "team", + NM_DEVICE_TYPE_DESC, + "Team", + NM_DEVICE_DEVICE_TYPE, + NM_DEVICE_TYPE_TEAM, + NM_DEVICE_LINK_TYPE, + NM_LINK_TYPE_TEAM, + NULL); } static void -dispose (GObject *object) +dispose(GObject *object) { - NMDeviceTeam *self = NM_DEVICE_TEAM (object); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); + NMDeviceTeam * self = NM_DEVICE_TEAM(object); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - if (priv->teamd_dbus_watch) { - g_bus_unwatch_name (priv->teamd_dbus_watch); - priv->teamd_dbus_watch = 0; - } + if (priv->teamd_dbus_watch) { + g_bus_unwatch_name(priv->teamd_dbus_watch); + priv->teamd_dbus_watch = 0; + } - if (priv->usock_monitor) { - g_signal_handlers_disconnect_by_data (priv->usock_monitor, object); - g_clear_object (&priv->usock_monitor); - } + if (priv->usock_monitor) { + g_signal_handlers_disconnect_by_data(priv->usock_monitor, object); + g_clear_object(&priv->usock_monitor); + } - teamd_cleanup (self, TRUE); - nm_clear_g_free (&priv->config); + teamd_cleanup(self, TRUE); + nm_clear_g_free(&priv->config); - G_OBJECT_CLASS (nm_device_team_parent_class)->dispose (object); + G_OBJECT_CLASS(nm_device_team_parent_class)->dispose(object); } static const NMDBusInterfaceInfoExtended interface_info_device_team = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_TEAM, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Carrier", "b", NM_DEVICE_CARRIER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Slaves", "ao", NM_DEVICE_SLAVES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Config", "s", NM_DEVICE_TEAM_CONFIG), - ), - ), - .legacy_property_changed = TRUE, + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( + NM_DBUS_INTERFACE_DEVICE_TEAM, + .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), + .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", + "s", + NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Carrier", "b", NM_DEVICE_CARRIER), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Slaves", "ao", NM_DEVICE_SLAVES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Config", + "s", + NM_DEVICE_TEAM_CONFIG), ), ), + .legacy_property_changed = TRUE, }; static void -nm_device_team_class_init (NMDeviceTeamClass *klass) +nm_device_team_class_init(NMDeviceTeamClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - - object_class->constructed = constructed; - object_class->dispose = dispose; - object_class->get_property = get_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_team); - - device_class->connection_type_supported = NM_SETTING_TEAM_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_TEAM_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_TEAM); - - device_class->is_master = TRUE; - device_class->create_and_realize = create_and_realize; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->complete_connection = complete_connection; - device_class->update_connection = update_connection; - device_class->master_update_slave_connection = master_update_slave_connection; - - device_class->act_stage1_prepare_also_for_external_or_assume = TRUE; - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; - device_class->deactivate = deactivate; - device_class->enslave_slave = enslave_slave; - device_class->release_slave = release_slave; - - obj_properties[PROP_CONFIG] = - g_param_spec_string (NM_DEVICE_TEAM_CONFIG, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + GObjectClass * object_class = G_OBJECT_CLASS(klass); + NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); + NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); + + object_class->constructed = constructed; + object_class->dispose = dispose; + object_class->get_property = get_property; + + dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_team); + + device_class->connection_type_supported = NM_SETTING_TEAM_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_TEAM_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_TEAM); + + device_class->is_master = TRUE; + device_class->create_and_realize = create_and_realize; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->complete_connection = complete_connection; + device_class->update_connection = update_connection; + device_class->master_update_slave_connection = master_update_slave_connection; + + device_class->act_stage1_prepare_also_for_external_or_assume = TRUE; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; + device_class->deactivate = deactivate; + device_class->enslave_slave = enslave_slave; + device_class->release_slave = release_slave; + + obj_properties[PROP_CONFIG] = g_param_spec_string(NM_DEVICE_TEAM_CONFIG, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); } |