core: persist state of software generic devices across restarts

When a generic connection has a custom device-handler, it always
generates a NMDeviceGeneric, even when the link that gets created is
of a type natively supported by NM. On service restart, we need to
keep track that the device is generic or otherwise a different device
type will be instantiated.
This commit is contained in:
Beniamino Galvani 2023-11-21 14:57:17 +01:00
parent df6c35ec75
commit f2613be150
5 changed files with 54 additions and 11 deletions

View file

@ -28,6 +28,10 @@ G_DEFINE_ABSTRACT_TYPE(NMDeviceFactory, nm_device_factory, G_TYPE_OBJECT)
/*****************************************************************************/
static NMDeviceFactory *generic_factory;
/*****************************************************************************/
static void
nm_device_factory_get_supported_types(NMDeviceFactory *factory,
const NMLinkType **out_link_types,
@ -66,7 +70,8 @@ nm_device_factory_create_device(NMDeviceFactory *factory,
if (plink) {
g_return_val_if_fail(!connection, NULL);
g_return_val_if_fail(strcmp(iface, plink->name) == 0, NULL);
nm_assert(factory == nm_device_factory_manager_find_factory_for_link_type(plink->type));
nm_assert(factory == nm_device_factory_manager_find_factory_for_link_type(plink->type)
|| factory == generic_factory);
} else if (connection)
nm_assert(factory == nm_device_factory_manager_find_factory_for_connection(connection));
else
@ -184,6 +189,12 @@ static void __attribute__((destructor)) _cleanup(void)
nm_clear_pointer(&factories_by_setting, g_hash_table_unref);
}
NMDeviceFactory *
nm_device_factory_get_generic_factory(void)
{
return generic_factory;
}
NMDeviceFactory *
nm_device_factory_manager_find_factory_for_link_type(NMLinkType link_type)
{
@ -300,9 +311,12 @@ _load_internal_factory(GType factory_gtype,
gpointer user_data)
{
gs_unref_object NMDeviceFactory *factory = NULL;
GType nm_generic_device_factory_get_type(void);
factory = g_object_new(factory_gtype, NULL);
_add_factory(factory, NULL, callback, user_data);
if (factory_gtype == nm_generic_device_factory_get_type())
generic_factory = factory;
}
static void

View file

@ -234,4 +234,6 @@ NMDeviceFactory *nm_device_factory_manager_find_factory_for_connection(NMConnect
void nm_device_factory_manager_for_each_factory(NMDeviceFactoryManagerFactoryFunc callback,
gpointer user_data);
NMDeviceFactory *nm_device_factory_get_generic_factory(void);
#endif /* __NETWORKMANAGER_DEVICE_FACTORY_H__ */

View file

@ -2354,9 +2354,10 @@ _nm_config_state_set(NMConfig *self, gboolean allow_persist, gboolean force_pers
"route-metric-default-aspired"
#define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_ROUTE_METRIC_DEFAULT_EFFECTIVE \
"route-metric-default-effective"
#define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_ROOT_PATH "root-path"
#define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_NEXT_SERVER "next-server"
#define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_DHCP_BOOTFILE "dhcp-bootfile"
#define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_ROOT_PATH "root-path"
#define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_NEXT_SERVER "next-server"
#define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_DHCP_BOOTFILE "dhcp-bootfile"
#define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_GENERIC_SOFTWARE "generic-software"
static NM_UTILS_LOOKUP_STR_DEFINE(
_device_state_managed_type_to_str,
@ -2457,6 +2458,12 @@ _config_device_state_data_new(int ifindex, GKeyFile *kf)
device_state->route_metric_default_aspired = route_metric_default_aspired;
device_state->route_metric_default_effective = route_metric_default_effective;
device_state->generic_sw =
nm_config_keyfile_get_boolean(kf,
DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_GENERIC_SOFTWARE,
FALSE);
p = (char *) (&device_state[1]);
if (connection_uuid) {
memcpy(p, connection_uuid, connection_uuid_len);
@ -2502,7 +2509,7 @@ nm_config_device_state_load(int ifindex)
? ", nm-owned=1"
: (device_state->nm_owned == NM_TERNARY_FALSE ? ", nm-owned=0" : "");
_LOGT("device-state: %s #%d (%s); managed=%s%s%s%s%s%s%s%s, "
_LOGT("device-state: %s #%d (%s); managed=%s%s%s%s%s%s%s%s%s, "
"route-metric-default=%" G_GUINT32_FORMAT "-%" G_GUINT32_FORMAT "",
kf ? "read" : "miss",
ifindex,
@ -2519,6 +2526,7 @@ nm_config_device_state_load(int ifindex)
"",
""),
nm_owned_str,
device_state->generic_sw ? ", generic-software" : "",
device_state->route_metric_default_aspired,
device_state->route_metric_default_effective);
@ -2577,7 +2585,8 @@ nm_config_device_state_write(int ifindex,
guint32 route_metric_default_aspired,
guint32 route_metric_default_effective,
NMDhcpConfig *dhcp4_config,
NMDhcpConfig *dhcp6_config)
NMDhcpConfig *dhcp6_config,
gboolean generic_sw)
{
char path[NM_STRLEN(NM_CONFIG_DEVICE_STATE_DIR "/") + DEVICE_STATE_FILENAME_LEN_MAX + 1];
GError *local = NULL;
@ -2664,6 +2673,13 @@ nm_config_device_state_write(int ifindex,
dhcp_bootfile);
}
if (generic_sw) {
g_key_file_set_boolean(kf,
DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_GENERIC_SOFTWARE,
TRUE);
}
for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) {
NMDhcpConfig *dhcp_config = IS_IPv4 ? dhcp4_config : dhcp6_config;
gs_free NMUtilsNamedValue *values = NULL;
@ -2691,7 +2707,7 @@ nm_config_device_state_write(int ifindex,
g_error_free(local);
return FALSE;
}
_LOGT("device-state: write #%d (%s); managed=%s%s%s%s%s%s%s, "
_LOGT("device-state: write #%d (%s); managed=%s%s%s%s%s%s%s%s, "
"route-metric-default=%" G_GUINT32_FORMAT "-%" G_GUINT32_FORMAT "%s%s%s"
"%s%s%s"
"%s%s%s",
@ -2700,6 +2716,7 @@ nm_config_device_state_write(int ifindex,
_device_state_managed_type_to_str(managed),
NM_PRINT_FMT_QUOTED(connection_uuid, ", connection-uuid=", connection_uuid, "", ""),
NM_PRINT_FMT_QUOTED(perm_hw_addr_fake, ", perm-hw-addr-fake=", perm_hw_addr_fake, "", ""),
generic_sw ? ", generic-software" : "",
route_metric_default_aspired,
route_metric_default_effective,
NM_PRINT_FMT_QUOTED(next_server, ", next-server=", next_server, "", ""),

View file

@ -176,6 +176,8 @@ struct _NMConfigDeviceStateData {
/* whether the device was nm-owned (0/1) or -1 for
* non-software devices. */
NMTernary nm_owned : 3;
/* whether the device is a generic one created by NM */
bool generic_sw : 1;
};
NMConfigDeviceStateData *nm_config_device_state_load(int ifindex);
@ -188,7 +190,8 @@ gboolean nm_config_device_state_write(int
guint32 route_metric_default_aspired,
guint32 route_metric_default_effective,
NMDhcpConfig *dhcp4_config,
NMDhcpConfig *dhcp6_config);
NMDhcpConfig *dhcp6_config,
gboolean generic);
void nm_config_device_state_prune_stale(GHashTable *preserve_ifindexes,
NMPlatform *preserve_in_platform);

View file

@ -4213,8 +4213,12 @@ platform_link_added(NMManager *self,
}
add:
/* Try registered device factories */
factory = nm_device_factory_manager_find_factory_for_link_type(plink->type);
if (dev_state && dev_state->generic_sw) {
factory = nm_device_factory_get_generic_factory();
} else {
/* Try registered device factories */
factory = nm_device_factory_manager_find_factory_for_link_type(plink->type);
}
if (factory) {
gboolean ignore = FALSE;
gs_free_error GError *error = NULL;
@ -7860,7 +7864,10 @@ nm_manager_write_device_state(NMManager *self, NMDevice *device, int *out_ifinde
route_metric_default_aspired,
route_metric_default_effective,
nm_device_get_dhcp_config(device, AF_INET),
nm_device_get_dhcp_config(device, AF_INET6)))
nm_device_get_dhcp_config(device, AF_INET6),
nm_device_is_software(device)
&& nm_device_get_device_type(device)
== NM_DEVICE_TYPE_GENERIC))
return FALSE;
NM_SET_OUT(out_ifindex, ifindex);