platform: don't wait for udev before announcing links
This commit is contained in:
@@ -1615,6 +1615,17 @@ carrier_changed (NMDevice *device, gboolean carrier)
|
||||
NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->carrier_changed (device, carrier);
|
||||
}
|
||||
|
||||
static void
|
||||
link_changed (NMDevice *device, NMPlatformLink *info)
|
||||
{
|
||||
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
|
||||
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
|
||||
|
||||
NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->link_changed (device, info);
|
||||
if (!priv->subchan1 && info->udi)
|
||||
_update_s390_subchannels (self);
|
||||
}
|
||||
|
||||
static void
|
||||
dispose (GObject *object)
|
||||
{
|
||||
@@ -1714,6 +1725,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
|
||||
parent_class->spec_match_list = spec_match_list;
|
||||
parent_class->update_connection = update_connection;
|
||||
parent_class->carrier_changed = carrier_changed;
|
||||
parent_class->link_changed = link_changed;
|
||||
|
||||
parent_class->state_changed = device_state_changed;
|
||||
|
||||
|
@@ -176,6 +176,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
gboolean in_state_changed;
|
||||
gboolean initialized;
|
||||
gboolean platform_link_initialized;
|
||||
|
||||
NMDeviceState state;
|
||||
NMDeviceStateReason state_reason;
|
||||
@@ -1051,6 +1052,7 @@ void
|
||||
nm_device_finish_init (NMDevice *self)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
gboolean platform_unmanaged = FALSE;
|
||||
|
||||
g_assert (priv->initialized == FALSE);
|
||||
|
||||
@@ -1063,6 +1065,20 @@ nm_device_finish_init (NMDevice *self)
|
||||
if (priv->master)
|
||||
nm_device_enslave_slave (priv->master, self, NULL);
|
||||
|
||||
if (priv->ifindex > 0) {
|
||||
if (priv->platform_link_initialized || (priv->is_nm_owned && priv->is_software)) {
|
||||
nm_platform_link_get_unmanaged (NM_PLATFORM_GET, priv->ifindex, &platform_unmanaged);
|
||||
nm_device_set_initial_unmanaged_flag (self, NM_UNMANAGED_DEFAULT, platform_unmanaged);
|
||||
} else {
|
||||
/* Hardware and externally-created software links stay unmanaged
|
||||
* until they are fully initialized by the platform. NM created
|
||||
* links must be available for activation immediately and thus
|
||||
* do not get the PLATFORM_INIT unmanaged flag set.
|
||||
*/
|
||||
nm_device_set_initial_unmanaged_flag (self, NM_UNMANAGED_PLATFORM_INIT, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
priv->initialized = TRUE;
|
||||
}
|
||||
|
||||
@@ -1255,6 +1271,7 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
NMUtilsIPv6IfaceId token_iid;
|
||||
gboolean ip_ifname_changed = FALSE;
|
||||
gboolean platform_unmanaged = FALSE;
|
||||
|
||||
if (info->udi && g_strcmp0 (info->udi, priv->udi)) {
|
||||
/* Update UDI to what udev gives us */
|
||||
@@ -1263,6 +1280,13 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
|
||||
g_object_notify (G_OBJECT (self), NM_DEVICE_UDI);
|
||||
}
|
||||
|
||||
if (g_strcmp0 (info->driver, priv->driver)) {
|
||||
/* Update driver to what udev gives us */
|
||||
g_free (priv->driver);
|
||||
priv->driver = g_strdup (info->driver);
|
||||
g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER);
|
||||
}
|
||||
|
||||
/* Update MTU if it has changed. */
|
||||
if (priv->mtu != info->mtu) {
|
||||
priv->mtu = info->mtu;
|
||||
@@ -1355,6 +1379,22 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->ifindex > 0 && !priv->platform_link_initialized && info->initialized) {
|
||||
priv->platform_link_initialized = TRUE;
|
||||
|
||||
if (nm_platform_link_get_unmanaged (NM_PLATFORM_GET, priv->ifindex, &platform_unmanaged)) {
|
||||
nm_device_set_unmanaged (self,
|
||||
NM_UNMANAGED_DEFAULT,
|
||||
platform_unmanaged,
|
||||
NM_DEVICE_STATE_REASON_USER_REQUESTED);
|
||||
}
|
||||
|
||||
nm_device_set_unmanaged (self,
|
||||
NM_UNMANAGED_PLATFORM_INIT,
|
||||
FALSE,
|
||||
NM_DEVICE_STATE_REASON_NOW_MANAGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -7088,7 +7128,7 @@ nm_device_set_unmanaged (NMDevice *self,
|
||||
|
||||
if (unmanaged)
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_UNMANAGED, reason);
|
||||
else
|
||||
else if (nm_device_get_state (self) == NM_DEVICE_STATE_UNMANAGED)
|
||||
nm_device_state_changed (self, NM_DEVICE_STATE_UNAVAILABLE, reason);
|
||||
}
|
||||
}
|
||||
@@ -8716,6 +8756,7 @@ set_property (GObject *object, guint prop_id,
|
||||
priv->up = platform_device->up;
|
||||
g_free (priv->driver);
|
||||
priv->driver = g_strdup (platform_device->driver);
|
||||
priv->platform_link_initialized = platform_device->initialized;
|
||||
}
|
||||
break;
|
||||
case PROP_UDI:
|
||||
|
@@ -344,6 +344,8 @@ RfKillType nm_device_get_rfkill_type (NMDevice *device);
|
||||
* @NM_UNMANAGED_USER: %TRUE when unmanaged by user decision (via unmanaged-specs)
|
||||
* @NM_UNMANAGED_PARENT: %TRUE when unmanaged due to parent device being unmanaged
|
||||
* @NM_UNMANAGED_EXTERNAL_DOWN: %TRUE when unmanaged because !IFF_UP and not created by NM
|
||||
* @NM_UNMANAGED_PLATFORM_INIT: %TRUE when unmanaged because platform link not
|
||||
* yet initialized
|
||||
*/
|
||||
typedef enum {
|
||||
NM_UNMANAGED_NONE = 0x00,
|
||||
@@ -352,6 +354,7 @@ typedef enum {
|
||||
NM_UNMANAGED_USER = 0x04,
|
||||
NM_UNMANAGED_PARENT = 0x08,
|
||||
NM_UNMANAGED_EXTERNAL_DOWN = 0x10,
|
||||
NM_UNMANAGED_PLATFORM_INIT = 0x20,
|
||||
|
||||
/* Boundary value */
|
||||
__NM_UNMANAGED_LAST,
|
||||
|
@@ -1791,7 +1791,7 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume)
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
const char *iface, *driver, *type_desc;
|
||||
const GSList *unmanaged_specs;
|
||||
gboolean user_unmanaged, sleeping, platform_unmanaged;
|
||||
gboolean user_unmanaged, sleeping;
|
||||
gboolean enabled = FALSE;
|
||||
RfKillType rtype;
|
||||
GSList *iter, *remove = NULL;
|
||||
@@ -1871,9 +1871,6 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume)
|
||||
user_unmanaged = nm_device_spec_match_list (device, unmanaged_specs);
|
||||
nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_USER, user_unmanaged);
|
||||
|
||||
if (nm_platform_link_get_unmanaged (NM_PLATFORM_GET, nm_device_get_ifindex (device), &platform_unmanaged))
|
||||
nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_DEFAULT, platform_unmanaged);
|
||||
|
||||
sleeping = manager_sleeping (self);
|
||||
nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_INTERNAL, sleeping);
|
||||
|
||||
|
@@ -116,6 +116,7 @@ link_init (NMFakePlatformLink *device, int ifindex, int type, const char *name)
|
||||
device->link.type_name = type_to_type_name (type);
|
||||
device->link.driver = type_to_type_name (type);
|
||||
device->link.udi = device->udi = g_strdup_printf ("fake:%d", ifindex);
|
||||
device->link.initialized = TRUE;
|
||||
if (name)
|
||||
strcpy (device->link.name, name);
|
||||
switch (device->link.type) {
|
||||
|
@@ -887,19 +887,6 @@ type_to_string (NMLinkType type)
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_is_announceable (NMPlatform *platform, struct rtnl_link *rtnllink)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
|
||||
/* Hardware devices must be found by udev so rules get run and tags set */
|
||||
if (g_hash_table_lookup (priv->udev_devices,
|
||||
GINT_TO_POINTER (rtnl_link_get_ifindex (rtnllink))))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#define DEVTYPE_PREFIX "DEVTYPE="
|
||||
|
||||
static char *
|
||||
@@ -1058,15 +1045,17 @@ init_link (NMPlatform *platform, NMPlatformLink *info, struct rtnl_link *rtnllin
|
||||
udev_device = g_hash_table_lookup (priv->udev_devices, GINT_TO_POINTER (info->ifindex));
|
||||
if (udev_device) {
|
||||
info->driver = udev_get_driver (udev_device, info->ifindex);
|
||||
if (!info->driver)
|
||||
info->driver = g_intern_string (rtnl_link_get_type (rtnllink));
|
||||
if (!info->driver)
|
||||
info->driver = ethtool_get_driver (info->name);
|
||||
if (!info->driver)
|
||||
info->driver = "unknown";
|
||||
info->udi = g_udev_device_get_sysfs_path (udev_device);
|
||||
info->initialized = TRUE;
|
||||
}
|
||||
|
||||
if (!info->driver)
|
||||
info->driver = g_intern_string (rtnl_link_get_type (rtnllink));
|
||||
if (!info->driver)
|
||||
info->driver = ethtool_get_driver (info->name);
|
||||
if (!info->driver)
|
||||
info->driver = "unknown";
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -1624,22 +1613,6 @@ announce_object (NMPlatform *platform, const struct nl_object *object, NMPlatfor
|
||||
if (!init_link (platform, &device, rtnl_link))
|
||||
return;
|
||||
|
||||
/* Skip devices not yet discovered by udev. They will be
|
||||
* announced by udev_device_added(). This doesn't apply to removed
|
||||
* devices, as those come either from udev_device_removed(),
|
||||
* event_notification() or link_delete() which block the announcment
|
||||
* themselves when appropriate.
|
||||
*/
|
||||
switch (change_type) {
|
||||
case NM_PLATFORM_SIGNAL_ADDED:
|
||||
case NM_PLATFORM_SIGNAL_CHANGED:
|
||||
if (!device.driver)
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Link deletion or setting down is sometimes accompanied by address
|
||||
* and/or route deletion.
|
||||
*
|
||||
@@ -2067,15 +2040,12 @@ event_notification (struct nl_msg *msg, gpointer user_data)
|
||||
return NL_OK;
|
||||
|
||||
nl_cache_remove (cached_object);
|
||||
/* Don't announce removed interfaces that are not recognized by
|
||||
* udev. They were either not yet discovered or they have been
|
||||
* already removed and announced.
|
||||
*/
|
||||
if (event == RTM_DELLINK) {
|
||||
if (!link_is_announceable (platform, (struct rtnl_link *) cached_object))
|
||||
return NL_OK;
|
||||
}
|
||||
announce_object (platform, cached_object, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_EXTERNAL);
|
||||
if (event == RTM_DELLINK) {
|
||||
int ifindex = rtnl_link_get_ifindex ((struct rtnl_link *) cached_object);
|
||||
|
||||
g_hash_table_remove (priv->udev_devices, GINT_TO_POINTER (ifindex));
|
||||
}
|
||||
|
||||
return NL_OK;
|
||||
case RTM_NEWLINK:
|
||||
@@ -2303,12 +2273,8 @@ link_get_all (NMPlatform *platform)
|
||||
struct nl_object *object;
|
||||
|
||||
for (object = nl_cache_get_first (priv->link_cache); object; object = nl_cache_get_next (object)) {
|
||||
struct rtnl_link *rtnl_link = (struct rtnl_link *) object;
|
||||
|
||||
if (link_is_announceable (platform, rtnl_link)) {
|
||||
if (init_link (platform, &device, rtnl_link))
|
||||
g_array_append_val (links, device);
|
||||
}
|
||||
if (init_link (platform, &device, (struct rtnl_link *) object))
|
||||
g_array_append_val (links, device);
|
||||
}
|
||||
|
||||
return links;
|
||||
@@ -2321,13 +2287,7 @@ _nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *l)
|
||||
auto_nl_object struct rtnl_link *rtnllink = NULL;
|
||||
|
||||
rtnllink = rtnl_link_get (priv->link_cache, ifindex);
|
||||
if (rtnllink) {
|
||||
if (link_is_announceable (platform, rtnllink)) {
|
||||
if (init_link (platform, l, rtnllink))
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
return (rtnllink && init_link (platform, l, rtnllink));
|
||||
}
|
||||
|
||||
static struct nl_object *
|
||||
@@ -2386,13 +2346,6 @@ link_get (NMPlatform *platform, int ifindex)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* physical interfaces must be found by udev before they can be used */
|
||||
if (!link_is_announceable (platform, rtnllink)) {
|
||||
platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
|
||||
rtnl_link_put (rtnllink);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rtnllink;
|
||||
}
|
||||
|
||||
@@ -4432,7 +4385,6 @@ udev_device_added (NMPlatform *platform,
|
||||
auto_nl_object struct rtnl_link *rtnllink = NULL;
|
||||
const char *ifname;
|
||||
int ifindex;
|
||||
gboolean was_announceable = FALSE;
|
||||
|
||||
ifname = g_udev_device_get_name (udev_device);
|
||||
if (!ifname) {
|
||||
@@ -4457,15 +4409,15 @@ udev_device_added (NMPlatform *platform,
|
||||
}
|
||||
|
||||
rtnllink = rtnl_link_get (priv->link_cache, ifindex);
|
||||
if (rtnllink)
|
||||
was_announceable = link_is_announceable (platform, rtnllink);
|
||||
if (!rtnllink) {
|
||||
warning ("(%s): udev-add: interface not known via netlink; ignoring...", ifname);
|
||||
return;
|
||||
}
|
||||
|
||||
g_hash_table_insert (priv->udev_devices, GINT_TO_POINTER (ifindex),
|
||||
g_object_ref (udev_device));
|
||||
|
||||
/* Announce devices only if they also have been discovered via Netlink. */
|
||||
if (rtnllink && link_is_announceable (platform, rtnllink))
|
||||
announce_object (platform, (struct nl_object *) rtnllink, was_announceable ? NM_PLATFORM_SIGNAL_CHANGED : NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_EXTERNAL);
|
||||
announce_object (platform, (struct nl_object *) rtnllink, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_EXTERNAL);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -4473,9 +4425,7 @@ udev_device_removed (NMPlatform *platform,
|
||||
GUdevDevice *udev_device)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
auto_nl_object struct rtnl_link *rtnllink = NULL;
|
||||
int ifindex = 0;
|
||||
gboolean was_announceable = FALSE;
|
||||
|
||||
if (g_udev_device_get_property (udev_device, "IFINDEX"))
|
||||
ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
|
||||
@@ -4500,15 +4450,7 @@ udev_device_removed (NMPlatform *platform,
|
||||
if (ifindex <= 0)
|
||||
return;
|
||||
|
||||
rtnllink = rtnl_link_get (priv->link_cache, ifindex);
|
||||
if (rtnllink)
|
||||
was_announceable = link_is_announceable (platform, rtnllink);
|
||||
|
||||
g_hash_table_remove (priv->udev_devices, GINT_TO_POINTER (ifindex));
|
||||
|
||||
/* Announce device removal if it is no longer announceable. */
|
||||
if (was_announceable && !link_is_announceable (platform, rtnllink))
|
||||
announce_object (platform, (struct nl_object *) rtnllink, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_EXTERNAL);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -4553,8 +4495,6 @@ constructed (GObject *_object)
|
||||
NMPlatform *platform = NM_PLATFORM (_object);
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
const char *udev_subsys[] = { "net", NULL };
|
||||
GUdevEnumerator *enumerator;
|
||||
GList *devices, *iter;
|
||||
int channel_flags;
|
||||
gboolean status;
|
||||
int nle;
|
||||
@@ -4614,6 +4554,24 @@ constructed (GObject *_object)
|
||||
g_signal_connect (priv->udev_client, "uevent", G_CALLBACK (handle_udev_event), platform);
|
||||
priv->udev_devices = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
|
||||
|
||||
/* request all IPv6 addresses (hopeing that there is at least one), to check for
|
||||
* the IFA_FLAGS attribute. */
|
||||
nle = nl_rtgen_request (priv->nlh_event, RTM_GETADDR, AF_INET6, NLM_F_DUMP);
|
||||
if (nle < 0)
|
||||
nm_log_warn (LOGD_PLATFORM, "Netlink error: requesting RTM_GETADDR failed with %s", nl_geterror (nle));
|
||||
|
||||
priv->wifi_data = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) wifi_utils_deinit);
|
||||
|
||||
G_OBJECT_CLASS (nm_linux_platform_parent_class)->constructed (_object);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_devices (NMPlatform *platform)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
GUdevEnumerator *enumerator;
|
||||
GList *devices, *iter;
|
||||
|
||||
/* And read initial device list */
|
||||
enumerator = g_udev_enumerator_new (priv->udev_client);
|
||||
g_udev_enumerator_add_match_subsystem (enumerator, "net");
|
||||
@@ -4631,16 +4589,6 @@ constructed (GObject *_object)
|
||||
}
|
||||
g_list_free (devices);
|
||||
g_object_unref (enumerator);
|
||||
|
||||
/* request all IPv6 addresses (hopeing that there is at least one), to check for
|
||||
* the IFA_FLAGS attribute. */
|
||||
nle = nl_rtgen_request (priv->nlh_event, RTM_GETADDR, AF_INET6, NLM_F_DUMP);
|
||||
if (nle < 0)
|
||||
nm_log_warn (LOGD_PLATFORM, "Netlink error: requesting RTM_GETADDR failed with %s", nl_geterror (nle));
|
||||
|
||||
priv->wifi_data = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) wifi_utils_deinit);
|
||||
|
||||
G_OBJECT_CLASS (nm_linux_platform_parent_class)->constructed (_object);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -4678,6 +4626,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
|
||||
object_class->constructed = constructed;
|
||||
object_class->finalize = nm_linux_platform_finalize;
|
||||
|
||||
platform_class->setup_devices = setup_devices;
|
||||
|
||||
platform_class->sysctl_set = sysctl_set;
|
||||
platform_class->sysctl_get = sysctl_get;
|
||||
|
||||
|
@@ -405,6 +405,10 @@ nm_platform_query_devices (NMPlatform *self)
|
||||
NM_PLATFORM_REASON_INTERNAL);
|
||||
}
|
||||
g_array_unref (links_array);
|
||||
|
||||
/* Platform specific device setup. */
|
||||
if (klass->setup_devices)
|
||||
klass->setup_devices (self);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2608,6 +2612,12 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route)
|
||||
return (((a)->field) < ((b)->field)) ? -1 : 1; \
|
||||
} G_STMT_END
|
||||
|
||||
#define _CMP_FIELD_BOOL(a, b, field) \
|
||||
G_STMT_START { \
|
||||
if ((!((a)->field)) != (!((b)->field))) \
|
||||
return ((!((a)->field)) < (!((b)->field))) ? -1 : 1; \
|
||||
} G_STMT_END
|
||||
|
||||
#define _CMP_FIELD_STR(a, b, field) \
|
||||
G_STMT_START { \
|
||||
int c = strcmp ((a)->field, (b)->field); \
|
||||
@@ -2643,6 +2653,7 @@ nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b)
|
||||
_CMP_FIELD (a, b, arp);
|
||||
_CMP_FIELD (a, b, mtu);
|
||||
_CMP_FIELD_STR0 (a, b, type_name);
|
||||
_CMP_FIELD_BOOL (a, b, initialized);
|
||||
_CMP_FIELD_STR0 (a, b, udi);
|
||||
_CMP_FIELD_STR0 (a, b, driver);
|
||||
return 0;
|
||||
|
@@ -88,6 +88,7 @@ struct _NMPlatformLink {
|
||||
const char *type_name;
|
||||
const char *udi;
|
||||
const char *driver;
|
||||
gboolean initialized;
|
||||
int master;
|
||||
int parent;
|
||||
gboolean up;
|
||||
@@ -358,6 +359,8 @@ struct _NMPlatform {
|
||||
typedef struct {
|
||||
GObjectClass parent;
|
||||
|
||||
void (*setup_devices) (NMPlatform *);
|
||||
|
||||
gboolean (*sysctl_set) (NMPlatform *, const char *path, const char *value);
|
||||
char * (*sysctl_get) (NMPlatform *, const char *path);
|
||||
|
||||
|
Reference in New Issue
Block a user