From 095aff0c21c24cf66034d114e073dc6030007283 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 18 Oct 2011 13:48:44 +0200 Subject: [PATCH] bonding: kernel bonding device creation Creates virtual kernel devices as needed. Since the manager is initialized after the connections have been loaded no CONNECTIONS_ADDED notification is received for connections parsed at startup. Therefore walks the loaded connections looking for bonding connections. Connections added on the fly are handled via the notifications. Connection renaming and deleting is not supported yet. Signed-off-by: Thomas Graf --- src/nm-manager.c | 84 ++++++++++++++++++++++++++++++++++++++--- src/nm-netlink-compat.h | 19 +++++++++- src/nm-system.c | 31 +++++++++++++++ src/nm-system.h | 3 ++ 4 files changed, 130 insertions(+), 7 deletions(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index 475344a522..f75523acd0 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 478bc8b6da..f5539f4797 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 62ab8b9375..6df2c99b63 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 ae4e7d91f8..a606503547 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