core: don't create virtual interfaces we already have
Make sure we don't already have an NMDevice for this interface before creating it, and also when creating the interface, make a new NMDevice for it immediately to prevent a race between telling the kernel to create the interface via netlink, and when udev later tells us about it. In between there we could be triggered to try creating the interface again.
This commit is contained in:
@@ -3563,7 +3563,11 @@ set_property (GObject *object, guint prop_id,
|
|||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_UDI:
|
case PROP_UDI:
|
||||||
/* construct-only */
|
/* Only virtual interfaces can set UDI post-construction */
|
||||||
|
if (priv->initialized)
|
||||||
|
g_return_if_fail (nm_system_get_iface_type (priv->ifindex, NULL) != NM_IFACE_TYPE_UNSPEC);
|
||||||
|
|
||||||
|
g_free (priv->udi);
|
||||||
priv->udi = g_strdup (g_value_get_string (value));
|
priv->udi = g_strdup (g_value_get_string (value));
|
||||||
break;
|
break;
|
||||||
case PROP_IFACE:
|
case PROP_IFACE:
|
||||||
@@ -3746,7 +3750,7 @@ nm_device_class_init (NMDeviceClass *klass)
|
|||||||
"UDI",
|
"UDI",
|
||||||
"Unique Device Identifier",
|
"Unique Device Identifier",
|
||||||
NULL,
|
NULL,
|
||||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||||
|
|
||||||
g_object_class_install_property
|
g_object_class_install_property
|
||||||
(object_class, PROP_IFACE,
|
(object_class, PROP_IFACE,
|
||||||
|
129
src/nm-manager.c
129
src/nm-manager.c
@@ -888,6 +888,27 @@ get_active_connections (NMManager *manager, NMConnection *filter)
|
|||||||
/* Settings stuff via NMSettings */
|
/* Settings stuff via NMSettings */
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get_virtual_iface_name:
|
||||||
|
* @self: the #NMManager
|
||||||
|
* @connection: the #NMConnection representing a virtual interface
|
||||||
|
*
|
||||||
|
* Given @connection, returns the interface name that the connection
|
||||||
|
* would represent. If the interface name is not given by the connection,
|
||||||
|
* this may require constructing it based on information in the connection
|
||||||
|
* and existing network interfaces.
|
||||||
|
*
|
||||||
|
* Returns: the expected interface name (caller takes ownership), or %NULL
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
get_virtual_iface_name (NMManager *self, NMConnection *connection)
|
||||||
|
{
|
||||||
|
if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME))
|
||||||
|
return g_strdup (nm_connection_get_virtual_iface_name (connection));
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
connection_needs_virtual_device (NMConnection *connection)
|
connection_needs_virtual_device (NMConnection *connection)
|
||||||
{
|
{
|
||||||
@@ -897,36 +918,98 @@ connection_needs_virtual_device (NMConnection *connection)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static char *
|
||||||
system_update_virtual_device (NMConnection *connection)
|
get_virtual_iface_placeholder_udi (void)
|
||||||
{
|
{
|
||||||
if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)) {
|
static guint32 id = 0;
|
||||||
NMSettingBond *s_bond;
|
|
||||||
|
|
||||||
s_bond = nm_connection_get_setting_bond (connection);
|
return g_strdup_printf ("/virtual/device/placeholder/%d", id++);
|
||||||
g_assert (s_bond);
|
}
|
||||||
|
|
||||||
return nm_system_add_bonding_master (s_bond);
|
/**
|
||||||
|
* system_create_virtual_device:
|
||||||
|
* @self: the #NMManager
|
||||||
|
* @connection: the connection which might require a virtual device
|
||||||
|
*
|
||||||
|
* If @connection requires a virtual device and one does not yet exist for it,
|
||||||
|
* creates that device.
|
||||||
|
*
|
||||||
|
* Returns: the #NMDevice if successfully created, NULL if not
|
||||||
|
*/
|
||||||
|
static NMDevice *
|
||||||
|
system_create_virtual_device (NMManager *self, NMConnection *connection)
|
||||||
|
{
|
||||||
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||||
|
GSList *iter;
|
||||||
|
char *iface = NULL, *udi;
|
||||||
|
NMDevice *device = NULL;
|
||||||
|
int master_ifindex = -1;
|
||||||
|
const char *driver = NULL;
|
||||||
|
|
||||||
|
iface = get_virtual_iface_name (self, connection);
|
||||||
|
if (!iface) {
|
||||||
|
nm_log_warn (LOGD_DEVICE, "(%s) failed to determine virtual interface name",
|
||||||
|
nm_connection_get_id (connection));
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
/* Make sure we didn't create a device for this connection already */
|
||||||
|
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
|
||||||
|
NMDevice *candidate = iter->data;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if ( g_strcmp0 (nm_device_get_iface (candidate), iface) == 0
|
||||||
|
|| nm_device_check_connection_compatible (candidate, connection, &error)) {
|
||||||
|
g_clear_error (&error);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
g_clear_error (&error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)) {
|
||||||
|
if (!nm_system_add_bonding_master (iface)) {
|
||||||
|
nm_log_warn (LOGD_DEVICE, "(%s): failed to add bonding master interface for '%s'",
|
||||||
|
iface, nm_connection_get_id (connection));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
driver = "bonding";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (driver) {
|
||||||
|
udi = get_virtual_iface_placeholder_udi ();
|
||||||
|
device = nm_device_ethernet_new (udi, iface, driver);
|
||||||
|
g_free (udi);
|
||||||
|
if (device)
|
||||||
|
add_device (self, device);
|
||||||
|
else
|
||||||
|
nm_log_warn (LOGD_DEVICE, "(%s) failed to add virtual interface device", iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
g_free (iface);
|
||||||
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
system_create_virtual_devices (NMSettings *settings)
|
system_create_virtual_devices (NMManager *self)
|
||||||
{
|
{
|
||||||
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||||
GSList *iter, *connections;
|
GSList *iter, *connections;
|
||||||
|
|
||||||
nm_log_info (LOGD_CORE, "Creating virtual devices");
|
nm_log_dbg (LOGD_CORE, "creating virtual devices...");
|
||||||
|
|
||||||
connections = nm_settings_get_connections (settings);
|
connections = nm_settings_get_connections (priv->settings);
|
||||||
for (iter = connections; iter; iter = g_slist_next (iter)) {
|
for (iter = connections; iter; iter = g_slist_next (iter)) {
|
||||||
NMConnection *connection = NM_CONNECTION (iter->data);
|
NMConnection *connection = iter->data;
|
||||||
|
NMSettingConnection *s_con = nm_connection_get_setting_connection (connection);
|
||||||
|
|
||||||
if (connection_needs_virtual_device (connection))
|
g_assert (s_con);
|
||||||
system_update_virtual_device (connection);
|
if (connection_needs_virtual_device (connection)) {
|
||||||
|
/* We only create a virtual interface if the connection can autoconnect */
|
||||||
|
if (nm_setting_connection_get_autoconnect (s_con))
|
||||||
|
system_create_virtual_device (self, connection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_slist_free (connections);
|
g_slist_free (connections);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -938,7 +1021,7 @@ connection_added (NMSettings *settings,
|
|||||||
bluez_manager_resync_devices (manager);
|
bluez_manager_resync_devices (manager);
|
||||||
|
|
||||||
if (connection_needs_virtual_device (NM_CONNECTION (connection)))
|
if (connection_needs_virtual_device (NM_CONNECTION (connection)))
|
||||||
system_update_virtual_device (NM_CONNECTION (connection));
|
system_create_virtual_device (manager, NM_CONNECTION (connection));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1540,6 +1623,11 @@ add_device (NMManager *self, NMDevice *device)
|
|||||||
nm_settings_device_added (priv->settings, device);
|
nm_settings_device_added (priv->settings, device);
|
||||||
g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
|
g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
|
||||||
|
|
||||||
|
/* New devices might be master interfaces for virtual interfaces; so we may
|
||||||
|
* need to create new virtual interfaces now.
|
||||||
|
*/
|
||||||
|
system_create_virtual_devices (self);
|
||||||
|
|
||||||
/* If the device has a connection it can assume, do that now */
|
/* If the device has a connection it can assume, do that now */
|
||||||
if (existing && managed && nm_device_is_available (device)) {
|
if (existing && managed && nm_device_is_available (device)) {
|
||||||
const char *ac_path;
|
const char *ac_path;
|
||||||
@@ -1937,8 +2025,13 @@ udev_device_added_cb (NMUdevManager *udev_mgr,
|
|||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
|
ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
|
||||||
if (find_device_by_ifindex (self, ifindex))
|
device = find_device_by_ifindex (self, ifindex);
|
||||||
|
if (device) {
|
||||||
|
/* If it's a virtual device we may need to update its UDI */
|
||||||
|
if (nm_system_get_iface_type (ifindex, iface) != NM_IFACE_TYPE_UNSPEC)
|
||||||
|
g_object_set (G_OBJECT (device), NM_DEVICE_UDI, sysfs_path, NULL);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Try registered device factories */
|
/* Try registered device factories */
|
||||||
for (iter = priv->factories; iter; iter = g_slist_next (iter)) {
|
for (iter = priv->factories; iter; iter = g_slist_next (iter)) {
|
||||||
@@ -3046,7 +3139,7 @@ nm_manager_start (NMManager *self)
|
|||||||
* Connections added before the manager is started do not emit
|
* Connections added before the manager is started do not emit
|
||||||
* connection-added signals thus devices have to be created manually.
|
* connection-added signals thus devices have to be created manually.
|
||||||
*/
|
*/
|
||||||
system_create_virtual_devices (priv->settings);
|
system_create_virtual_devices (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@@ -1281,34 +1281,30 @@ nm_system_apply_bonding_config (NMSettingBond *s_bond)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* nm_system_add_bonding_master:
|
* nm_system_add_bonding_master:
|
||||||
* @setting: bonding setting
|
* @iface: the interface name for the new bond master
|
||||||
*
|
*
|
||||||
* Adds a virtual bonding device if it does not exist yet.
|
* Adds a virtual bonding device if it does not exist yet.
|
||||||
*
|
*
|
||||||
* Returns: %TRUE on success, %FALSE on failure
|
* Returns: %TRUE on success, %FALSE on failure
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
nm_system_add_bonding_master (NMSettingBond *setting)
|
nm_system_add_bonding_master (const char *iface)
|
||||||
{
|
{
|
||||||
struct nl_sock *sock;
|
struct nl_sock *sock;
|
||||||
const char *name;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
g_return_val_if_fail (iface != NULL, FALSE);
|
||||||
|
|
||||||
sock = nm_netlink_get_default_handle ();
|
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 */
|
/* Existing bonding devices with matching name will be reused */
|
||||||
err = rtnl_link_bond_add (sock, name, NULL);
|
err = rtnl_link_bond_add (sock, iface, NULL);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
nm_log_err (LOGD_DEVICE, "(%s): error %d returned from "
|
nm_log_err (LOGD_DEVICE, "(%s): error %d returned from "
|
||||||
"rtnl_link_bond_add(): %s",
|
"rtnl_link_bond_add(): %s",
|
||||||
name, err, nl_geterror (err));
|
iface, err, nl_geterror (err));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nm_system_apply_bonding_config (setting);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -90,7 +90,7 @@ 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_iface_set_mac (int ifindex, const struct ether_addr *mac);
|
||||||
|
|
||||||
gboolean nm_system_apply_bonding_config (NMSettingBond *s_bond);
|
gboolean nm_system_apply_bonding_config (NMSettingBond *s_bond);
|
||||||
gboolean nm_system_add_bonding_master (NMSettingBond *setting);
|
gboolean nm_system_add_bonding_master (const char *iface);
|
||||||
gboolean nm_system_iface_enslave (NMDevice *slave, NMDevice *master);
|
gboolean nm_system_iface_enslave (NMDevice *slave, NMDevice *master);
|
||||||
gboolean nm_system_iface_release (NMDevice *slave, NMDevice *master);
|
gboolean nm_system_iface_release (NMDevice *slave, NMDevice *master);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user