core: create devices first and realize them later

Unrealized devices aren't backed by kernel resources and so won't know
all of their attributes.  That means three things:

1) they must update their attributes when they become realized
2) they must clear those attributes when unrealized
3) they must be looser in checking compatible connections until
they are realized

This requires that the setup() function be split into two parts, start & finish,
because finish must be run after add_device()

Also, we can simplify whether to pay attention to 'recheck-assume', which
is now dependent on priv->is_nm_owned, because the only case where NM should
*not* listen for the 'recheck-assume' signal is when the device is a
software device created by NM itself.  That logic was previously spread
across the callers of add_device() but is now consolidated into
nm-manager.c::device_realized() and nm-device.c::nm_device_create_and_realize().
This commit is contained in:
Dan Williams
2014-09-24 16:58:07 -05:00
committed by Thomas Haller
parent b7eb622c24
commit 4dbaac4ba2
13 changed files with 358 additions and 281 deletions

View File

@@ -97,7 +97,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
return FALSE; return FALSE;
mac_address = nm_setting_bridge_get_mac_address (s_bridge); mac_address = nm_setting_bridge_get_mac_address (s_bridge);
if (mac_address) { if (mac_address && nm_device_is_real (device)) {
const char *hw_addr; const char *hw_addr;
hw_addr = nm_device_get_hw_address (device); hw_addr = nm_device_get_hw_address (device);

View File

@@ -305,9 +305,9 @@ nm_device_ethernet_init (NMDeviceEthernet *self)
} }
static void static void
setup (NMDevice *device, NMPlatformLink *plink) setup_start (NMDevice *device, NMPlatformLink *plink)
{ {
NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->setup (device, plink); NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->setup_start (device, plink);
g_object_notify (G_OBJECT (device), NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS); g_object_notify (G_OBJECT (device), NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS);
} }
@@ -1716,7 +1716,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
object_class->set_property = set_property; object_class->set_property = set_property;
parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->get_generic_capabilities = get_generic_capabilities;
parent_class->setup = setup; parent_class->setup_start = setup_start;
parent_class->check_connection_compatible = check_connection_compatible; parent_class->check_connection_compatible = check_connection_compatible;
parent_class->complete_connection = complete_connection; parent_class->complete_connection = complete_connection;
parent_class->new_default_connection = new_default_connection; parent_class->new_default_connection = new_default_connection;

View File

@@ -61,13 +61,13 @@ get_type_description (NMDevice *device)
} }
static void static void
setup (NMDevice *device, NMPlatformLink *plink) setup_start (NMDevice *device, NMPlatformLink *plink)
{ {
NMDeviceGeneric *self = NM_DEVICE_GENERIC (device); NMDeviceGeneric *self = NM_DEVICE_GENERIC (device);
NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE (self); NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE (self);
int ifindex; int ifindex;
NM_DEVICE_CLASS (nm_device_generic_parent_class)->setup (device, plink); NM_DEVICE_CLASS (nm_device_generic_parent_class)->setup_start (device, plink);
g_clear_pointer (&priv->type_description, g_free); g_clear_pointer (&priv->type_description, g_free);
ifindex = nm_device_get_ip_ifindex (NM_DEVICE (self)); ifindex = nm_device_get_ip_ifindex (NM_DEVICE (self));
@@ -203,7 +203,7 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass)
object_class->get_property = get_property; object_class->get_property = get_property;
object_class->set_property = set_property; object_class->set_property = set_property;
parent_class->setup = setup; parent_class->setup_start = setup_start;
parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->get_generic_capabilities = get_generic_capabilities;
parent_class->get_type_description = get_type_description; parent_class->get_type_description = get_type_description;
parent_class->check_connection_compatible = check_connection_compatible; parent_class->check_connection_compatible = check_connection_compatible;

View File

@@ -149,7 +149,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
if (!s_infiniband) if (!s_infiniband)
return FALSE; return FALSE;
if (s_infiniband) { if (nm_device_is_real (device)) {
const char *mac; const char *mac;
mac = nm_setting_infiniband_get_mac_address (s_infiniband); mac = nm_setting_infiniband_get_mac_address (s_infiniband);

View File

@@ -503,6 +503,10 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
if (!s_ip_tunnel) if (!s_ip_tunnel)
return FALSE; return FALSE;
if (nm_setting_ip_tunnel_get_mode (s_ip_tunnel) != priv->mode)
return FALSE;
if (nm_device_is_real (device)) {
/* Check parent interface; could be an interface name or a UUID */ /* Check parent interface; could be an interface name or a UUID */
parent = nm_setting_ip_tunnel_get_parent (s_ip_tunnel); parent = nm_setting_ip_tunnel_get_parent (s_ip_tunnel);
if (parent) { if (parent) {
@@ -510,9 +514,6 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
return FALSE; return FALSE;
} }
if (nm_setting_ip_tunnel_get_mode (s_ip_tunnel) != priv->mode)
return FALSE;
if (!address_equal_pp (priv->addr_family, if (!address_equal_pp (priv->addr_family,
nm_setting_ip_tunnel_get_local (s_ip_tunnel), nm_setting_ip_tunnel_get_local (s_ip_tunnel),
priv->local)) priv->local))
@@ -539,6 +540,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
if (nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel) != priv->flow_label) if (nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel) != priv->flow_label)
return FALSE; return FALSE;
} }
}
return TRUE; return TRUE;
} }
@@ -751,9 +753,9 @@ create_and_realize (NMDevice *device,
} }
static void static void
setup (NMDevice *device, NMPlatformLink *plink) setup_start (NMDevice *device, NMPlatformLink *plink)
{ {
NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->setup (device, plink); NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->setup_start (device, plink);
update_properties (device); update_properties (device);
} }
@@ -847,7 +849,7 @@ nm_device_ip_tunnel_class_init (NMDeviceIPTunnelClass *klass)
device_class->check_connection_compatible = check_connection_compatible; device_class->check_connection_compatible = check_connection_compatible;
device_class->create_and_realize = create_and_realize; device_class->create_and_realize = create_and_realize;
device_class->realize = realize; device_class->realize = realize;
device_class->setup = setup; device_class->setup_start = setup_start;
device_class->unrealize = unrealize; device_class->unrealize = unrealize;
device_class->connection_type = NM_SETTING_IP_TUNNEL_SETTING_NAME; device_class->connection_type = NM_SETTING_IP_TUNNEL_SETTING_NAME;

View File

