core, libnm: expose the reason for unmanaged devices

A common source for doubts and questions from users is about why
devices are unmanaged. Unfortunately NM doesn't expose that
information properly via D-Bus and so it's not available in nmcli.

The device D-Bus object has two properties that are strictly related:
"state" and "state-reason". The latter represents the reason for the
current state. Introduce new reasons to indicate the possible causes
for the unmanaged state. Note that a device can be unmanaged because
of multiple reasons at the same time, we only return one.

Before:

  $ nmcli -f GENERAL.DEVICE,GENERAL.TYPE,GENERAL.STATE,GENERAL.reason device show

  GENERAL.DEVICE:                         enp7s0
  GENERAL.TYPE:                           ethernet
  GENERAL.STATE:                          10 (unmanaged)
  GENERAL.REASON:                         0 (No reason given)

  GENERAL.DEVICE:                         tun0
  GENERAL.TYPE:                           tun
  GENERAL.STATE:                          10 (unmanaged)
  GENERAL.REASON:                         0 (No reason given)

  GENERAL.DEVICE:                         hwsim0
  GENERAL.TYPE:                           unknown
  GENERAL.STATE:                          10 (unmanaged)
  GENERAL.REASON:                         0 (No reason given)

After:

  $ nmcli -f GENERAL.DEVICE,GENERAL.TYPE,GENERAL.STATE,GENERAL.reason device show

  GENERAL.DEVICE:                         enp7s0
  GENERAL.TYPE:                           ethernet
  GENERAL.STATE:                          10 (unmanaged)
  GENERAL.REASON:                         76 (The device is unmanaged by user decision via settings plugin ("unmanaged-devices" for keyfile or "NM_CONTROLLED=no" for ifcfg-rh))

  GENERAL.DEVICE:                         tun0
  GENERAL.TYPE:                           tun
  GENERAL.STATE:                          10 (unmanaged)
  GENERAL.REASON:                         75 (The device is unmanaged by explicit user decision (e.g. 'nmcli device set $DEV managed no')

  GENERAL.DEVICE:                         hwsim0
  GENERAL.TYPE:                           unknown
  GENERAL.STATE:                          10 (unmanaged)
  GENERAL.REASON:                         69 (The device is unmanaged because the device type is unmanaged by default)

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1887
This commit is contained in:
Beniamino Galvani 2024-03-08 19:29:36 +01:00 committed by Fernando Fernandez Mancera
parent 7d5b4d0b62
commit 6af2fb351c
5 changed files with 128 additions and 9 deletions

3
NEWS
View file

@ -10,6 +10,9 @@ USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE!
* Support changing the OpenSSL ciphers for 802.1X authentication via
connection property "802-1x.openssl-ciphers".
* The reason why a device is unmanaged is now properly set in the
"StateReason" property of the "Device" D-Bus object. The property is
visible in nmcli via "nmcli -f all device show $DEV".
=============================================
NetworkManager-1.46

View file

@ -128,8 +128,20 @@ NM_UTILS_LOOKUP_STR_DEFINE(
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED,
"sriov-configuration-failed"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PEER_NOT_FOUND, "peer-not-found"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DEVICE_HANDLER_FAILED,
"device-handler-failed"), );
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DEVICE_HANDLER_FAILED, "device-handler-failed"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_BY_DEFAULT, "unmanaged-by-default"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_EXTERNAL_DOWN,
"unmanaged-external-down"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_LINK_NOT_INIT,
"unmanaged-link-not-init"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_QUITTING, "unmanaged-quitting"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_SLEEPING, "unmanaged-sleeping"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_CONF, "unmanaged-user-conf"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_EXPLICIT,
"unmanaged-user-explicit"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_SETTINGS,
"unmanaged-user-settings"),
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_UDEV, "unmanaged-user-udev"), );
NM_UTILS_LOOKUP_STR_DEFINE(nm_device_mtu_source_to_string,
NMDeviceMtuSource,

View file

@ -15008,8 +15008,39 @@ _unmanaged_flags2str(NMUnmanagedFlags flags, NMUnmanagedFlags mask, char *buf, g
return buf;
}
static NMDeviceStateReason
unmanaged_flags_to_reason(NMUnmanagedFlags flags)
{
/* Even if there are multiple flags, we can only return one reason.
* Return the most important reason.
*/
if (NM_FLAGS_HAS(flags, NM_UNMANAGED_SLEEPING))
return NM_DEVICE_STATE_REASON_UNMANAGED_SLEEPING;
if (NM_FLAGS_HAS(flags, NM_UNMANAGED_QUITTING))
return NM_DEVICE_STATE_REASON_UNMANAGED_QUITTING;
if (NM_FLAGS_HAS(flags, NM_UNMANAGED_USER_SETTINGS))
return NM_DEVICE_STATE_REASON_UNMANAGED_USER_SETTINGS;
if (NM_FLAGS_HAS(flags, NM_UNMANAGED_PLATFORM_INIT))
return NM_DEVICE_STATE_REASON_UNMANAGED_LINK_NOT_INIT;
if (NM_FLAGS_HAS(flags, NM_UNMANAGED_USER_UDEV))
return NM_DEVICE_STATE_REASON_UNMANAGED_USER_UDEV;
if (NM_FLAGS_HAS(flags, NM_UNMANAGED_USER_EXPLICIT))
return NM_DEVICE_STATE_REASON_UNMANAGED_USER_EXPLICIT;
if (NM_FLAGS_HAS(flags, NM_UNMANAGED_USER_CONF))
return NM_DEVICE_STATE_REASON_UNMANAGED_USER_CONF;
if (NM_FLAGS_HAS(flags, NM_UNMANAGED_BY_DEFAULT))
return NM_DEVICE_STATE_REASON_UNMANAGED_BY_DEFAULT;
if (NM_FLAGS_HAS(flags, NM_UNMANAGED_EXTERNAL_DOWN))
return NM_DEVICE_STATE_REASON_UNMANAGED_EXTERNAL_DOWN;
return NM_DEVICE_STATE_REASON_NOW_UNMANAGED;
}
static gboolean
_get_managed_by_flags(NMUnmanagedFlags flags, NMUnmanagedFlags mask, gboolean for_user_request)
_get_managed_by_flags(NMUnmanagedFlags flags,
NMUnmanagedFlags mask,
gboolean for_user_request,
NMDeviceStateReason *unmanaged_reason)
{
/* Evaluate the managed state based on the unmanaged flags.
*
@ -15028,7 +15059,7 @@ _get_managed_by_flags(NMUnmanagedFlags flags, NMUnmanagedFlags mask, gboolean fo
*
* Effectively, this check is redundant, as the code below already
* already ensures that. Still, express this invariant explicitly here. */
if (_get_managed_by_flags(flags, mask, FALSE))
if (_get_managed_by_flags(flags, mask, FALSE, unmanaged_reason))
return TRUE;
/* A for-user-request, is effectively the same as pretending
@ -15071,7 +15102,12 @@ _get_managed_by_flags(NMUnmanagedFlags flags, NMUnmanagedFlags mask, gboolean fo
| NM_UNMANAGED_EXTERNAL_DOWN);
}
return flags == NM_UNMANAGED_NONE;
if (flags == NM_UNMANAGED_NONE) {
return TRUE;
} else {
NM_SET_OUT(unmanaged_reason, unmanaged_flags_to_reason(flags));
return FALSE;
}
}
/**
@ -15100,7 +15136,10 @@ nm_device_get_managed(NMDevice *self, gboolean for_user_request)
priv = NM_DEVICE_GET_PRIVATE(self);
return _get_managed_by_flags(priv->unmanaged_flags, priv->unmanaged_mask, for_user_request);
return _get_managed_by_flags(priv->unmanaged_flags,
priv->unmanaged_mask,
for_user_request,
NULL);
}
/**
@ -15239,9 +15278,9 @@ _set_unmanaged_flags(NMDevice *self,
(priv->unmanaged_flags | priv->unmanaged_mask) ? "=" : "",
(guint) priv->unmanaged_flags,
(guint) priv->unmanaged_mask,
(_get_managed_by_flags(priv->unmanaged_flags, priv->unmanaged_mask, FALSE)
(_get_managed_by_flags(priv->unmanaged_flags, priv->unmanaged_mask, FALSE, NULL)
? "managed"
: (_get_managed_by_flags(priv->unmanaged_flags, priv->unmanaged_mask, TRUE)
: (_get_managed_by_flags(priv->unmanaged_flags, priv->unmanaged_mask, TRUE, NULL)
? "manageable"
: "unmanaged")),
priv->real ? "" : "/unrealized",
@ -15260,6 +15299,9 @@ _set_unmanaged_flags(NMDevice *self,
if (transition_state) {
new_state = was_managed ? NM_DEVICE_STATE_UNMANAGED : NM_DEVICE_STATE_UNAVAILABLE;
if (new_state == NM_DEVICE_STATE_UNMANAGED) {
/* In state UNMANAGED, the reason always depends on current flags, not on what
* the caller passed. */
_get_managed_by_flags(priv->unmanaged_flags, priv->unmanaged_mask, FALSE, &reason);
_cancel_activation(self);
} else {
/* The assume check should happen before the device transitions to
@ -15274,6 +15316,13 @@ _set_unmanaged_flags(NMDevice *self,
nm_device_state_changed(self, new_state, reason);
else
nm_device_queue_state(self, new_state, reason);
} else {
/* No state change, but possibly update the reason in UNMANAGED */
if (!_get_managed_by_flags(priv->unmanaged_flags, priv->unmanaged_mask, FALSE, &reason)
&& reason != priv->state_reason) {
priv->state_reason = reason;
_notify(self, PROP_STATE_REASON);
}
}
}

