summary refs log tree commit diff
path: root/src/devices/team/nm-device-team.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2021-02-11 18:11:46 +0100
committerMichael Biebl <biebl@debian.org>2021-02-11 18:11:46 +0100
commit80ec1decc49c72efec2a8b87c06245c92c0ab807 (patch)
treee3b229aa94e8dcf0590f2317664176e7b8f7607b /src/devices/team/nm-device-team.c
parent65f86e8f56267192d42f2b629fc6b0c99fb9cd0c (diff)
New upstream version 1.29.90 upstream/1.29.90
Diffstat (limited to 'src/devices/team/nm-device-team.c')
-rw-r--r--src/devices/team/nm-device-team.c1096
1 files changed, 0 insertions, 1096 deletions
diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c
deleted file mode 100644
index 27aa3004..00000000
--- a/src/devices/team/nm-device-team.c
+++ /dev/null
@@ -1,1096 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (C) 2013 Jiri Pirko <jiri@resnulli.us>
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#include "nm-default.h"
-
-#include "nm-device-team.h"
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/wait.h>
-#include <teamdctl.h>
-#include <stdlib.h>
-
-#include "nm-glib-aux/nm-jansson.h"
-#include "NetworkManagerUtils.h"
-#include "devices/nm-device-private.h"
-#include "platform/nm-platform.h"
-#include "nm-config.h"
-#include "nm-core-internal.h"
-#include "nm-dbus-manager.h"
-#include "nm-ip4-config.h"
-#include "nm-std-aux/nm-dbus-compat.h"
-
-#include "devices/nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceTeam);
-
-/*****************************************************************************/
-
-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;
-} NMDeviceTeamPrivate;
-
-struct _NMDeviceTeam {
-    NMDevice            parent;
-    NMDeviceTeamPrivate _priv;
-};
-
-struct _NMDeviceTeamClass {
-    NMDeviceClass parent;
-};
-
-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)
-
-/*****************************************************************************/
-
-static gboolean teamd_start(NMDeviceTeam *self);
-
-/*****************************************************************************/
-
-static NMDeviceCapabilities
-get_generic_capabilities(NMDevice *device)
-{
-    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)
-{
-    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)
-{
-    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)
-{
-    return nm_str_not_empty(NM_DEVICE_TEAM_GET_PRIVATE(self)->config);
-}
-
-static gboolean
-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;
-}
-
-static gboolean
-teamd_read_timeout_cb(gpointer user_data)
-{
-    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;
-}
-
-static void
-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);
-}
-
-/*****************************************************************************/
-
-static gboolean
-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;
-}
-
-/*****************************************************************************/
-
-static void
-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);
-    }
-}
-
-static void
-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;
-    }
-}
-
-static gboolean
-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;
-}
-
-static void
-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);
-}
-
-static void
-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);
-        }
-    }
-}
-
-static void
-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);
-}
-
-static void
-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);
-
-    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;
-    }
-
-    _LOGI(LOGD_TEAM, "teamd vanished from D-Bus");
-
-    teamd_gone(self);
-}
-
-static void
-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:;
-    }
-}
-
-static void
-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);
-    }
-}
-
-static void
-teamd_child_setup(gpointer user_data)
-{
-    nm_utils_setpgid(NULL);
-    signal(SIGPIPE, SIG_IGN);
-}
-
-static const char **
-teamd_env(void)
-{
-    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";
-
-    return env;
-}
-
-static gboolean
-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);
-}
-
-static gboolean
-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;
-}
-
-static NMActStageReturn
-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;
-}
-
-static void
-deactivate(NMDevice *device)
-{
-    NMDeviceTeam *       self = NM_DEVICE_TEAM(device);
-    NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self);
-
-    priv->stage1_state = NM_DEVICE_STAGE_STATE_INIT;
-
-    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)
-        teamd_kill(self, NULL, NULL);
-
-    teamd_cleanup(self, TRUE);
-}
-
-static gboolean
-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;
-}
-
-static void
-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), "{}");
-}
-
-static gboolean
-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;
-}
-
-/*****************************************************************************/
-
-static void
-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;
-    }
-}
-
-/*****************************************************************************/
-
-static void
-nm_device_team_init(NMDeviceTeam *self)
-{
-    nm_assert(nm_device_is_master(NM_DEVICE(self)));
-}
-
-static void
-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 *
-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);
-}
-
-static void
-dispose(GObject *object)
-{
-    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->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);
-
-    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,
-};
-
-static void
-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);
-}