@@ -226,6 +226,13 @@ realize (NMDevice *device, NMPlatformLink *plink, GError **error)
return TRUE; return TRUE;
} }
static void
setup_start (NMDevice *device, NMPlatformLink *plink)
{
NM_DEVICE_CLASS (nm_device_tun_parent_class)->setup_start (device, plink);
reload_tun_properties (device);
}
static gboolean static gboolean
check_connection_compatible (NMDevice *device, NMConnection *connection) check_connection_compatible (NMDevice *device, NMConnection *connection)
{ {
@@ -235,8 +242,6 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
NMSettingTun *s_tun; NMSettingTun *s_tun;
gint64 user, group; gint64 user, group;
reload_tun_properties (self);
if (!NM_DEVICE_CLASS (nm_device_tun_parent_class)->check_connection_compatible (device, connection)) if (!NM_DEVICE_CLASS (nm_device_tun_parent_class)->check_connection_compatible (device, connection))
return FALSE; return FALSE;
@@ -244,6 +249,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
if (!s_tun) if (!s_tun)
return FALSE; return FALSE;
if (nm_device_is_real (device)) {
mode = tun_mode_from_string (priv->mode); mode = tun_mode_from_string (priv->mode);
if (mode != nm_setting_tun_get_mode (s_tun)) if (mode != nm_setting_tun_get_mode (s_tun))
return FALSE; return FALSE;
@@ -261,6 +267,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
return FALSE; return FALSE;
if (nm_setting_tun_get_multi_queue (s_tun) != priv->props.multi_queue) if (nm_setting_tun_get_multi_queue (s_tun) != priv->props.multi_queue)
return FALSE; return FALSE;
}
return TRUE; return TRUE;
} }
@@ -367,6 +374,7 @@ nm_device_tun_class_init (NMDeviceTunClass *klass)
device_class->check_connection_compatible = check_connection_compatible; device_class->check_connection_compatible = check_connection_compatible;
device_class->create_and_realize = create_and_realize; device_class->create_and_realize = create_and_realize;
device_class->realize = realize; device_class->realize = realize;
device_class->setup_start = setup_start;
device_class->unrealize = unrealize; device_class->unrealize = unrealize;
device_class->update_connection = update_connection; device_class->update_connection = update_connection;

View File

@@ -148,12 +148,12 @@ nm_device_vlan_set_parent (NMDeviceVlan *self, NMDevice *parent)
} }
static void static void
setup (NMDevice *device, NMPlatformLink *plink) setup_start (NMDevice *device, NMPlatformLink *plink)
{ {
NMDeviceVlan *self = NM_DEVICE_VLAN (device); NMDeviceVlan *self = NM_DEVICE_VLAN (device);
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
NM_DEVICE_CLASS (nm_device_vlan_parent_class)->setup (device, plink); NM_DEVICE_CLASS (nm_device_vlan_parent_class)->setup_start (device, plink);
_LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s", _LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s",
priv->vlan_id, nm_device_get_iface (priv->parent)); priv->vlan_id, nm_device_get_iface (priv->parent));
@@ -311,6 +311,9 @@ notify_new_device_added (NMDevice *device, NMDevice *new_device)
if (priv->parent) if (priv->parent)
return; return;
if (!nm_device_is_real (device))
return;
plnk = nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, nm_device_get_ifindex (device), &plink); plnk = nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, nm_device_get_ifindex (device), &plink);
if (!plnk) { if (!plnk) {
_LOGW (LOGD_VLAN, "failed to get VLAN interface info while checking added component."); _LOGW (LOGD_VLAN, "failed to get VLAN interface info while checking added component.");
@@ -397,6 +400,8 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
if (!s_vlan) if (!s_vlan)
return FALSE; return FALSE;
/* Before the device is realized some properties will not be set */
if (nm_device_is_real (device)) {
if (nm_setting_vlan_get_id (s_vlan) != priv->vlan_id) if (nm_setting_vlan_get_id (s_vlan) != priv->vlan_id)
return FALSE; return FALSE;
@@ -410,6 +415,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
if (!match_hwaddr (device, connection, TRUE)) if (!match_hwaddr (device, connection, TRUE))
return FALSE; return FALSE;
} }
}
/* Ensure the interface name matches. If not specified we assume a match /* Ensure the interface name matches. If not specified we assume a match
* since both the parent interface and the VLAN ID matched by the time we * since both the parent interface and the VLAN ID matched by the time we
@@ -672,7 +678,7 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass)
parent_class->create_and_realize = create_and_realize; parent_class->create_and_realize = create_and_realize;
parent_class->realize = realize; parent_class->realize = realize;
parent_class->setup = setup; parent_class->setup_start = setup_start;
parent_class->unrealize = unrealize; parent_class->unrealize = unrealize;
parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->get_generic_capabilities = get_generic_capabilities;
parent_class->bring_up = bring_up; parent_class->bring_up = bring_up;

View File

@@ -133,11 +133,11 @@ link_changed (NMDevice *device, NMPlatformLink *info)
} }
static void static void
setup (NMDevice *device, NMPlatformLink *plink) setup_start (NMDevice *device, NMPlatformLink *plink)
{ {
g_assert (plink->type == NM_LINK_TYPE_VXLAN); g_assert (plink->type == NM_LINK_TYPE_VXLAN);
NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->setup (device, plink); NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->setup_start (device, plink);
update_properties (device); update_properties (device);
} }
@@ -247,7 +247,7 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass)
object_class->get_property = get_property; object_class->get_property = get_property;
device_class->link_changed = link_changed; device_class->link_changed = link_changed;
device_class->setup = setup; device_class->setup_start = setup_start;
device_class->unrealize = unrealize; device_class->unrealize = unrealize;
/* properties */ /* properties */

View File

