diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index 917d457141..cd5e95f908 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -243,6 +243,19 @@ update_connection (NMDevice *device, NMConnection *connection) } } +static gboolean +master_update_slave_connection (NMDevice *self, + NMDevice *slave, + NMConnection *connection, + GError **error) +{ + g_object_set (nm_connection_get_setting_connection (connection), + NM_SETTING_CONNECTION_MASTER, nm_device_get_iface (self), + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME, + NULL); + return TRUE; +} + static void set_arp_targets (NMDevice *device, const char *value, @@ -590,6 +603,7 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) parent_class->complete_connection = complete_connection; parent_class->update_connection = update_connection; + parent_class->master_update_slave_connection = master_update_slave_connection; parent_class->act_stage1_prepare = act_stage1_prepare; parent_class->enslave_slave = enslave_slave; diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index cbf6ccf7d8..b00446af0c 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -322,27 +322,21 @@ update_connection (NMDevice *device, NMConnection *connection) } } -/** - * nm_bridge_update_slave_connection: - * @slave: the slave #NMDevice, is *not* necessarily a bridge interface - * @connection: the #NMConnection to update with the bridge port settings - * - * Reads bridge port configuration and updates @connection with those - * properties. - * - * Returns: %TRUE if the port configuration was read and @connection updated, - * %FALSE if not. - */ -gboolean -nm_bridge_update_slave_connection (NMDevice *slave, NMConnection *connection) +static gboolean +master_update_slave_connection (NMDevice *self, + NMDevice *slave, + NMConnection *connection, + GError **error) { + NMSettingConnection *s_con; NMSettingBridgePort *s_port; - int ifindex = nm_device_get_ifindex (slave); + int ifindex_slave = nm_device_get_ifindex (slave); + const char *iface = nm_device_get_iface (self); const Option *option; - g_return_val_if_fail (NM_IS_DEVICE (slave), FALSE); - g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); + g_return_val_if_fail (ifindex_slave > 0, FALSE); + s_con = nm_connection_get_setting_connection (connection); s_port = nm_connection_get_setting_bridge_port (connection); if (!s_port) { s_port = (NMSettingBridgePort *) nm_setting_bridge_port_new (); @@ -350,7 +344,7 @@ nm_bridge_update_slave_connection (NMDevice *slave, NMConnection *connection) } for (option = slave_options; option->name; option++) { - gs_free char *str = nm_platform_slave_get_option (ifindex, option->sysname); + gs_free char *str = nm_platform_slave_get_option (ifindex_slave, option->sysname); int value; if (str) { @@ -367,6 +361,10 @@ nm_bridge_update_slave_connection (NMDevice *slave, NMConnection *connection) } } + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, iface, + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BRIDGE_SETTING_NAME, + NULL); return TRUE; } @@ -566,6 +564,7 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass) parent_class->complete_connection = complete_connection; parent_class->update_connection = update_connection; + parent_class->master_update_slave_connection = master_update_slave_connection; parent_class->act_stage1_prepare = act_stage1_prepare; parent_class->enslave_slave = enslave_slave; diff --git a/src/devices/nm-device-bridge.h b/src/devices/nm-device-bridge.h index 4194f5a411..5570c73555 100644 --- a/src/devices/nm-device-bridge.h +++ b/src/devices/nm-device-bridge.h @@ -57,8 +57,6 @@ GType nm_device_bridge_get_type (void); NMDevice *nm_device_bridge_new (NMPlatformLink *platform_device); NMDevice *nm_device_bridge_new_for_connection (NMConnection *connection); -gboolean nm_bridge_update_slave_connection (NMDevice *slave, NMConnection *connection); - G_END_DECLS #endif /* NM_DEVICE_BRIDGE_H */ diff --git a/src/devices/nm-device-team.c b/src/devices/nm-device-team.c index e9dfbf38a2..67f3b0d3cf 100644 --- a/src/devices/nm-device-team.c +++ b/src/devices/nm-device-team.c @@ -245,44 +245,63 @@ update_connection (NMDevice *device, NMConnection *connection) /******************************************************************/ -gboolean -nm_team_update_slave_connection (NMDevice *slave, NMConnection *connection) +static gboolean +master_update_slave_connection (NMDevice *self, + NMDevice *slave, + NMConnection *connection, + GError **error) { - NMSettingTeamPort *s_port; - const char *iface = nm_device_get_iface (slave); - char *port_config = NULL; - gboolean with_teamdctl = FALSE; - int err = 0; #if WITH_TEAMDCTL - const char *master_iface; - int master_ifindex; + NMSettingTeamPort *s_port; + char *port_config = NULL; + int err = 0; struct teamdctl *tdc; const char *team_port_config = NULL; #endif + const char *iface = nm_device_get_iface (self); + const char *iface_slave = nm_device_get_iface (slave); - g_return_val_if_fail (NM_IS_DEVICE (slave), FALSE); - g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); - -#if WITH_TEAMDCTL - master_ifindex = nm_platform_link_get_master (nm_device_get_ifindex (slave)); - g_assert (master_ifindex > 0); - master_iface = nm_platform_link_get_name (master_ifindex); - g_assert (master_iface); - +#if !WITH_TEAMDCTL + g_set_error (error, + NM_DEVICE_TEAM_ERROR, + NM_DEVICE_TEAM_ERROR_NO_SUPPORT, + "update slave connection for slave '%s' failed for team master '%s' because compiled without libteamctl support", + iface_slave, iface); + return FALSE; +#else tdc = teamdctl_alloc (); - g_assert (tdc); - err = teamdctl_connect (tdc, master_iface, NULL, NULL); + if (!tdc) { + g_set_error (error, + NM_DEVICE_TEAM_ERROR, + NM_DEVICE_TEAM_ERROR_TEAMCTL_FAILURE, + "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) { - nm_log_err (LOGD_TEAM, "(%s): failed to connect to teamd for master %s (err=%d)", - iface, master_iface, err); teamdctl_free (tdc); + g_set_error (error, + NM_DEVICE_TEAM_ERROR, + NM_DEVICE_TEAM_ERROR_TEAMCTL_FAILURE, + "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, (char **)&team_port_config); + + err = teamdctl_port_config_get_raw_direct (tdc, iface_slave, (char **)&team_port_config); port_config = g_strdup (team_port_config); teamdctl_free (tdc); - with_teamdctl = TRUE; -#endif + if (err) { + g_set_error (error, + NM_DEVICE_TEAM_ERROR, + NM_DEVICE_TEAM_ERROR_TEAMCTL_FAILURE, + "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) { @@ -293,17 +312,12 @@ nm_team_update_slave_connection (NMDevice *slave, NMConnection *connection) g_object_set (G_OBJECT (s_port), NM_SETTING_TEAM_PORT_CONFIG, port_config, NULL); g_free (port_config); - if (!with_teamdctl || err != 0) { - if (!with_teamdctl) - nm_log_err (LOGD_TEAM, "(%s): failed to read teamd port configuration " - " (compiled without libteamdctl support)", iface); - else - nm_log_err (LOGD_TEAM, "(%s): failed to read teamd port configuration (err=%d)", - iface, err); - return FALSE; - } - + 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; +#endif } /******************************************************************/ @@ -871,6 +885,7 @@ nm_device_team_class_init (NMDeviceTeamClass *klass) parent_class->check_connection_available = check_connection_available; parent_class->complete_connection = complete_connection; parent_class->update_connection = update_connection; + parent_class->master_update_slave_connection = master_update_slave_connection; parent_class->act_stage1_prepare = act_stage1_prepare; parent_class->deactivate = deactivate; diff --git a/src/devices/nm-device-team.h b/src/devices/nm-device-team.h index 32bc5fd86f..9af0bb3c6d 100644 --- a/src/devices/nm-device-team.h +++ b/src/devices/nm-device-team.h @@ -38,6 +38,8 @@ typedef enum { NM_DEVICE_TEAM_ERROR_CONNECTION_NOT_TEAM = 0, /*< nick=ConnectionNotTeam >*/ NM_DEVICE_TEAM_ERROR_CONNECTION_INVALID, /*< nick=ConnectionInvalid >*/ NM_DEVICE_TEAM_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/ + NM_DEVICE_TEAM_ERROR_TEAMCTL_FAILURE, /*< nick=TeamCtlFailure >*/ + NM_DEVICE_TEAM_ERROR_NO_SUPPORT, /*< nick=NoSupport >*/ } NMTeamError; #define NM_DEVICE_TEAM_SLAVES "slaves" @@ -57,8 +59,6 @@ GType nm_device_team_get_type (void); NMDevice *nm_device_team_new (NMPlatformLink *platform_device); NMDevice *nm_device_team_new_for_connection (NMConnection *connection); -gboolean nm_team_update_slave_connection (NMDevice *slave, NMConnection *connection); - G_END_DECLS #endif /* NM_DEVICE_TEAM_H */ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 84c714a102..2ee1c4937b 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -70,10 +70,6 @@ #include "nm-config.h" #include "nm-dns-manager.h" -#include "nm-device-bridge.h" -#include "nm-device-bond.h" -#include "nm-device-team.h" - static void impl_device_disconnect (NMDevice *device, DBusGMethodInvocation *context); #include "nm-device-glue.h" @@ -1627,20 +1623,67 @@ device_has_config (NMDevice *device) return FALSE; } +/** + * nm_device_master_update_slave_connection: + * @self: the master #NMDevice + * @slave: the slave #NMDevice + * @connection: the #NMConnection to update with the slave settings + * @GError: (out): error description + * + * Reads the slave configuration for @slave and updates @connection with those + * properties. This invokes a virtual function on the master device @self. + * + * Returns: %TRUE if the configuration was read and @connection updated, + * %FALSE on failure. + */ +gboolean +nm_device_master_update_slave_connection (NMDevice *self, + NMDevice *slave, + NMConnection *connection, + GError **error) +{ + NMDeviceClass *klass; + gboolean success; + const char *iface; + + g_return_val_if_fail (self, FALSE); + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail (slave, FALSE); + g_return_val_if_fail (connection, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); + g_return_val_if_fail (nm_connection_get_setting_connection (connection), FALSE); + + iface = nm_device_get_iface (self); + g_return_val_if_fail (iface, FALSE); + + klass = NM_DEVICE_GET_CLASS (self); + if (klass->master_update_slave_connection) { + success = klass->master_update_slave_connection (self, slave, connection, error); + + g_return_val_if_fail (!error || (success && !*error) || *error, success); + return success; + } + + g_set_error (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_UNSUPPORTED_DEVICE_TYPE, + "master device '%s' cannot update a slave connection for slave device '%s' (master type not supported?)", + iface, nm_device_get_iface (slave)); + return FALSE; +} + NMConnection * -nm_device_generate_connection (NMDevice *device) +nm_device_generate_connection (NMDevice *device, NMDevice *master) { NMDeviceClass *klass = NM_DEVICE_GET_CLASS (device); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device); const char *ifname = nm_device_get_iface (device); - int ifindex = nm_device_get_ifindex (device); NMConnection *connection; NMSetting *s_con; NMSetting *s_ip4; NMSetting *s_ip6; gs_free char *uuid = NULL; gs_free char *name = NULL; - int master_ifindex = 0; const char *ip4_method, *ip6_method; GError *error = NULL; @@ -1654,19 +1697,6 @@ nm_device_generate_connection (NMDevice *device) return NULL; } - if (ifindex) - master_ifindex = nm_platform_link_get_master (ifindex); - if (master_ifindex) { - NMDevice *master; - - master = nm_manager_get_device_by_ifindex (nm_manager_get (), master_ifindex); - if (!master || !nm_device_get_act_request (master)) { - nm_log_dbg (LOGD_DEVICE, "(%s): cannot generate connection for slave before its master (%s)", - ifname, nm_platform_link_get_name (master_ifindex)); - return NULL; - } - } - connection = nm_connection_new (); s_con = nm_setting_connection_new (); uuid = nm_utils_uuid_generate (); @@ -1684,36 +1714,18 @@ nm_device_generate_connection (NMDevice *device) nm_connection_add_setting (connection, s_con); /* If the device is a slave, update various slave settings */ - if (master_ifindex) { - const char *master_iface = nm_platform_link_get_name (master_ifindex); - const char *slave_type = NULL; - gboolean success = FALSE; - - switch (nm_platform_link_get_type (master_ifindex)) { - case NM_LINK_TYPE_BRIDGE: - slave_type = NM_SETTING_BRIDGE_SETTING_NAME; - success = nm_bridge_update_slave_connection (device, connection); - break; - case NM_LINK_TYPE_BOND: - slave_type = NM_SETTING_BOND_SETTING_NAME; - success = TRUE; - break; - case NM_LINK_TYPE_TEAM: - slave_type = NM_SETTING_TEAM_SETTING_NAME; - success = nm_team_update_slave_connection (device, connection); - break; - default: - g_warn_if_reached (); - break; + if (master) { + if (!nm_device_master_update_slave_connection (master, + device, + connection, + &error)) + { + nm_log_err (LOGD_DEVICE, "(%s): master device '%s' failed to update slave connection: %s", + ifname, nm_device_get_iface (master), error ? error->message : "(unknown error)"); + g_error_free (error); + g_object_unref (connection); + return NULL; } - - if (!success) - nm_log_err (LOGD_DEVICE, "(%s): failed to read slave configuration", ifname); - - g_object_set (s_con, - NM_SETTING_CONNECTION_MASTER, master_iface, - NM_SETTING_CONNECTION_SLAVE_TYPE, slave_type, - NULL); } else { /* Only regular and master devices get IP configuration; slaves do not */ s_ip4 = nm_ip4_config_create_setting (priv->ip4_config); diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index f74486e6fc..d034c946dc 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -94,6 +94,7 @@ typedef enum { NM_DEVICE_ERROR_CONNECTION_ACTIVATING = 0, /*< nick=ConnectionActivating >*/ NM_DEVICE_ERROR_CONNECTION_INVALID, /*< nick=ConnectionInvalid >*/ NM_DEVICE_ERROR_NOT_ACTIVE, /*< nick=NotActive >*/ + NM_DEVICE_ERROR_UNSUPPORTED_DEVICE_TYPE, /*< nick=UnsupportedDeviceType >*/ } NMDeviceError; struct _NMDevice { @@ -192,6 +193,11 @@ typedef struct { /* Update the connection with currently configured L2 settings */ void (* update_connection) (NMDevice *device, NMConnection *connection); + gboolean (*master_update_slave_connection) (NMDevice *self, + NMDevice *slave, + NMConnection *connection, + GError **error); + gboolean (* enslave_slave) (NMDevice *self, NMDevice *slave, NMConnection *connection, @@ -258,7 +264,12 @@ NMConnection * nm_device_get_connection (NMDevice *dev); gboolean nm_device_is_available (NMDevice *dev); gboolean nm_device_has_carrier (NMDevice *dev); -NMConnection * nm_device_generate_connection (NMDevice *device); +NMConnection * nm_device_generate_connection (NMDevice *device, NMDevice *master); + +gboolean nm_device_master_update_slave_connection (NMDevice *master, + NMDevice *slave, + NMConnection *connection, + GError **error); NMConnection * nm_device_get_best_auto_connection (NMDevice *dev, GSList *connections, diff --git a/src/nm-manager.c b/src/nm-manager.c index 13b4a01417..052ccb7834 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1557,16 +1557,36 @@ get_existing_connection (NMManager *manager, NMDevice *device) NMConnection *connection = NULL, *matched; NMSettingsConnection *added = NULL; GError *error = NULL; + NMDevice *master = NULL; + int ifindex = nm_device_get_ifindex (device); nm_device_capture_initial_config (device); + if (ifindex) { + int master_ifindex = nm_platform_link_get_master (ifindex); + + if (master_ifindex) { + master = nm_manager_get_device_by_ifindex (manager, master_ifindex); + if (!master) { + nm_log_dbg (LOGD_DEVICE, "(%s): cannot generate connection for slave before its master (%s/%d)", + nm_device_get_iface (device), nm_platform_link_get_name (master_ifindex), master_ifindex); + return NULL; + } + if (!nm_device_get_act_request (master)) { + nm_log_dbg (LOGD_DEVICE, "(%s): cannot generate connection for slave before master %s activates", + nm_device_get_iface (device), nm_device_get_iface (master)); + return NULL; + } + } + } + /* The core of the API is nm_device_generate_connection() function and * update_connection() virtual method and the convenient connection_type * class attribute. Subclasses supporting the new API must have * update_connection() implemented, otherwise nm_device_generate_connection() * returns NULL. */ - connection = nm_device_generate_connection (device); + connection = nm_device_generate_connection (device, master); if (!connection) return NULL;