View file

@ -612,6 +612,25 @@ typedef enum {
* @NM_DEVICE_STATE_REASON_PEER_NOT_FOUND: The Wi-Fi P2P peer could not be found
* @NM_DEVICE_STATE_REASON_DEVICE_HANDLER_FAILED: The device handler dispatcher returned an
* error. Since: 1.46
* @NM_DEVICE_STATE_REASON_UNMANAGED_BY_DEFAULT: The device is unmanaged because the device type
* is unmanaged by default. Since: 1.48
* @NM_DEVICE_STATE_REASON_UNMANAGED_EXTERNAL_DOWN: The device is unmanaged because it is an
* external device and is unconfigured (down or without addresses). Since: 1.48
* @NM_DEVICE_STATE_REASON_UNMANAGED_LINK_NOT_INIT: The device is unmanaged because the link is
* not initialized by udev. Since: 1.48
* @NM_DEVICE_STATE_REASON_UNMANAGED_QUITTING: The device is unmanaged because NetworkManager is
* quitting. Since: 1.48
* @NM_DEVICE_STATE_REASON_UNMANAGED_SLEEPING: The device is unmanaged because networking is
* disabled or the system is suspended. Since: 1.48
* @NM_DEVICE_STATE_REASON_UNMANAGED_USER_CONF: The device is unmanaged by user decision in
* NetworkManager.conf ('unmanaged' in a [device*] section). Since: 1.48
* @NM_DEVICE_STATE_REASON_UNMANAGED_USER_EXPLICIT: The device is unmanaged by explicit user
* decision (e.g. 'nmcli device set $DEV managed no'). Since: 1.48
* @NM_DEVICE_STATE_REASON_UNMANAGED_USER_SETTINGS: The device is unmanaged by user decision
* via settings plugin ('unmanaged-devices' for keyfile or 'NM_CONTROLLED=no' for ifcfg-rh).
* Since: 1.48
* @NM_DEVICE_STATE_REASON_UNMANAGED_USER_UDEV: The device is unmanaged via udev rule. Since: 1.48
*
* Device state change reason codes
*/
@ -685,6 +704,15 @@ typedef enum {
NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED = 66,
NM_DEVICE_STATE_REASON_PEER_NOT_FOUND = 67,
NM_DEVICE_STATE_REASON_DEVICE_HANDLER_FAILED = 68,
NM_DEVICE_STATE_REASON_UNMANAGED_BY_DEFAULT = 69,
NM_DEVICE_STATE_REASON_UNMANAGED_EXTERNAL_DOWN = 70,
NM_DEVICE_STATE_REASON_UNMANAGED_LINK_NOT_INIT = 71,
NM_DEVICE_STATE_REASON_UNMANAGED_QUITTING = 72,
NM_DEVICE_STATE_REASON_UNMANAGED_SLEEPING = 73,
NM_DEVICE_STATE_REASON_UNMANAGED_USER_CONF = 74,
NM_DEVICE_STATE_REASON_UNMANAGED_USER_EXPLICIT = 75,
NM_DEVICE_STATE_REASON_UNMANAGED_USER_SETTINGS = 76,
NM_DEVICE_STATE_REASON_UNMANAGED_USER_UDEV = 77,
} NMDeviceStateReason;
/**

View file

@ -466,7 +466,34 @@ NM_UTILS_LOOKUP_STR_DEFINE(
NM_UTILS_LOOKUP_ITEM(NM_DEVICE_STATE_REASON_PEER_NOT_FOUND,
N_("The Wi-Fi P2P peer could not be found")),
NM_UTILS_LOOKUP_ITEM(NM_DEVICE_STATE_REASON_DEVICE_HANDLER_FAILED,
N_("The device handler dispatcher returned an error")), );
N_("The device handler dispatcher returned an error")),
NM_UTILS_LOOKUP_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_SLEEPING,
N_("The device is unmanaged because networking is disabled "
"or the system is suspended")),
NM_UTILS_LOOKUP_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_QUITTING,
N_("The device is unmanaged because NetworkManager is quitting")),
NM_UTILS_LOOKUP_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_LINK_NOT_INIT,
N_("The device is unmanaged because the link is not initialized by udev")),
NM_UTILS_LOOKUP_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_EXPLICIT,
N_("The device is unmanaged by explicit user decision (e.g. 'nmcli device "
"set $DEV managed no'")),
NM_UTILS_LOOKUP_ITEM(
NM_DEVICE_STATE_REASON_UNMANAGED_USER_SETTINGS,
N_("The device is unmanaged by user decision via settings plugin "
"(\"unmanaged-devices\" for keyfile or \"NM_CONTROLLED=no\" for ifcfg-rh)")),
NM_UTILS_LOOKUP_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_CONF,
N_("The device is unmanaged by user decision in NetworkManager.conf "
"('unmanaged' in a [device*] section")),
NM_UTILS_LOOKUP_ITEM(
NM_DEVICE_STATE_REASON_UNMANAGED_BY_DEFAULT,
N_("The device is unmanaged because the device type is unmanaged by default")),
NM_UTILS_LOOKUP_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_UDEV,
N_("The device is unmanaged via udev rule")),
NM_UTILS_LOOKUP_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_EXTERNAL_DOWN,
N_("The device is unmanaged because it is an external device and is "
"unconfigured (down or without addresses)")),
);
NM_UTILS_LOOKUP_STR_DEFINE(
nm_active_connection_state_reason_to_string,