@@ -556,7 +556,7 @@ nm_device_get_iface (NMDevice *self)
int int
nm_device_get_ifindex (NMDevice *self) nm_device_get_ifindex (NMDevice *self)
{ {
g_return_val_if_fail (self != NULL, 0); g_return_val_if_fail (NM_IS_DEVICE (self), 0);
return NM_DEVICE_GET_PRIVATE (self)->ifindex; return NM_DEVICE_GET_PRIVATE (self)->ifindex;
} }
@@ -1152,8 +1152,7 @@ nm_device_release_one_slave (NMDevice *self, NMDevice *slave, gboolean configure
static gboolean static gboolean
can_unmanaged_external_down (NMDevice *self) can_unmanaged_external_down (NMDevice *self)
{ {
return nm_device_is_software (self) return nm_device_is_software (self) && !NM_DEVICE_GET_PRIVATE (self)->is_nm_owned;
&& !nm_device_get_is_nm_owned (self);
} }
/** /**
@@ -1385,12 +1384,19 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier)
} }
static void static void
device_set_master (NMDevice *self, int ifindex) device_recheck_slave_status (NMDevice *self, NMPlatformLink *plink)
{ {
NMDevice *master;
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
master = nm_manager_get_device_by_ifindex (nm_manager_get (), ifindex); g_return_if_fail (plink != NULL);
if (priv->enslaved && plink->master != nm_device_get_ifindex (priv->master))
nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
if (plink->master && !priv->enslaved) {
NMDevice *master;
master = nm_manager_get_device_by_ifindex (nm_manager_get (), plink->master);
if (master && NM_DEVICE_GET_CLASS (master)->enslave_slave) { if (master && NM_DEVICE_GET_CLASS (master)->enslave_slave) {
g_clear_object (&priv->master); g_clear_object (&priv->master);
priv->master = g_object_ref (master); priv->master = g_object_ref (master);
@@ -1400,8 +1406,9 @@ device_set_master (NMDevice *self, int ifindex)
nm_device_get_iface (master)); nm_device_get_iface (master));
} else { } else {
_LOGW (LOGD_DEVICE, "enslaved to unknown device %d %s", _LOGW (LOGD_DEVICE, "enslaved to unknown device %d %s",
ifindex, plink->master,
nm_platform_link_get_name (NM_PLATFORM_GET, ifindex)); nm_platform_link_get_name (NM_PLATFORM_GET, plink->master));
}
} }
} }
@@ -1449,6 +1456,12 @@ device_link_changed (NMDevice *self)
g_object_notify (G_OBJECT (self), NM_DEVICE_MTU); g_object_notify (G_OBJECT (self), NM_DEVICE_MTU);
} }
if (info.driver && g_strcmp0 (priv->driver, info.driver) != 0) {
g_free (priv->driver);
priv->driver = g_strdup (info.driver);
g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER);
}
if (info.name[0] && strcmp (priv->iface, info.name) != 0) { if (info.name[0] && strcmp (priv->iface, info.name) != 0) {
_LOGI (LOGD_DEVICE, "interface index %d renamed iface from '%s' to '%s'", _LOGI (LOGD_DEVICE, "interface index %d renamed iface from '%s' to '%s'",
priv->ifindex, priv->iface, info.name); priv->ifindex, priv->iface, info.name);
@@ -1471,15 +1484,6 @@ device_link_changed (NMDevice *self)
nm_device_emit_recheck_auto_activate (self); nm_device_emit_recheck_auto_activate (self);
} }
/* Update slave status for external changes */
if (priv->enslaved && info.master != nm_device_get_ifindex (priv->master))
nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
if (info.master && !priv->enslaved) {
device_set_master (self, info.master);
if (priv->master)
nm_device_enslave_slave (priv->master, self, NULL);
}
if (priv->rdisc && nm_platform_link_get_ipv6_token (NM_PLATFORM_GET, priv->ifindex, &token_iid)) { if (priv->rdisc && nm_platform_link_get_ipv6_token (NM_PLATFORM_GET, priv->ifindex, &token_iid)) {
_LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface); _LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface);
if (nm_rdisc_set_iid (priv->rdisc, token_iid)) if (nm_rdisc_set_iid (priv->rdisc, token_iid))
@@ -1562,6 +1566,7 @@ device_link_changed (NMDevice *self)
if (emit_link_initialized) if (emit_link_initialized)
g_signal_emit (self, signals[LINK_INITIALIZED], 0); g_signal_emit (self, signals[LINK_INITIALIZED], 0);
device_recheck_slave_status (self, &info);
return G_SOURCE_REMOVE; return G_SOURCE_REMOVE;
} }
@@ -1635,7 +1640,8 @@ link_changed (NMDevice *self, NMPlatformLink *info)
* @plink: an existing platform link or %NULL * @plink: an existing platform link or %NULL
* @error: location to store error, or %NULL * @error: location to store error, or %NULL
* *
* Initializes and sets up the device using existing backing resources. * Initializes and sets up the device using existing backing resources. Before
* the device is ready for use nm_device_setup_finish() must be called.
* *
* Returns: %TRUE on success, %FALSE on error * Returns: %TRUE on success, %FALSE on error
*/ */
@@ -1648,7 +1654,7 @@ nm_device_realize (NMDevice *self, NMPlatformLink *plink, GError **error)
return FALSE; return FALSE;
} }
NM_DEVICE_GET_CLASS (self)->setup (self, plink); NM_DEVICE_GET_CLASS (self)->setup_start (self, plink);
return TRUE; return TRUE;
} }
@@ -1671,15 +1677,20 @@ nm_device_create_and_realize (NMDevice *self,
NMDevice *parent, NMDevice *parent,
GError **error) GError **error)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMPlatformLink plink = { .type = NM_LINK_TYPE_UNKNOWN }; NMPlatformLink plink = { .type = NM_LINK_TYPE_UNKNOWN };
/* Must be set before device is realized */
priv->is_nm_owned = !nm_platform_link_get_by_ifname (NM_PLATFORM_GET, priv->iface);
/* Create any resources the device needs */ /* Create any resources the device needs */
if (NM_DEVICE_GET_CLASS (self)->create_and_realize) { if (NM_DEVICE_GET_CLASS (self)->create_and_realize) {
if (!NM_DEVICE_GET_CLASS (self)->create_and_realize (self, connection, parent, &plink, error)) if (!NM_DEVICE_GET_CLASS (self)->create_and_realize (self, connection, parent, &plink, error))
return FALSE; return FALSE;
} }
NM_DEVICE_GET_CLASS (self)->setup (self, (plink.type != NM_LINK_TYPE_UNKNOWN) ? &plink : NULL); NM_DEVICE_GET_CLASS (self)->setup_start (self, (plink.type != NM_LINK_TYPE_UNKNOWN) ? &plink : NULL);
nm_device_setup_finish (self, (plink.type != NM_LINK_TYPE_UNKNOWN) ? &plink : NULL);
g_return_val_if_fail (nm_device_check_connection_compatible (self, connection), TRUE); g_return_val_if_fail (nm_device_check_connection_compatible (self, connection), TRUE);
return TRUE; return TRUE;
@@ -1742,7 +1753,7 @@ check_carrier (NMDevice *self)
} }
static void static void
setup (NMDevice *self, NMPlatformLink *plink) setup_start (NMDevice *self, NMPlatformLink *plink)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
static guint32 id = 0; static guint32 id = 0;
@@ -1751,6 +1762,7 @@ setup (NMDevice *self, NMPlatformLink *plink)
g_return_if_fail (priv->ip_ifindex <= 0); g_return_if_fail (priv->ip_ifindex <= 0);
g_return_if_fail (priv->ip_iface == NULL); g_return_if_fail (priv->ip_iface == NULL);
/* Balanced by a thaw in nm_device_setup_finish() */
g_object_freeze_notify (G_OBJECT (self)); g_object_freeze_notify (G_OBJECT (self));
if (plink) { if (plink) {
@@ -1759,7 +1771,7 @@ setup (NMDevice *self, NMPlatformLink *plink)
} }
if (priv->ifindex > 0) { if (priv->ifindex > 0) {
_LOGD (LOGD_DEVICE, "setup(): %s, kernel ifindex %d", G_OBJECT_TYPE_NAME (self), priv->ifindex); _LOGD (LOGD_DEVICE, "setup_start(): %s, kernel ifindex %d", G_OBJECT_TYPE_NAME (self), priv->ifindex);
priv->physical_port_id = nm_platform_link_get_physical_port_id (NM_PLATFORM_GET, priv->ifindex); priv->physical_port_id = nm_platform_link_get_physical_port_id (NM_PLATFORM_GET, priv->ifindex);
g_object_notify (G_OBJECT (self), NM_DEVICE_PHYSICAL_PORT_ID); g_object_notify (G_OBJECT (self), NM_DEVICE_PHYSICAL_PORT_ID);
@@ -1844,17 +1856,29 @@ setup (NMDevice *self, NMPlatformLink *plink)
g_object_notify (G_OBJECT (self), NM_DEVICE_CAPABILITIES); g_object_notify (G_OBJECT (self), NM_DEVICE_CAPABILITIES);
/* Enslave ourselves */ priv->real = TRUE;
if (priv->ifindex > 0) {
int master = nm_platform_link_get_master (NM_PLATFORM_GET, priv->ifindex);
if (master > 0)
device_set_master (self, master);
} }
priv->real = TRUE; static void
setup_finish (NMDevice *self, NMPlatformLink *plink)
{
if (plink) {
update_device_from_platform_link (self, plink);
device_recheck_slave_status (self, plink);
}
}
void
nm_device_setup_finish (NMDevice *self, NMPlatformLink *plink)
{
NM_DEVICE_GET_CLASS (self)->setup_finish (self, plink);
NM_DEVICE_GET_PRIVATE (self)->real = TRUE;
g_object_notify (G_OBJECT (self), NM_DEVICE_REAL); g_object_notify (G_OBJECT (self), NM_DEVICE_REAL);
nm_device_recheck_available_connections (self);
/* Balanced by a freeze in setup_start() */
g_object_thaw_notify (G_OBJECT (self)); g_object_thaw_notify (G_OBJECT (self));
} }
@@ -2810,7 +2834,8 @@ nm_device_check_connection_compatible (NMDevice *self, NMConnection *connection)
static gboolean static gboolean
nm_device_can_assume_connections (NMDevice *self) nm_device_can_assume_connections (NMDevice *self)
{ {
return !!NM_DEVICE_GET_CLASS (self)->update_connection; return !!NM_DEVICE_GET_CLASS (self)->update_connection
&& !NM_DEVICE_GET_PRIVATE (self)->is_nm_owned;
} }
/** /**
@@ -6547,14 +6572,6 @@ nm_device_get_is_nm_owned (NMDevice *self)
return NM_DEVICE_GET_PRIVATE (self)->is_nm_owned; return NM_DEVICE_GET_PRIVATE (self)->is_nm_owned;
} }
void
nm_device_set_nm_owned (NMDevice *self)
{
g_return_if_fail (NM_IS_DEVICE (self));
NM_DEVICE_GET_PRIVATE (self)->is_nm_owned = TRUE;
}
/* /*
* delete_on_deactivate_link_delete * delete_on_deactivate_link_delete
* *
@@ -8461,6 +8478,7 @@ _nm_device_check_connection_available (NMDevice *self,
&& nm_device_get_unmanaged (self, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT)) && nm_device_get_unmanaged (self, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT))
return FALSE; return FALSE;
if ( state < NM_DEVICE_STATE_DISCONNECTED if ( state < NM_DEVICE_STATE_DISCONNECTED
&& !nm_device_is_software (self)
&& ( ( !NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER) && ( ( !NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)
&& !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) && !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE))
|| ( NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER) || ( NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)
@@ -10324,7 +10342,8 @@ nm_device_class_init (NMDeviceClass *klass)
klass->check_connection_compatible = check_connection_compatible; klass->check_connection_compatible = check_connection_compatible;
klass->check_connection_available = check_connection_available; klass->check_connection_available = check_connection_available;
klass->can_unmanaged_external_down = can_unmanaged_external_down; klass->can_unmanaged_external_down = can_unmanaged_external_down;
klass->setup = setup; klass->setup_start = setup_start;
klass->setup_finish = setup_finish;
klass->unrealize = unrealize; klass->unrealize = unrealize;
klass->is_up = is_up; klass->is_up = is_up;
klass->bring_up = bring_up; klass->bring_up = bring_up;

View File

@@ -174,14 +174,28 @@ typedef struct {
GError **error); GError **error);
/** /**
* setup(): * setup_start():
* @self: the #NMDevice * @self: the #NMDevice
* @plink: the #NMPlatformLink if backed by a kernel netdevice * @plink: the #NMPlatformLink if backed by a kernel netdevice
* *
* Update the device from backing resource properties (like hardware * Update the device from backing resource properties (like hardware
* addresses, carrier states, driver/firmware info, etc). * addresses, carrier states, driver/firmware info, etc). This function
* should only change properties for this device, and should not perform
* any tasks that affect other interfaces (like master/slave or parent/child
* stuff).
*/ */
void (*setup) (NMDevice *self, NMPlatformLink *plink); void (*setup_start) (NMDevice *self, NMPlatformLink *plink);
/**
* setup_finish():
* @self: the #NMDevice
* @plink: the #NMPlatformLink if backed by a kernel netdevice
*
* Update the device's master/slave or parent/child relationships from
* backing resource properties. After this function finishes, the device
* is ready for network connectivity.
*/
void (*setup_finish) (NMDevice *self, NMPlatformLink *plink);
/** /**
* unrealize(): * unrealize():
@@ -466,7 +480,6 @@ void nm_device_set_unmanaged_initial (NMDevice *device,
gboolean unmanaged); gboolean unmanaged);
gboolean nm_device_get_is_nm_owned (NMDevice *device); gboolean nm_device_get_is_nm_owned (NMDevice *device);
void nm_device_set_nm_owned (NMDevice *device);
gboolean nm_device_has_capability (NMDevice *self, NMDeviceCapabilities caps); gboolean nm_device_has_capability (NMDevice *self, NMDeviceCapabilities caps);
@@ -477,6 +490,8 @@ gboolean nm_device_create_and_realize (NMDevice *self,
NMConnection *connection, NMConnection *connection,
NMDevice *parent, NMDevice *parent,
GError **error); GError **error);
void nm_device_setup_finish (NMDevice *self,
NMPlatformLink *plink);
gboolean nm_device_unrealize (NMDevice *device, gboolean nm_device_unrealize (NMDevice *device,
gboolean remove_resources, gboolean remove_resources,
GError **error); GError **error);

View File

@@ -424,9 +424,9 @@ periodic_update_cb (gpointer user_data)
} }
static void static void
setup (NMDevice *device, NMPlatformLink *plink) setup_start (NMDevice *device, NMPlatformLink *plink)
{ {
NM_DEVICE_CLASS (nm_device_wifi_parent_class)->setup (device, plink); NM_DEVICE_CLASS (nm_device_wifi_parent_class)->setup_start (device, plink);
g_object_notify (G_OBJECT (device), NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS); g_object_notify (G_OBJECT (device), NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS);
} }
@@ -3040,7 +3040,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass)
object_class->dispose = dispose; object_class->dispose = dispose;
object_class->finalize = finalize; object_class->finalize = finalize;
parent_class->setup = setup; parent_class->setup_start = setup_start;
parent_class->bring_up = bring_up; parent_class->bring_up = bring_up;
parent_class->can_auto_connect = can_auto_connect; parent_class->can_auto_connect = can_auto_connect;
parent_class->is_available = is_available; parent_class->is_available = is_available;

View File

@@ -598,17 +598,17 @@ master_state_cb (NMActiveConnection *master,
gpointer user_data) gpointer user_data)
{ {
NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data); NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data);
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
NMActiveConnectionState master_state = nm_active_connection_get_state (master); NMActiveConnectionState master_state = nm_active_connection_get_state (master);
NMDevice *master_device = nm_active_connection_get_device (master);
check_master_ready (self); check_master_ready (self);
_LOGD ("master ActiveConnection [%p] state now '%s' (%d)", _LOGD ("master ActiveConnection [%p] state now '%s' (%d)",
master, state_to_string (master_state), master_state); master, state_to_string (master_state), master_state);
if ( master_state >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING if ( master_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATING
&& !priv->master_ready) { && (!master_device || !nm_device_is_real (master_device))) {
/* Master failed without ever creating its device */ /* Master failed without ever creating or realizing its device */
if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed) if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed)
NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed (self); NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed (self);
} }

