diff --git a/src/nm-manager.c b/src/nm-manager.c index 475344a52..f75523acd 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -924,12 +924,80 @@ get_active_connections (NMManager *manager, NMConnection *filter) /* Settings stuff via NMSettings */ /*******************************************************************/ +static gboolean +connection_needs_virtual_device (NMConnection *connection) +{ + if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)) + return TRUE; + + return FALSE; +} + +static gboolean +system_update_virtual_device (NMConnection *connection) +{ + if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)) { + NMSettingBond *s_bond; + + s_bond = nm_connection_get_setting_bond (connection); + g_assert (s_bond); + + return nm_system_add_bonding_master (s_bond); + } + + return TRUE; +} + static void -connections_changed (NMSettings *settings, +system_create_virtual_devices (NMSettings *settings) +{ + GSList *iter, *connections; + + nm_log_info (LOGD_CORE, "Creating virtual devices"); + + connections = nm_settings_get_connections (settings); + for (iter = connections; iter; iter = g_slist_next (iter)) { + NMConnection *connection = NM_CONNECTION (iter->data); + + if (connection_needs_virtual_device (connection)) + system_update_virtual_device (connection); + } + + g_slist_free (connections); +} + +static void +connection_added (NMSettings *settings, + NMSettingsConnection *connection, + NMManager *manager) +{ + bluez_manager_resync_devices (manager); + + if (connection_needs_virtual_device (NM_CONNECTION (connection))) + system_update_virtual_device (NM_CONNECTION (connection)); +} + +static void +connection_changed (NMSettings *settings, NMSettingsConnection *connection, NMManager *manager) { bluez_manager_resync_devices (manager); + + /* FIXME: Some virtual devices may need to be updated in the future. */ +} + +static void +connection_removed (NMSettings *settings, + NMSettingsConnection *connection, + NMManager *manager) +{ + bluez_manager_resync_devices (manager); + + /* + * Do not delete existing virtual devices to keep connectivity up. + * Virtual devices are reused when NetworkManager is restarted. + */ } static void @@ -2823,6 +2891,12 @@ nm_manager_start (NMManager *self) nm_udev_manager_query_devices (priv->udev_mgr); bluez_manager_resync_devices (self); + + /* + * Connections added before the manager is started do not emit + * connection-added signals thus devices have to be created manually. + */ + system_create_virtual_devices (priv->settings); } static gboolean @@ -3099,13 +3173,13 @@ nm_manager_new (NMSettings *settings, g_signal_connect (priv->settings, "notify::" NM_SETTINGS_HOSTNAME, G_CALLBACK (system_hostname_changed_cb), singleton); g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED, - G_CALLBACK (connections_changed), singleton); + G_CALLBACK (connection_added), singleton); g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, - G_CALLBACK (connections_changed), singleton); + G_CALLBACK (connection_changed), singleton); g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, - G_CALLBACK (connections_changed), singleton); + G_CALLBACK (connection_removed), singleton); g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED, - G_CALLBACK (connections_changed), singleton); + G_CALLBACK (connection_changed), singleton); dbus_g_connection_register_g_object (bus, NM_DBUS_PATH, G_OBJECT (singleton)); diff --git a/src/nm-netlink-compat.h b/src/nm-netlink-compat.h index 478bc8b6d..f5539f479 100644 --- a/src/nm-netlink-compat.h +++ b/src/nm-netlink-compat.h @@ -68,7 +68,14 @@ __rtnl_link_alloc_cache (struct nl_sock *h, struct nl_cache **cache) /* functions with similar prototypes */ #define nlmsg_datalen nlmsg_len -#endif + +static inline int +rtnl_link_bond_add (struct nl_sock *h, const char *name, void *data) +{ + /* Bonding only in libnl3 */ + return -NLE_OPNOTSUPP; +} +#endif /* HAVE_LIBNL2 */ /* libnl-1.0 compat functions */ @@ -214,6 +221,14 @@ static inline int __genl_ctrl_alloc_cache(struct nl_sock *h, struct nl_cache **c #define NLE_NOACCESS 27 #define NLE_PERM 28 #define NLE_PKTLOC_FILE 29 -#endif + +static inline int +rtnl_link_bond_add (struct nl_sock *h, const char *name, void *data) +{ + /* Bonding only in libnl3 */ + return -NLE_OPNOTSUPP; +} + +#endif /* HAVE_LIBNL1 */ #endif /* NM_NETLINK_COMPAT_H */ diff --git a/src/nm-system.c b/src/nm-system.c index 62ab8b937..6df2c99b6 100644 --- a/src/nm-system.c +++ b/src/nm-system.c @@ -1202,3 +1202,34 @@ nm_system_device_set_priority (int ifindex, rtnl_route_put (found); } } + +/** + * nm_system_add_bonding_master: + * @setting: bonding setting + * + * Adds a virtual bonding device if it does not exist yet. + * + * Returns: %TRUE on success, %FALSE on failure + */ +gboolean +nm_system_add_bonding_master(NMSettingBond *setting) +{ + struct nl_sock *sock; + const char *name; + int err; + + sock = nm_netlink_get_default_handle (); + name = nm_setting_bond_get_interface_name (setting); + g_assert (name); + + /* Existing bonding devices with matching name will be reused */ + err = rtnl_link_bond_add (sock, name, NULL); + if (err < 0) { + nm_log_err (LOGD_DEVICE, "(%s): error %d returned from " + "rtnl_link_bond_add(): %s", + name, err, nl_geterror (err)); + return FALSE; + } + + return TRUE; +} diff --git a/src/nm-system.h b/src/nm-system.h index ae4e7d91f..a60650354 100644 --- a/src/nm-system.h +++ b/src/nm-system.h @@ -30,6 +30,7 @@ #include #include "nm-device.h" #include "nm-ip4-config.h" +#include "nm-setting-bond.h" /* Prototypes for system/distribution dependent functions, * implemented in the backend files in backends/ directory @@ -89,4 +90,6 @@ gboolean nm_system_iface_set_mtu (int ifindex, guint32 mtu); gboolean nm_system_iface_set_mac (int ifindex, const struct ether_addr *mac); +gboolean nm_system_add_bonding_master (NMSettingBond *setting); + #endif