View File

@@ -58,7 +58,7 @@
#include "nmdbus-manager.h" #include "nmdbus-manager.h"
#include "nmdbus-device.h" #include "nmdbus-device.h"
static void add_device (NMManager *self, NMDevice *device, gboolean try_assume); static void add_device (NMManager *self, NMDevice *device);
static NMActiveConnection *_new_active_connection (NMManager *self, static NMActiveConnection *_new_active_connection (NMManager *self,
NMConnection *connection, NMConnection *connection,
@@ -487,8 +487,11 @@ find_device_by_ip_iface (NMManager *self, const gchar *iface)
g_return_val_if_fail (iface != NULL, NULL); g_return_val_if_fail (iface != NULL, NULL);
for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = g_slist_next (iter)) { for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = g_slist_next (iter)) {
if (g_strcmp0 (nm_device_get_ip_iface (NM_DEVICE (iter->data)), iface) == 0) NMDevice *candidate = iter->data;
return NM_DEVICE (iter->data);
if ( nm_device_is_real (candidate)
&& g_strcmp0 (nm_device_get_ip_iface (candidate), iface) == 0)
return candidate;
} }
return NULL; return NULL;
} }
@@ -840,6 +843,8 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection)
NMDevice *parent, *first_compatible = NULL; NMDevice *parent, *first_compatible = NULL;
GSList *iter; GSList *iter;
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
factory = nm_device_factory_manager_find_factory_for_connection (connection); factory = nm_device_factory_manager_find_factory_for_connection (connection);
if (!factory) if (!factory)
return NULL; return NULL;
@@ -849,7 +854,7 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection)
return NULL; return NULL;
/* Try as an interface name */ /* Try as an interface name */
parent = find_device_by_ip_iface (self, parent_name); parent = find_device_by_iface (self, parent_name);
if (parent) if (parent)
return parent; return parent;
@@ -964,10 +969,9 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError
{ {
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMDeviceFactory *factory; NMDeviceFactory *factory;
GSList *iter; GSList *connections, *iter;
char *iface = NULL; gs_free char *iface = NULL;
NMDevice *device = NULL, *parent = NULL; NMDevice *device = NULL, *parent = NULL;
gboolean nm_owned = FALSE;
g_return_val_if_fail (NM_IS_MANAGER (self), NULL); g_return_val_if_fail (NM_IS_MANAGER (self), NULL);
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
@@ -989,7 +993,7 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError
NM_MANAGER_ERROR, NM_MANAGER_ERROR,
NM_MANAGER_ERROR_FAILED, NM_MANAGER_ERROR_FAILED,
"interface name '%s' already created", iface); "interface name '%s' already created", iface);
goto out; return NULL;
} }
} }
@@ -1003,79 +1007,61 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError
NM_MANAGER_ERROR_FAILED, NM_MANAGER_ERROR_FAILED,
"NetworkManager plugin for '%s' unavailable", "NetworkManager plugin for '%s' unavailable",
nm_connection_get_connection_type (connection)); nm_connection_get_connection_type (connection));
goto out; return NULL;
} }
nm_owned = !nm_platform_link_get_by_ifname (NM_PLATFORM_GET, iface);
device = nm_device_factory_create_device (factory, iface, NULL, connection, NULL, error); device = nm_device_factory_create_device (factory, iface, NULL, connection, NULL, error);
if (device) { if (!device)
if (!nm_device_create_and_realize (device, connection, parent, error)) { return NULL;
g_clear_object (&device);
goto out;
}
if (nm_owned) add_device (self, device);
nm_device_set_nm_owned (device);
/* If it was created by NM there's no connection to assume, but if it
* previously existed there might be one.
*/
add_device (self, device, !nm_owned);
/* Add device takes a reference that NMManager still owns, so it's /* Add device takes a reference that NMManager still owns, so it's
* safe to unref here and still return @device. * safe to unref here and still return @device.
*/ */
g_object_unref (device); g_object_unref (device);
/* Create backing resources if the device has any autoconnect connections */
connections = nm_settings_get_connections (priv->settings);
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMConnection *candidate = iter->data;
NMSettingConnection *s_con;
if (!nm_device_check_connection_compatible (device, candidate))
continue;
s_con = nm_connection_get_setting_connection (candidate);
g_assert (s_con);
if (!nm_setting_connection_get_autoconnect (s_con))
continue;
/* Create any backing resources the device needs */
if (!nm_device_create_and_realize (device, connection, parent, error)) {
remove_device (self, device, FALSE, TRUE);
device = NULL;
}
break;
} }
out:
g_free (iface);
return device; return device;
} }
static void
system_create_virtual_devices (NMManager *self)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GSList *iter, *connections;
nm_log_dbg (LOGD_CORE, "creating virtual devices...");
connections = nm_settings_get_connections (priv->settings);
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMConnection *connection = iter->data;
/* We only create a virtual interface if the connection can autoconnect */
if ( nm_connection_is_virtual (connection)
&& nm_settings_connection_can_autoconnect (NM_SETTINGS_CONNECTION (connection)))
system_create_virtual_device (self, connection, NULL);
}
g_slist_free (connections);
}
static void static void
connection_added (NMSettings *settings, connection_added (NMSettings *settings,
NMSettingsConnection *settings_connection, NMConnection *connection,
NMManager *manager) NMManager *manager)
{ {
NMConnection *connection = NM_CONNECTION (settings_connection); if (nm_connection_is_virtual (connection))
if (nm_connection_is_virtual (connection)) {
NMSettingConnection *s_con = nm_connection_get_setting_connection (connection);
g_assert (s_con);
if (nm_setting_connection_get_autoconnect (s_con))
system_create_virtual_device (manager, connection, NULL); system_create_virtual_device (manager, connection, NULL);
} }
}
static void static void
connection_changed (NMSettings *settings, connection_changed (NMSettings *settings,
NMSettingsConnection *connection, NMConnection *connection,
NMManager *manager) NMManager *manager)
{ {
/* FIXME: Some virtual devices may need to be updated in the future. */ if (nm_connection_is_virtual (connection))
system_create_virtual_device (manager, connection, NULL);
} }
static void static void
@@ -1590,17 +1576,25 @@ assume_connection (NMManager *self, NMDevice *device, NMSettingsConnection *conn
return TRUE; return TRUE;
} }
static gboolean
can_start_device (NMManager *self, NMDevice *device)
{
return nm_device_is_real (device)
&& !manager_sleeping (self)
&& !nm_device_get_unmanaged (device, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT);
}
static gboolean static gboolean
recheck_assume_connection (NMDevice *device, gpointer user_data) recheck_assume_connection (NMDevice *device, gpointer user_data)
{ {
NMManager *self = NM_MANAGER (user_data); NMManager *self = NM_MANAGER (user_data);
NMSettingsConnection *connection; NMSettingsConnection *connection;
gboolean was_unmanaged = FALSE, success, generated; gboolean was_unmanaged = FALSE, success, generated = FALSE;
NMDeviceState state; NMDeviceState state;
if (manager_sleeping (self)) g_return_val_if_fail (!nm_device_get_is_nm_owned (device), FALSE);
return FALSE;
if (nm_device_get_unmanaged (device, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT)) if (!can_start_device (self, device))
return FALSE; return FALSE;
state = nm_device_get_state (device); state = nm_device_get_state (device);
@@ -1671,26 +1665,51 @@ device_ip_iface_changed (NMDevice *device,
} }
} }
static void
device_realized (NMDevice *device,
GParamSpec *pspec,
NMManager *self)
{
int ifindex;
gboolean assumed = FALSE;
/* Loopback device never gets managed */
ifindex = nm_device_get_ifindex (device);
if (ifindex > 0 && nm_platform_link_get_type (NM_PLATFORM_GET, ifindex) == NM_LINK_TYPE_LOOPBACK)
return;
if (!can_start_device (self, device))
return;
if (!nm_device_get_is_nm_owned (device)) {
assumed = recheck_assume_connection (device, self);
g_signal_connect (device, NM_DEVICE_RECHECK_ASSUME,
G_CALLBACK (recheck_assume_connection), self);
}
if (!assumed && nm_device_get_managed (device)) {
nm_device_state_changed (device,
NM_DEVICE_STATE_UNAVAILABLE,
NM_DEVICE_STATE_REASON_NOW_MANAGED);
}
}
/** /**
* add_device: * add_device:
* @self: the #NMManager * @self: the #NMManager
* @device: the #NMDevice to add * @device: the #NMDevice to add
* @try_assume: %TRUE if existing connection (if any) should be assumed
* *
* If successful, this function will increase the references count of @device. * If successful, this function will increase the references count of @device.
* Callers should decrease the reference count. * Callers should decrease the reference count.
*/ */
static void static void
add_device (NMManager *self, NMDevice *device, gboolean try_assume) add_device (NMManager *self, NMDevice *device)
{ {
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
const char *iface, *driver, *type_desc; const char *iface, *type_desc;
const GSList *unmanaged_specs; const GSList *unmanaged_specs;
gboolean user_unmanaged, sleeping;
gboolean enabled = FALSE;
RfKillType rtype; RfKillType rtype;
GSList *iter, *remove = NULL; GSList *iter, *remove = NULL;
gboolean connection_assumed = FALSE;
int ifindex; int ifindex;
const char *dbus_path; const char *dbus_path;
@@ -1738,6 +1757,9 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume)
g_signal_connect (device, "notify::" NM_DEVICE_IP_IFACE, g_signal_connect (device, "notify::" NM_DEVICE_IP_IFACE,
G_CALLBACK (device_ip_iface_changed), G_CALLBACK (device_ip_iface_changed),
self); self);
g_signal_connect (device, "notify::" NM_DEVICE_REAL,
G_CALLBACK (device_realized),
self);
if (priv->startup) { if (priv->startup) {
g_signal_connect (device, "notify::" NM_DEVICE_HAS_PENDING_ACTION, g_signal_connect (device, "notify::" NM_DEVICE_HAS_PENDING_ACTION,
@@ -1752,52 +1774,29 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume)
rtype = nm_device_get_rfkill_type (device); rtype = nm_device_get_rfkill_type (device);
if (rtype != RFKILL_TYPE_UNKNOWN) { if (rtype != RFKILL_TYPE_UNKNOWN) {
nm_manager_rfkill_update (self, rtype); nm_manager_rfkill_update (self, rtype);
enabled = radio_enabled_for_type (self, rtype, TRUE); nm_device_set_enabled (device, radio_enabled_for_type (self, rtype, TRUE));
nm_device_set_enabled (device, enabled);
} }
iface = nm_device_get_iface (device); iface = nm_device_get_iface (device);
g_assert (iface); g_assert (iface);
type_desc = nm_device_get_type_desc (device); type_desc = nm_device_get_type_desc (device);
g_assert (type_desc); g_assert (type_desc);
driver = nm_device_get_driver (device);
if (!driver) nm_log_info (LOGD_HW, "(%s): new %s device", iface, type_desc);
driver = "unknown";
nm_log_info (LOGD_HW, "(%s): new %s device (carrier: %s, driver: '%s', ifindex: %d)",
iface, type_desc,
nm_device_has_capability (device, NM_DEVICE_CAP_CARRIER_DETECT)
? (nm_device_has_carrier (device) ? "ON" : "OFF")
: "UNKNOWN",
driver, nm_device_get_ifindex (device));
unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings); unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
user_unmanaged = nm_device_spec_match_list (device, unmanaged_specs); nm_device_set_unmanaged_initial (device,
nm_device_set_unmanaged_initial (device, NM_UNMANAGED_USER, user_unmanaged); NM_UNMANAGED_USER,
nm_device_spec_match_list (device, unmanaged_specs));
sleeping = manager_sleeping (self); nm_device_set_unmanaged_initial (device,
nm_device_set_unmanaged_initial (device, NM_UNMANAGED_INTERNAL, sleeping); NM_UNMANAGED_INTERNAL,
manager_sleeping (self));
dbus_path = nm_exported_object_export (NM_EXPORTED_OBJECT (device)); dbus_path = nm_exported_object_export (NM_EXPORTED_OBJECT (device));
nm_log_dbg (LOGD_DEVICE, "(%s): exported as %s", nm_device_get_iface (device), dbus_path); nm_log_dbg (LOGD_DEVICE, "(%s): exported as %s", nm_device_get_iface (device), dbus_path);
nm_device_finish_init (device); nm_device_finish_init (device);
if (try_assume) {
connection_assumed = recheck_assume_connection (device, self);
g_signal_connect (device, NM_DEVICE_RECHECK_ASSUME,
G_CALLBACK (recheck_assume_connection), self);
}
if (!connection_assumed && nm_device_get_managed (device)) {
nm_device_state_changed (device,
NM_DEVICE_STATE_UNAVAILABLE,
NM_DEVICE_STATE_REASON_NOW_MANAGED);
}
/* Try to generate a default connection. If this fails because the link is
* not initialized, we will retry again in device_link_initialized_cb().
*/
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);
g_object_notify (G_OBJECT (self), NM_MANAGER_DEVICES); g_object_notify (G_OBJECT (self), NM_MANAGER_DEVICES);
@@ -1808,11 +1807,6 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume)
if (d != device) if (d != device)
nm_device_notify_new_device_added (d, device); nm_device_notify_new_device_added (d, 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);
} }
/*******************************************************************/ /*******************************************************************/
@@ -1824,9 +1818,10 @@ factory_device_added_cb (NMDeviceFactory *factory,
{ {
GError *error = NULL; GError *error = NULL;
if (nm_device_realize (device, NULL, &error)) if (nm_device_realize (device, NULL, &error)) {
add_device (NM_MANAGER (user_data), device, TRUE); add_device (NM_MANAGER (user_data), device);
else { nm_device_setup_finish (device, NULL);
} else {
nm_log_warn (LOGD_DEVICE, "(%s): failed to realize device: %s", nm_log_warn (LOGD_DEVICE, "(%s): failed to realize device: %s",
nm_device_get_iface (device), error->message); nm_device_get_iface (device), error->message);
g_error_free (error); g_error_free (error);
@@ -1881,6 +1876,26 @@ platform_link_added (NMManager *self,
if (nm_manager_get_device_by_ifindex (self, ifindex)) if (nm_manager_get_device_by_ifindex (self, ifindex))
return; return;
device = find_device_by_iface (self, plink->name);
if (device) {
if (!nm_device_is_real (device)) {
if (nm_device_realize (device, plink, &error))
nm_device_setup_finish (device, plink);
else {
nm_log_warn (LOGD_DEVICE, "(%s): %s", plink->name, error->message);
g_clear_error (&error);
remove_device (self, device, FALSE, FALSE);
}
return;
} else if (!nm_device_realize (device, plink, &error)) {
nm_log_warn (LOGD_HW, "%s: factory failed to create device: %s",
plink->name, error->message);
g_clear_error (&error);
return;
}
return;
}
/* Try registered device factories */ /* Try registered device factories */
factory = nm_device_factory_manager_find_factory_for_link_type (plink->type); factory = nm_device_factory_manager_find_factory_for_link_type (plink->type);
if (factory) { if (factory) {
@@ -1917,10 +1932,11 @@ platform_link_added (NMManager *self,
if (device) { if (device) {
if (nm_plugin_missing) if (nm_plugin_missing)
nm_device_set_nm_plugin_missing (device, TRUE); nm_device_set_nm_plugin_missing (device, TRUE);
if (nm_device_realize (device, plink, &error)) if (nm_device_realize (device, plink, &error)) {
add_device (self, device, plink->type != NM_LINK_TYPE_LOOPBACK); add_device (self, device);
else { nm_device_setup_finish (device, plink);
nm_log_warn (LOGD_HW, "%s: failed to realize device: %s", } else {
nm_log_warn (LOGD_DEVICE, "%s: failed to realize device: %s",
plink->name, error->message); plink->name, error->message);
g_clear_error (&error); g_clear_error (&error);
} }
@@ -1954,18 +1970,22 @@ _platform_link_cb_idle (PlatformLinkCbData *data)
device = nm_manager_get_device_by_ifindex (self, data->ifindex); device = nm_manager_get_device_by_ifindex (self, data->ifindex);
if (device) { if (device) {
if (nm_device_is_software (device)) { if (nm_device_is_software (device)) {
/* Software devices stick around until their connection is removed */
if (!nm_device_unrealize (device, FALSE, &error)) { if (!nm_device_unrealize (device, FALSE, &error)) {
nm_log_warn (LOGD_DEVICE, "(%s): failed to unrealize: %s", nm_log_warn (LOGD_DEVICE, "(%s): failed to unrealize: %s",
nm_device_get_iface (device), nm_device_get_iface (device),
error->message); error->message);
g_clear_error (&error); g_clear_error (&error);
remove_device (self, device, FALSE, TRUE);
} }
} } else {
/* Hardware devices always get removed when their kernel link is gone */
remove_device (self, device, FALSE, TRUE); remove_device (self, device, FALSE, TRUE);
} }
} }
g_object_remove_weak_pointer (G_OBJECT (self), (gpointer *) &data->self); g_object_remove_weak_pointer (G_OBJECT (self), (gpointer *) &data->self);
} }
}
g_slice_free (PlatformLinkCbData, data); g_slice_free (PlatformLinkCbData, data);
return G_SOURCE_REMOVE; return G_SOURCE_REMOVE;
} }
@@ -2079,7 +2099,8 @@ impl_manager_get_devices (NMManager *self,
const char *path; const char *path;
path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (iter->data)); path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (iter->data));
if (path) if ( path
&& nm_device_is_real (iter->data))
paths[i++] = path; paths[i++] = path;
} }
paths[i++] = NULL; paths[i++] = NULL;
@@ -2181,7 +2202,7 @@ find_master (NMManager *self,
const char *master; const char *master;
NMDevice *master_device = NULL; NMDevice *master_device = NULL;
NMSettingsConnection *master_connection = NULL; NMSettingsConnection *master_connection = NULL;
GSList *iter, *connections = NULL; GSList *iter;
s_con = nm_connection_get_setting_connection (connection); s_con = nm_connection_get_setting_connection (connection);
g_assert (s_con); g_assert (s_con);
@@ -2191,7 +2212,7 @@ find_master (NMManager *self,
return TRUE; /* success, but no master */ return TRUE; /* success, but no master */
/* Try as an interface name first */ /* Try as an interface name first */
master_device = find_device_by_ip_iface (self, master); master_device = find_device_by_iface (self, master);
if (master_device) { if (master_device) {
if (master_device == device) { if (master_device == device) {
g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED,
@@ -2223,23 +2244,6 @@ find_master (NMManager *self,
break; break;
} }
} }
} else {
/* Might be a virtual interface that hasn't been created yet, so
* look through the interface names of connections that require
* virtual interfaces and see if one of their virtual interface
* names matches the master.
*/
connections = nm_manager_get_activatable_connections (self);
for (iter = connections; iter && !master_connection; iter = g_slist_next (iter)) {
NMSettingsConnection *candidate = iter->data;
char *vname;
vname = get_virtual_iface_name (self, NM_CONNECTION (candidate), NULL, NULL);
if (g_strcmp0 (master, vname) == 0 && is_compatible_with_slave (NM_CONNECTION (candidate), connection))
master_connection = candidate;
g_free (vname);
}
g_slist_free (connections);
} }
} }
@@ -2333,7 +2337,7 @@ ensure_master_active_connection (NMManager *self,
/* If the device is disconnected, find a compatible connection and /* If the device is disconnected, find a compatible connection and
* activate it on the device. * activate it on the device.
*/ */
if (master_state == NM_DEVICE_STATE_DISCONNECTED) { if (master_state == NM_DEVICE_STATE_DISCONNECTED || !nm_device_is_real (master_device)) {
GSList *connections; GSList *connections;
g_assert (master_connection == NULL); g_assert (master_connection == NULL);
@@ -2394,9 +2398,11 @@ ensure_master_active_connection (NMManager *self,
continue; continue;
found_device = TRUE; found_device = TRUE;
if (!nm_device_is_software (candidate)) {
master_state = nm_device_get_state (candidate); master_state = nm_device_get_state (candidate);
if (master_state != NM_DEVICE_STATE_DISCONNECTED) if (nm_device_is_real (candidate) && master_state != NM_DEVICE_STATE_DISCONNECTED)
continue; continue;
}
master_ac = nm_manager_activate_connection (self, master_ac = nm_manager_activate_connection (self,
master_connection, master_connection,
@@ -2683,6 +2689,17 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
return FALSE; return FALSE;
} }
/* Create any backing resources the device needs */
if (!nm_device_is_real (device)) {
NMDevice *parent;
parent = find_parent_device_for_connection (self, (NMConnection *) connection);
if (!nm_device_create_and_realize (device, (NMConnection *) connection, parent, error)) {
g_prefix_error (error, "%s failed to create resources: ", nm_device_get_iface (device));
return FALSE;
}
}
/* Try to find the master connection/device if the connection has a dependency */ /* Try to find the master connection/device if the connection has a dependency */
if (!find_master (self, applied, device, if (!find_master (self, applied, device,
&master_connection, &master_device, &master_ac, &master_connection, &master_device, &master_ac,
@@ -3086,7 +3103,7 @@ validate_activation_request (NMManager *self,
if (!iface) if (!iface)
goto error; goto error;
device = find_device_by_ip_iface (self, iface); device = find_device_by_iface (self, iface);
g_free (iface); g_free (iface);
} }
} }
@@ -4209,6 +4226,7 @@ gboolean
nm_manager_start (NMManager *self, GError **error) nm_manager_start (NMManager *self, GError **error)
{ {
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GSList *iter, *connections;
guint i; guint i;
if (!nm_settings_start (priv->settings, error)) if (!nm_settings_start (priv->settings, error))
@@ -4256,11 +4274,14 @@ nm_manager_start (NMManager *self, GError **error)
/* Load VPN plugins */ /* Load VPN plugins */
priv->vpn_manager = g_object_ref (nm_vpn_manager_get ()); priv->vpn_manager = g_object_ref (nm_vpn_manager_get ());
/* /* 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 (self); nm_log_dbg (LOGD_CORE, "creating virtual devices...");
connections = nm_settings_get_connections (priv->settings);
for (iter = connections; iter; iter = iter->next)
connection_added (priv->settings, NM_CONNECTION (iter->data), self);
g_slist_free (connections);
priv->devices_inited = TRUE; priv->devices_inited = TRUE;
@@ -5067,6 +5088,12 @@ nm_manager_init (NMManager *manager)
priv->metered = NM_METERED_UNKNOWN; priv->metered = NM_METERED_UNKNOWN;
} }
static gboolean
device_is_real (GObject *device, gpointer user_data)
{
return nm_device_is_real (NM_DEVICE (device));
}
static void static void
get_property (GObject *object, guint prop_id, get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec) GValue *value, GParamSpec *pspec)
@@ -5139,7 +5166,7 @@ get_property (GObject *object, guint prop_id,
g_value_set_boolean (value, priv->sleeping); g_value_set_boolean (value, priv->sleeping);
break; break;
case PROP_DEVICES: case PROP_DEVICES:
nm_utils_g_value_set_object_path_array (value, priv->devices, NULL, NULL); nm_utils_g_value_set_object_path_array (value, priv->devices, device_is_real, NULL);
break; break;
case PROP_METERED: case PROP_METERED:
g_value_set_uint (value, priv->metered); g_value_set_uint (value, priv->metered);