core: merge branch 'th/device-match'

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1657
This commit is contained in:
Thomas Haller 2023-06-14 12:02:15 +02:00
commit dafe66905f
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
12 changed files with 486 additions and 286 deletions

View file

@ -30,6 +30,7 @@
#include "libnm-platform/nm-linux-platform.h"
#include "libnm-platform/nm-platform-utils.h"
#include "nm-auth-utils.h"
#include "devices/nm-device.h"
/*****************************************************************************/
@ -900,6 +901,73 @@ nm_utils_match_connection(NMConnection *const *connections,
/*****************************************************************************/
const struct _NMMatchSpecDeviceData *
nm_match_spec_device_data_init_from_device(struct _NMMatchSpecDeviceData *out_data,
NMDevice *device)
{
const char *hw_address;
gboolean is_fake;
nm_assert(out_data);
if (!device) {
*out_data = (NMMatchSpecDeviceData){};
return out_data;
}
nm_assert(NM_IS_DEVICE(device));
hw_address = nm_device_get_permanent_hw_address_full(
device,
!nm_device_get_unmanaged_flags(device, NM_UNMANAGED_PLATFORM_INIT),
&is_fake);
/* Note that here we access various getters on @device, without cloning
* or taking ownership and return it to the caller.
*
* The returned data is only valid, until NMDevice gets modified again. */
*out_data = (NMMatchSpecDeviceData){
.interface_name = nm_device_get_iface(device),
.device_type = nm_device_get_type_description(device),
.driver = nm_device_get_driver(device),
.driver_version = nm_device_get_driver_version(device),
.hwaddr = is_fake ? NULL : hw_address,
.s390_subchannels = nm_device_get_s390_subchannels(device),
.dhcp_plugin = nm_dhcp_manager_get_config(nm_dhcp_manager_get()),
};
return out_data;
}
const NMMatchSpecDeviceData *
nm_match_spec_device_data_init_from_platform(NMMatchSpecDeviceData *out_data,
const NMPlatformLink *pllink,
const char *match_device_type,
const char *match_dhcp_plugin)
{
nm_assert(out_data);
/* we can only match by certain properties that are available on the
* platform link (and even @pllink might be missing.
*
* It's still useful because of specs like "*" and "except:interface-name:eth0",
* which match even in that case. */
*out_data = (NMMatchSpecDeviceData){
.interface_name = pllink ? pllink->name : NULL,
.device_type = match_device_type,
.driver = pllink ? pllink->driver : NULL,
.driver_version = NULL,
.hwaddr = NULL,
.s390_subchannels = NULL,
.dhcp_plugin = match_dhcp_plugin,
};
return out_data;
}
/*****************************************************************************/
int
nm_match_spec_device_by_pllink(const NMPlatformLink *pllink,
const char *match_device_type,
@ -907,32 +975,15 @@ nm_match_spec_device_by_pllink(const NMPlatformLink *pllink,
const GSList *specs,
int no_match_value)
{
NMMatchSpecMatchType m;
NMMatchSpecMatchType m;
NMMatchSpecDeviceData data;
/* we can only match by certain properties that are available on the
* platform link (and even @pllink might be missing.
*
* It's still useful because of specs like "*" and "except:interface-name:eth0",
* which match even in that case. */
m = nm_match_spec_device(specs,
pllink ? pllink->name : NULL,
match_device_type,
pllink ? pllink->driver : NULL,
NULL,
NULL,
NULL,
match_dhcp_plugin);
switch (m) {
case NM_MATCH_SPEC_MATCH:
return TRUE;
case NM_MATCH_SPEC_NEG_MATCH:
return FALSE;
case NM_MATCH_SPEC_NO_MATCH:
return no_match_value;
}
nm_assert_not_reached();
return no_match_value;
nm_match_spec_device_data_init_from_platform(&data,
pllink,
match_device_type,
match_dhcp_plugin));
return nm_match_spec_match_type_to_bool(m, no_match_value);
}
/*****************************************************************************/

View file

@ -89,6 +89,20 @@ NMConnection *nm_utils_match_connection(NMConnection *const *connections,
NMUtilsMatchFilterFunc match_filter_func,
gpointer match_filter_data);
/*****************************************************************************/
struct _NMMatchSpecDeviceData;
const struct _NMMatchSpecDeviceData *
nm_match_spec_device_data_init_from_device(struct _NMMatchSpecDeviceData *out_data,
NMDevice *device);
const struct _NMMatchSpecDeviceData *
nm_match_spec_device_data_init_from_platform(struct _NMMatchSpecDeviceData *out_data,
const NMPlatformLink *pllink,
const char *match_device_type,
const char *match_dhcp_plugin);
int nm_match_spec_device_by_pllink(const NMPlatformLink *pllink,
const char *match_device_type,
const char *match_dhcp_plugin,

View file

@ -5115,6 +5115,18 @@ nm_device_get_ip_iface_identifier(NMDevice *self,
return NM_DEVICE_GET_CLASS(self)->get_ip_iface_identifier(self, iid);
}
const char *
nm_device_get_s390_subchannels(NMDevice *self)
{
NMDeviceClass *klass;
g_return_val_if_fail(NM_IS_DEVICE(self), NULL);
klass = NM_DEVICE_GET_CLASS(self);
return klass->get_s390_subchannels ? klass->get_s390_subchannels(self) : NULL;
}
const char *
nm_device_get_driver(NMDevice *self)
{
@ -7508,14 +7520,15 @@ device_init_static_sriov_num_vfs(NMDevice *self)
if (priv->ifindex > 0 && nm_device_has_capability(self, NM_DEVICE_CAP_SRIOV)) {
int num_vfs;
num_vfs = nm_config_data_get_device_config_int64(NM_CONFIG_GET_DATA,
NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS,
self,
10,
0,
G_MAXINT32,
-1,
-1);
num_vfs = nm_config_data_get_device_config_int64_by_device(
NM_CONFIG_GET_DATA,
NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS,
self,
10,
0,
G_MAXINT32,
-1,
-1);
if (num_vfs >= 0)
sriov_op_queue(self, num_vfs, NM_OPTION_BOOL_DEFAULT, NULL, NULL);
}
@ -7531,7 +7544,7 @@ config_changed(NMConfig *config,
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
if (priv->state <= NM_DEVICE_STATE_DISCONNECTED || priv->state >= NM_DEVICE_STATE_ACTIVATED) {
priv->ignore_carrier = nm_config_data_get_ignore_carrier(config_data, self);
priv->ignore_carrier = nm_config_data_get_ignore_carrier_by_device(config_data, self);
if (NM_FLAGS_HAS(changes, NM_CONFIG_CHANGE_VALUES)
&& !nm_device_get_applied_setting(self, NM_TYPE_SETTING_SRIOV))
device_init_static_sriov_num_vfs(self);
@ -7670,8 +7683,9 @@ realize_start_setup(NMDevice *self,
nm_device_update_permanent_hw_address(self, FALSE);
/* Note: initial hardware address must be read before calling get_ignore_carrier() */
config = nm_config_get();
priv->ignore_carrier = nm_config_data_get_ignore_carrier(nm_config_get_data(config), self);
config = nm_config_get();
priv->ignore_carrier =
nm_config_data_get_ignore_carrier_by_device(nm_config_get_data(config), self);
if (!priv->config_changed_id) {
priv->config_changed_id = g_signal_connect(config,
NM_CONFIG_SIGNAL_CONFIG_CHANGED,
@ -10902,10 +10916,13 @@ connection_ip_method_requires_carrier(NMConnection *connection,
static gboolean
connection_requires_carrier(NMConnection *connection)
{
NMSettingIPConfig *s_ip4, *s_ip6;
NMSettingIPConfig *s_ip4;
NMSettingIPConfig *s_ip6;
NMSettingConnection *s_con;
gboolean ip4_carrier_wanted, ip6_carrier_wanted;
gboolean ip4_used = FALSE, ip6_used = FALSE;
gboolean ip4_carrier_wanted;
gboolean ip6_carrier_wanted;
gboolean ip4_used = FALSE;
gboolean ip6_used = FALSE;
/* We can progress to IP_CONFIG now, so that we're enslaved.
* That may actually cause carrier to go up and thus continue activation. */
@ -14302,14 +14319,15 @@ nm_device_is_up(NMDevice *self)
static gint64
_get_carrier_wait_ms(NMDevice *self)
{
return nm_config_data_get_device_config_int64(NM_CONFIG_GET_DATA,
NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT,
self,
10,
0,
G_MAXINT32,
CARRIER_WAIT_TIME_MS,
CARRIER_WAIT_TIME_MS);
return nm_config_data_get_device_config_int64_by_device(
NM_CONFIG_GET_DATA,
NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT,
self,
10,
0,
G_MAXINT32,
CARRIER_WAIT_TIME_MS,
CARRIER_WAIT_TIME_MS);
}
/*
@ -14866,11 +14884,11 @@ nm_device_check_unrealized_device_managed(NMDevice *self)
nm_assert(!nm_device_is_real(self));
if (!nm_config_data_get_device_config_boolean(NM_CONFIG_GET_DATA,
NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED,
self,
TRUE,
TRUE))
if (!nm_config_data_get_device_config_boolean_by_device(NM_CONFIG_GET_DATA,
NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED,
self,
TRUE,
TRUE))
return FALSE;
if (nm_device_spec_match_list(self, nm_settings_get_unmanaged_specs(priv->settings)))
@ -14937,11 +14955,11 @@ nm_device_set_unmanaged_by_user_conf(NMDevice *self)
gboolean value;
NMUnmanFlagOp set_op;
value = nm_config_data_get_device_config_boolean(NM_CONFIG_GET_DATA,
NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED,
self,
-1,
TRUE);
value = nm_config_data_get_device_config_boolean_by_device(NM_CONFIG_GET_DATA,
NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED,
self,
-1,
TRUE);
switch (value) {
case TRUE:
set_op = NM_UNMAN_FLAG_OP_SET_MANAGED;
@ -15324,10 +15342,7 @@ check_connection_available(NMDevice *self,
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
/* Connections which require a network connection are not available when
* the device has no carrier, even with ignore-carrer=TRUE.
*/
if (priv->carrier || !connection_requires_carrier(connection))
if (priv->carrier)
return TRUE;
if (NM_FLAGS_HAS(flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)
@ -15339,12 +15354,6 @@ check_connection_available(NMDevice *self,
return TRUE;
}
/* master types are always available even without carrier.
* Making connection non-available would un-enslave slaves which
* is not desired. */
if (nm_device_is_master(self))
return TRUE;
if (!priv->up) {
/* If the device is !IFF_UP it also has no carrier. But we assume that if we
* would start activating the device (and thereby set the device IFF_UP),
@ -15354,6 +15363,18 @@ check_connection_available(NMDevice *self,
return TRUE;
}
if (!connection_requires_carrier(connection)) {
/* Connections that don't require carrier are available. */
return TRUE;
}
if (nm_device_is_master(self)) {
/* master types are always available even without carrier.
* Making connection non-available would un-enslave slaves which
* is not desired. */
return TRUE;
}
nm_utils_error_set_literal(error,
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
"device has no carrier");
@ -16283,7 +16304,8 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason,
/* We cache the ignore_carrier state to not react on config-reloads while the connection
* is active. But on deactivating, reset the ignore-carrier flag to the current state. */
priv->ignore_carrier = nm_config_data_get_ignore_carrier(NM_CONFIG_GET_DATA, self);
priv->ignore_carrier =
nm_config_data_get_ignore_carrier_by_device(NM_CONFIG_GET_DATA, self);
if (quitting) {
nm_dispatcher_call_device_sync(NM_DISPATCHER_ACTION_PRE_DOWN, self, req);
@ -17275,38 +17297,11 @@ nm_device_spec_match_list(NMDevice *self, const GSList *specs)
int
nm_device_spec_match_list_full(NMDevice *self, const GSList *specs, int no_match_value)
{
NMDeviceClass *klass;
NMMatchSpecMatchType m;
const char *hw_address = NULL;
gboolean is_fake;
NMMatchSpecDeviceData data;
NMMatchSpecMatchType m;
g_return_val_if_fail(NM_IS_DEVICE(self), FALSE);
klass = NM_DEVICE_GET_CLASS(self);
hw_address = nm_device_get_permanent_hw_address_full(
self,
!nm_device_get_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT),
&is_fake);
m = nm_match_spec_device(specs,
nm_device_get_iface(self),
nm_device_get_type_description(self),
nm_device_get_driver(self),
nm_device_get_driver_version(self),
is_fake ? NULL : hw_address,
klass->get_s390_subchannels ? klass->get_s390_subchannels(self) : NULL,
nm_dhcp_manager_get_config(nm_dhcp_manager_get()));
switch (m) {
case NM_MATCH_SPEC_MATCH:
return TRUE;
case NM_MATCH_SPEC_NEG_MATCH:
return FALSE;
case NM_MATCH_SPEC_NO_MATCH:
return no_match_value;
}
nm_assert_not_reached();
return no_match_value;
m = nm_match_spec_device(specs, nm_match_spec_device_data_init_from_device(&data, self));
return nm_match_spec_match_type_to_bool(m, no_match_value);
}
guint

View file

@ -460,6 +460,7 @@ gboolean nm_device_is_real(NMDevice *dev);
const char *nm_device_get_ip_iface(NMDevice *dev);
const char *nm_device_get_ip_iface_from_platform(NMDevice *dev);
int nm_device_get_ip_ifindex(const NMDevice *dev);
const char *nm_device_get_s390_subchannels(NMDevice *self);
const char *nm_device_get_driver(NMDevice *dev);
const char *nm_device_get_driver_version(NMDevice *dev);
const char *nm_device_get_type_desc(NMDevice *dev);

View file

@ -3108,12 +3108,12 @@ config_changed(NMConfig *config,
NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
gboolean old_iwd_ac = priv->iwd_autoconnect;
priv->iwd_autoconnect =
nm_config_data_get_device_config_boolean(config_data,
NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_IWD_AUTOCONNECT,
NM_DEVICE(self),
TRUE,
TRUE);
priv->iwd_autoconnect = nm_config_data_get_device_config_boolean_by_device(
config_data,
NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_IWD_AUTOCONNECT,
NM_DEVICE(self),
TRUE,
TRUE);
if (old_iwd_ac != priv->iwd_autoconnect && priv->dbus_station_proxy && !priv->current_ap) {
gs_unref_variant GVariant *value = NULL;

View file

@ -1398,7 +1398,7 @@ _hw_addr_set_scanning(NMDeviceWifi *self, gboolean do_reset)
priv = NM_DEVICE_WIFI_GET_PRIVATE(self);
randomize = nm_config_data_get_device_config_boolean(
randomize = nm_config_data_get_device_config_boolean_by_device(
NM_CONFIG_GET_DATA,
NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_RAND_MAC_ADDRESS,
device,
@ -1431,7 +1431,7 @@ _hw_addr_set_scanning(NMDeviceWifi *self, gboolean do_reset)
* a new one.*/
priv->hw_addr_scan_expire = now + SCAN_RAND_MAC_ADDRESS_EXPIRE_SEC;
generate_mac_address_mask = nm_config_data_get_device_config(
generate_mac_address_mask = nm_config_data_get_device_config_by_device(
NM_CONFIG_GET_DATA,
NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_GENERATE_MAC_ADDRESS_MASK,
device,

View file

@ -130,6 +130,12 @@ G_DEFINE_TYPE(NMConfigData, nm_config_data, G_TYPE_OBJECT)
static const char *
_match_section_info_get_str(const MatchSectionInfo *m, GKeyFile *keyfile, const char *property);
static const char *_config_data_get_device_config(const NMConfigData *self,
const char *property,
const NMMatchSpecDeviceData *match_data,
NMDevice *device,
gboolean *has_match);
/*****************************************************************************/
const char *
@ -366,7 +372,55 @@ nm_config_data_get_iwd_config_path(const NMConfigData *self)
}
gboolean
nm_config_data_get_ignore_carrier(const NMConfigData *self, NMDevice *device)
nm_config_data_get_ignore_carrier_for_port(const NMConfigData *self,
const char *master,
const char *slave_type)
{
const char *value;
gboolean has_match;
int m;
NMMatchSpecDeviceData match_data;
g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE);
if (!master || !slave_type)
goto out_default;
if (!nm_utils_ifname_valid_kernel(master, NULL))
goto out_default;
match_data = (NMMatchSpecDeviceData){
.interface_name = master,
.device_type = slave_type,
};
value = _config_data_get_device_config(self,
NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER,
&match_data,
NULL,
&has_match);
if (has_match)
m = nm_config_parse_boolean(value, -1);
else {
NMMatchSpecMatchType x;
x = nm_match_spec_device(NM_CONFIG_DATA_GET_PRIVATE(self)->ignore_carrier, &match_data);
m = nm_match_spec_match_type_to_bool(x, -1);
}
if (NM_IN_SET(m, TRUE, FALSE))
return m;
out_default:
/* if ignore-carrier is not explicitly or detected for the master, then we assume it's
* enabled. This is in line with nm_config_data_get_ignore_carrier_by_device(), where
* ignore-carrier is enabled based on nm_device_ignore_carrier_by_default().
*/
return TRUE;
}
gboolean
nm_config_data_get_ignore_carrier_by_device(const NMConfigData *self, NMDevice *device)
{
const char *value;
gboolean has_match;
@ -375,10 +429,10 @@ nm_config_data_get_ignore_carrier(const NMConfigData *self, NMDevice *device)
g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE);
g_return_val_if_fail(NM_IS_DEVICE(device), FALSE);
value = nm_config_data_get_device_config(self,
NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER,
device,
&has_match);
value = nm_config_data_get_device_config_by_device(self,
NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER,
device,
&has_match);
if (has_match)
m = nm_config_parse_boolean(value, -1);
else
@ -1488,21 +1542,23 @@ global_dns_equal(NMGlobalDnsConfig *old, NMGlobalDnsConfig *new)
/*****************************************************************************/
static const MatchSectionInfo *
_match_section_infos_lookup(const MatchSectionInfo *match_section_infos,
GKeyFile *keyfile,
const char *property,
NMDevice *device,
const NMPlatformLink *pllink,
const char *match_device_type,
const char **out_value)
_match_section_infos_lookup(const MatchSectionInfo *match_section_infos,
GKeyFile *keyfile,
const char *property,
const NMMatchSpecDeviceData *match_data,
NMDevice *device,
const char **out_value)
{
const char *match_dhcp_plugin;
NMMatchSpecDeviceData match_data_local;
/* Caller must either provide a "match_data" or a "device" (actually,
* neither is also fine, albeit unusual). */
nm_assert(!match_data || !device);
nm_assert(!device || NM_IS_DEVICE(device));
if (!match_section_infos)
goto out;
match_dhcp_plugin = nm_dhcp_manager_get_config(nm_dhcp_manager_get());
for (; match_section_infos->group_name; match_section_infos++) {
const char *value;
gboolean match;
@ -1519,16 +1575,17 @@ _match_section_infos_lookup(const MatchSectionInfo *match_section_infos,
continue;
if (match_section_infos->match_device.has) {
if (device)
match = nm_device_spec_match_list(device, match_section_infos->match_device.spec);
else if (pllink)
match = nm_match_spec_device_by_pllink(pllink,
match_device_type,
match_dhcp_plugin,
match_section_infos->match_device.spec,
FALSE);
else
match = FALSE;
NMMatchSpecMatchType m;
if (G_UNLIKELY(!match_data)) {
/* In most cases, we don't actually have any matches. So we "optimize"
* here by allowing the user to specify a NMDEvice directly, and only
* initialize the match-data when needed. */
match_data = nm_match_spec_device_data_init_from_device(&match_data_local, device);
}
m = nm_match_spec_device(match_section_infos->match_device.spec, match_data);
match = nm_match_spec_match_type_to_bool(m, FALSE);
} else
match = TRUE;
@ -1543,11 +1600,12 @@ out:
return NULL;
}
const char *
nm_config_data_get_device_config(const NMConfigData *self,
const char *property,
NMDevice *device,
gboolean *has_match)
static const char *
_config_data_get_device_config(const NMConfigData *self,
const char *property,
const NMMatchSpecDeviceData *match_data,
NMDevice *device,
gboolean *has_match)
{
const NMConfigDataPrivate *priv;
const MatchSectionInfo *connection_info;
@ -1558,19 +1616,39 @@ nm_config_data_get_device_config(const NMConfigData *self,
g_return_val_if_fail(self, NULL);
g_return_val_if_fail(property && *property, NULL);
nm_assert(!match_data || !device);
nm_assert(!device || NM_IS_DEVICE(device));
priv = NM_CONFIG_DATA_GET_PRIVATE(self);
connection_info = _match_section_infos_lookup(&priv->device_infos[0],
priv->keyfile,
property,
match_data,
device,
NULL,
NULL,
&value);
NM_SET_OUT(has_match, !!connection_info);
return value;
}
const char *
nm_config_data_get_device_config(const NMConfigData *self,
const char *property,
const NMMatchSpecDeviceData *match_data,
gboolean *has_match)
{
return _config_data_get_device_config(self, property, match_data, NULL, has_match);
}
const char *
nm_config_data_get_device_config_by_device(const NMConfigData *self,
const char *property,
NMDevice *device,
gboolean *has_match)
{
return _config_data_get_device_config(self, property, NULL, device, has_match);
}
const char *
nm_config_data_get_device_config_by_pllink(const NMConfigData *self,
const char *property,
@ -1581,53 +1659,58 @@ nm_config_data_get_device_config_by_pllink(const NMConfigData *self,
const NMConfigDataPrivate *priv;
const MatchSectionInfo *connection_info;
const char *value;
NMMatchSpecDeviceData match_data;
g_return_val_if_fail(self, NULL);
g_return_val_if_fail(property && *property, NULL);
priv = NM_CONFIG_DATA_GET_PRIVATE(self);
nm_match_spec_device_data_init_from_platform(&match_data,
pllink,
match_device_type,
nm_dhcp_manager_get_config(nm_dhcp_manager_get()));
connection_info = _match_section_infos_lookup(&priv->device_infos[0],
priv->keyfile,
property,
&match_data,
NULL,
pllink,
match_device_type,
&value);
NM_SET_OUT(has_match, !!connection_info);
return value;
}
gboolean
nm_config_data_get_device_config_boolean(const NMConfigData *self,
const char *property,
NMDevice *device,
int val_no_match,
int val_invalid)
nm_config_data_get_device_config_boolean_by_device(const NMConfigData *self,
const char *property,
NMDevice *device,
int val_no_match,
int val_invalid)
{
const char *value;
gboolean has_match;
value = nm_config_data_get_device_config(self, property, device, &has_match);
value = nm_config_data_get_device_config_by_device(self, property, device, &has_match);
if (!has_match)
return val_no_match;
return nm_config_parse_boolean(value, val_invalid);
}
gint64
nm_config_data_get_device_config_int64(const NMConfigData *self,
const char *property,
NMDevice *device,
int base,
gint64 min,
gint64 max,
gint64 val_no_match,
gint64 val_invalid)
nm_config_data_get_device_config_int64_by_device(const NMConfigData *self,
const char *property,
NMDevice *device,
int base,
gint64 min,
gint64 max,
gint64 val_no_match,
gint64 val_invalid)
{
const char *value;
gboolean has_match;
value = nm_config_data_get_device_config(self, property, device, &has_match);
value = nm_config_data_get_device_config_by_device(self, property, device, &has_match);
if (!has_match) {
errno = ENOENT;
return val_no_match;
@ -1651,9 +1734,8 @@ nm_config_data_get_device_allowed_connections_specs(const NMConfigData *self,
connection_info = _match_section_infos_lookup(&priv->device_infos[0],
priv->keyfile,
NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS,
NULL,
device,
NULL,
NULL,
NULL);
if (connection_info) {
@ -1696,9 +1778,8 @@ nm_config_data_get_connection_default(const NMConfigData *self,
_match_section_infos_lookup(&priv->connection_infos[0],
priv->keyfile,
property,
NULL,
device,
NULL,
NULL,
&value);
return value;
}

View file

@ -185,7 +185,11 @@ const char *nm_config_data_get_dns_mode(const NMConfigData *self);
const char *nm_config_data_get_rc_manager(const NMConfigData *self);
gboolean nm_config_data_get_systemd_resolved(const NMConfigData *self);
gboolean nm_config_data_get_ignore_carrier(const NMConfigData *self, NMDevice *device);
gboolean nm_config_data_get_ignore_carrier_for_port(const NMConfigData *self,
const char *master,
const char *slave_type);
gboolean nm_config_data_get_ignore_carrier_by_device(const NMConfigData *self, NMDevice *device);
gboolean nm_config_data_get_assume_ipv6ll_only(const NMConfigData *self, NMDevice *device);
int nm_config_data_get_sriov_num_vfs(const NMConfigData *self, NMDevice *device);
@ -219,10 +223,17 @@ gint64 nm_config_data_get_connection_default_int64(const NMConfigData *self,
gint64 max,
gint64 fallback);
const char *nm_config_data_get_device_config(const NMConfigData *self,
const char *property,
NMDevice *device,
gboolean *has_match);
struct _NMMatchSpecDeviceData;
const char *nm_config_data_get_device_config(const NMConfigData *self,
const char *property,
const struct _NMMatchSpecDeviceData *match_data,
gboolean *has_match);
const char *nm_config_data_get_device_config_by_device(const NMConfigData *self,
const char *property,
NMDevice *device,
gboolean *has_match);
const char *nm_config_data_get_device_config_by_pllink(const NMConfigData *self,
const char *property,
@ -230,19 +241,19 @@ const char *nm_config_data_get_device_config_by_pllink(const NMConfigData *sel
const char *match_device_type,
gboolean *has_match);
gboolean nm_config_data_get_device_config_boolean(const NMConfigData *self,
const char *property,
NMDevice *device,
int val_no_match,
int val_invalid);
gint64 nm_config_data_get_device_config_int64(const NMConfigData *self,
const char *property,
NMDevice *device,
int base,
gint64 min,
gint64 max,
gint64 val_no_match,
gint64 val_invalid);
gboolean nm_config_data_get_device_config_boolean_by_device(const NMConfigData *self,
const char *property,
NMDevice *device,
int val_no_match,
int val_invalid);
gint64 nm_config_data_get_device_config_int64_by_device(const NMConfigData *self,
const char *property,
NMDevice *device,
int base,
gint64 min,
gint64 max,
gint64 val_no_match,
gint64 val_invalid);
const GSList *nm_config_data_get_device_allowed_connections_specs(const NMConfigData *self,
NMDevice *device,

View file

@ -1148,25 +1148,26 @@ nm_utils_read_link_absolute(const char *link_file, GError **error)
#define MATCH_TAG_CONFIG_ENV "env:"
typedef struct {
const char *interface_name;
const char *device_type;
const char *driver;
const char *driver_version;
const char *dhcp_plugin;
/* This struct contains pre-processed data from NMMatchSpecDeviceData so
* we only need to parse it once. */
const NMMatchSpecDeviceData *data;
const char *device_type;
const char *driver;
const char *driver_version;
const char *dhcp_plugin;
struct {
const char *value;
gboolean is_parsed;
guint len;
guint8 bin[_NM_UTILS_HWADDR_LEN_MAX];
gboolean is_parsed;
guint len;
guint8 bin[_NM_UTILS_HWADDR_LEN_MAX];
} hwaddr;
struct {
const char *value;
gboolean is_parsed;
guint32 a;
guint32 b;
guint32 c;
gboolean is_parsed;
gboolean is_good;
guint32 a;
guint32 b;
guint32 c;
} s390_subchannels;
} MatchDeviceData;
} MatchSpecDeviceData;
static gboolean
match_device_s390_subchannels_parse(const char *s390_subchannels,
@ -1234,22 +1235,25 @@ match_device_s390_subchannels_parse(const char *s390_subchannels,
}
static gboolean
match_data_s390_subchannels_eval(const char *spec_str, MatchDeviceData *match_data)
match_data_s390_subchannels_eval(const char *spec_str, MatchSpecDeviceData *match_data)
{
guint32 a, b, c;
guint32 a;
guint32 b;
guint32 c;
if (G_UNLIKELY(!match_data->s390_subchannels.is_parsed)) {
nm_assert(!match_data->s390_subchannels.is_good);
match_data->s390_subchannels.is_parsed = TRUE;
if (!match_data->s390_subchannels.value
|| !match_device_s390_subchannels_parse(match_data->s390_subchannels.value,
if (!match_data->data->s390_subchannels
|| !match_device_s390_subchannels_parse(match_data->data->s390_subchannels,
&match_data->s390_subchannels.a,
&match_data->s390_subchannels.b,
&match_data->s390_subchannels.c)) {
match_data->s390_subchannels.value = NULL;
return FALSE;
}
} else if (!match_data->s390_subchannels.value)
match_data->s390_subchannels.is_good = TRUE;
} else if (!match_data->s390_subchannels.is_good)
return FALSE;
if (!match_device_s390_subchannels_parse(spec_str, &a, &b, &c))
@ -1259,15 +1263,16 @@ match_data_s390_subchannels_eval(const char *spec_str, MatchDeviceData *match_da
}
static gboolean
match_device_hwaddr_eval(const char *spec_str, MatchDeviceData *match_data)
match_device_hwaddr_eval(const char *spec_str, MatchSpecDeviceData *match_data)
{
if (G_UNLIKELY(!match_data->hwaddr.is_parsed)) {
match_data->hwaddr.is_parsed = TRUE;
nm_assert(match_data->hwaddr.len == 0);
if (match_data->hwaddr.value) {
if (match_data->data->hwaddr) {
gsize l;
if (!_nm_utils_hwaddr_aton(match_data->hwaddr.value,
if (!_nm_utils_hwaddr_aton(match_data->data->hwaddr,
match_data->hwaddr.bin,
sizeof(match_data->hwaddr.bin),
&l))
@ -1275,7 +1280,7 @@ match_device_hwaddr_eval(const char *spec_str, MatchDeviceData *match_data)
match_data->hwaddr.len = l;
} else
return FALSE;
} else if (!match_data->hwaddr.len)
} else if (match_data->hwaddr.len == 0)
return FALSE;
return nm_utils_hwaddr_matches(spec_str, -1, match_data->hwaddr.bin, match_data->hwaddr.len);
@ -1330,7 +1335,7 @@ match_except(const char *spec_str, gboolean *out_except)
}
static gboolean
match_device_eval(const char *spec_str, gboolean allow_fuzzy, MatchDeviceData *match_data)
match_device_eval(const char *spec_str, gboolean allow_fuzzy, MatchSpecDeviceData *match_data)
{
if (spec_str[0] == '*' && spec_str[1] == '\0')
return TRUE;
@ -1353,10 +1358,10 @@ match_device_eval(const char *spec_str, gboolean allow_fuzzy, MatchDeviceData *m
use_pattern = TRUE;
}
if (match_data->interface_name) {
if (nm_streq(spec_str, match_data->interface_name))
if (match_data->data->interface_name) {
if (nm_streq(spec_str, match_data->data->interface_name))
return TRUE;
if (use_pattern && g_pattern_match_simple(spec_str, match_data->interface_name))
if (use_pattern && g_pattern_match_simple(spec_str, match_data->data->interface_name))
return TRUE;
}
return FALSE;
@ -1402,7 +1407,8 @@ match_device_eval(const char *spec_str, gboolean allow_fuzzy, MatchDeviceData *m
if (allow_fuzzy) {
if (match_device_hwaddr_eval(spec_str, match_data))
return TRUE;
if (match_data->interface_name && nm_streq(spec_str, match_data->interface_name))
if (match_data->data->interface_name
&& nm_streq(spec_str, match_data->data->interface_name))
return TRUE;
}
@ -1410,42 +1416,40 @@ match_device_eval(const char *spec_str, gboolean allow_fuzzy, MatchDeviceData *m
}
NMMatchSpecMatchType
nm_match_spec_device(const GSList *specs,
const char *interface_name,
const char *device_type,
const char *driver,
const char *driver_version,
const char *hwaddr,
const char *s390_subchannels,
const char *dhcp_plugin)
nm_match_spec_device(const GSList *specs, const NMMatchSpecDeviceData *data)
{
const GSList *iter;
gboolean has_match = FALSE;
gboolean has_match_except = FALSE;
gboolean has_except = FALSE;
gboolean has_not_except = FALSE;
const char *spec_str;
MatchDeviceData match_data = {
.interface_name = interface_name,
.device_type = nm_str_not_empty(device_type),
.driver = nm_str_not_empty(driver),
.driver_version = nm_str_not_empty(driver_version),
.dhcp_plugin = nm_str_not_empty(dhcp_plugin),
.hwaddr =
{
.value = hwaddr,
},
.s390_subchannels =
{
.value = s390_subchannels,
},
};
const GSList *iter;
gboolean has_match = FALSE;
gboolean has_match_except = FALSE;
gboolean has_except = FALSE;
gboolean has_not_except = FALSE;
const char *spec_str;
MatchSpecDeviceData match_data;
nm_assert(!hwaddr || nm_utils_hwaddr_valid(hwaddr, -1));
nm_assert(data);
nm_assert(!data->hwaddr || nm_utils_hwaddr_valid(data->hwaddr, -1));
if (!specs)
return NM_MATCH_SPEC_NO_MATCH;
match_data = (MatchSpecDeviceData){
.data = data,
.device_type = nm_str_not_empty(data->device_type),
.driver = nm_str_not_empty(data->driver),
.driver_version = nm_str_not_empty(data->driver_version),
.dhcp_plugin = nm_str_not_empty(data->dhcp_plugin),
.hwaddr =
{
.is_parsed = FALSE,
.len = 0,
},
.s390_subchannels =
{
.is_parsed = FALSE,
.is_good = FALSE,
},
};
for (iter = specs; iter; iter = iter->next) {
gboolean except;
@ -1478,6 +1482,20 @@ nm_match_spec_device(const GSList *specs,
return _match_result(has_except, has_not_except, has_match, has_match_except);
}
int
nm_match_spec_match_type_to_bool(NMMatchSpecMatchType m, int no_match_value)
{
switch (m) {
case NM_MATCH_SPEC_MATCH:
return TRUE;
case NM_MATCH_SPEC_NEG_MATCH:
return FALSE;
case NM_MATCH_SPEC_NO_MATCH:
return no_match_value;
}
return nm_assert_unreachable_val(no_match_value);
}
typedef struct {
const char *uuid;
const char *id;

View file

@ -193,14 +193,20 @@ typedef enum {
NM_MATCH_SPEC_NEG_MATCH = 2,
} NMMatchSpecMatchType;
NMMatchSpecMatchType nm_match_spec_device(const GSList *specs,
const char *interface_name,
const char *device_type,
const char *driver,
const char *driver_version,
const char *hwaddr,
const char *s390_subchannels,
const char *dhcp_plugin);
int nm_match_spec_match_type_to_bool(NMMatchSpecMatchType m, int no_match_value);
typedef struct _NMMatchSpecDeviceData {
const char *interface_name;
const char *device_type;
const char *driver;
const char *driver_version;
const char *dhcp_plugin;
const char *hwaddr;
const char *s390_subchannels;
} NMMatchSpecDeviceData;
NMMatchSpecMatchType nm_match_spec_device(const GSList *specs, const NMMatchSpecDeviceData *data);
NMMatchSpecMatchType nm_match_spec_config(const GSList *specs, guint nm_version, const char *env);
GSList *nm_match_spec_split(const char *value);
char *nm_match_spec_join(GSList *specs);

View file

@ -1523,10 +1523,31 @@ nm_manager_devcon_autoconnect_blocked_reason_set(NMManager
gboolean changed = FALSE;
char buf[100];
nm_assert(NM_IS_SETTINGS_CONNECTION(sett_conn));
nm_assert(!sett_conn || NM_IS_SETTINGS_CONNECTION(sett_conn));
nm_assert(!device || NM_IS_DEVICE(device));
nm_assert(value != NM_SETTINGS_AUTOCONNECT_BLOCKED_REASON_NONE);
nm_assert(!NM_FLAGS_ANY(value, ~(NM_SETTINGS_AUTOCONNECT_BLOCKED_REASON_FAILED)));
if (!sett_conn) {
if (!device)
g_return_val_if_reached(FALSE);
c_list_for_each_entry (data, &device->devcon_dev_lst_head, dev_lst) {
v = data->autoconnect.blocked_reason;
v = NM_FLAGS_ASSIGN(v, value, set);
if (data->autoconnect.blocked_reason == v)
continue;
_LOGT(LOGD_SETTINGS,
"block-autoconnect: " DEV_CON_DATA_LOG_FMT ": set blocked reason %s",
DEV_CON_DATA_LOG_ARGS_DATA(data),
nm_settings_autoconnect_blocked_reason_to_string(v, buf, sizeof(buf)));
data->autoconnect.blocked_reason = v;
changed = TRUE;
}
return changed;
}
if (device) {
data = _devcon_lookup_data(self, device, sett_conn, TRUE, TRUE);
v = data->autoconnect.blocked_reason;
@ -2575,9 +2596,10 @@ system_create_virtual_device(NMManager *self, NMConnection *connection)
guint i;
gs_free char *iface = NULL;
const char *parent_spec;
NMDevice *device = NULL, *parent = NULL;
NMDevice *device = NULL;
NMDevice *parent = NULL;
NMDevice *dev_candidate;
GError *error = NULL;
gs_free_error GError *error = NULL;
NMLogLevel log_level;
g_return_val_if_fail(NM_IS_MANAGER(self), NULL);
@ -2586,7 +2608,6 @@ system_create_virtual_device(NMManager *self, NMConnection *connection)
iface = nm_manager_get_connection_iface(self, connection, &parent, &parent_spec, &error);
if (!iface) {
_LOG3D(LOGD_DEVICE, connection, "can't get a name of a virtual device: %s", error->message);
g_error_free(error);
return NULL;
}
@ -2624,7 +2645,6 @@ system_create_virtual_device(NMManager *self, NMConnection *connection)
device = nm_device_factory_create_device(factory, iface, NULL, connection, NULL, &error);
if (!device) {
_LOG3W(LOGD_DEVICE, connection, "factory can't create the device: %s", error->message);
g_error_free(error);
return NULL;
}
@ -2635,7 +2655,6 @@ system_create_virtual_device(NMManager *self, NMConnection *connection)
connection,
"can't register the device with manager: %s",
error->message);
g_error_free(error);
g_object_unref(device);
return NULL;
}
@ -2656,7 +2675,6 @@ system_create_virtual_device(NMManager *self, NMConnection *connection)
if (!find_master(self, connection, device, NULL, NULL, NULL, &error)) {
_LOG3D(LOGD_DEVICE, connection, "skip activation: %s", error->message);
g_error_free(error);
return device;
}
@ -2670,7 +2688,6 @@ system_create_virtual_device(NMManager *self, NMConnection *connection)
continue;
s_con = nm_connection_get_setting_connection(candidate);
g_assert(s_con);
if (!nm_setting_connection_get_autoconnect(s_con)
|| nm_settings_connection_autoconnect_is_blocked(connections[i]))
continue;
@ -2686,7 +2703,6 @@ system_create_virtual_device(NMManager *self, NMConnection *connection)
connection,
"couldn't create the device: %s",
error->message);
g_error_free(error);
return NULL;
}
@ -3379,11 +3395,12 @@ get_existing_connection(NMManager *self, NMDevice *device, gboolean *out_generat
}
}
if (nm_config_data_get_device_config_boolean(NM_CONFIG_GET_DATA,
NM_CONFIG_KEYFILE_KEY_DEVICE_KEEP_CONFIGURATION,
device,
TRUE,
TRUE)) {
if (nm_config_data_get_device_config_boolean_by_device(
NM_CONFIG_GET_DATA,
NM_CONFIG_KEYFILE_KEY_DEVICE_KEEP_CONFIGURATION,
device,
TRUE,
TRUE)) {
/* The core of the API is nm_device_generate_connection() function, based on
* update_connection() virtual method and the @connection_type_supported
* class attribute. Devices that support assuming existing connections must
@ -4897,8 +4914,11 @@ find_master(NMManager *self,
NMSettingsConnection *const *connections;
guint i;
s_con = nm_connection_get_setting_connection(connection);
g_assert(s_con);
nm_assert(!out_master_connection || !*out_master_connection);
nm_assert(!out_master_device || !*out_master_device);
nm_assert(!out_master_ac || !*out_master_ac);
s_con = nm_connection_get_setting_connection(connection);
master = nm_setting_connection_get_master(s_con);
if (master == NULL)
@ -5006,10 +5026,16 @@ find_master(NMManager *self,
nm_device_get_iface(master_device));
}
if (out_master_connection)
*out_master_connection = master_connection;
if (out_master_device)
*out_master_device = master_device;
if (!master_device && !master_connection) {
g_set_error_literal(error,
NM_MANAGER_ERROR,
NM_MANAGER_ERROR_UNKNOWN_DEVICE,
"Master connection not found or invalid");
return FALSE;
}
NM_SET_OUT(out_master_connection, master_connection);
NM_SET_OUT(out_master_device, master_device);
if (out_master_ac && master_connection) {
*out_master_ac = active_connection_find(self,
master_connection,
@ -5019,15 +5045,7 @@ find_master(NMManager *self,
NULL);
}
if (master_device || master_connection)
return TRUE;
else {
g_set_error_literal(error,
NM_MANAGER_ERROR,
NM_MANAGER_ERROR_UNKNOWN_DEVICE,
"Master connection not found or invalid");
return FALSE;
}
return TRUE;
}
/**
@ -5272,8 +5290,9 @@ find_slaves(NMManager *manager,
&n_all_connections);
for (i = 0; i < n_all_connections; i++) {
NMSettingsConnection *master_connection = NULL;
NMDevice *master_device = NULL, *slave_device;
NMSettingsConnection *candidate = all_connections[i];
NMDevice *master_device = NULL;
NMDevice *slave_device;
NMSettingsConnection *candidate = all_connections[i];
find_master(manager,
nm_settings_connection_get_connection(candidate),
@ -5606,7 +5625,8 @@ active_connection_parent_active(NMActiveConnection *active,
static gboolean
_internal_activate_device(NMManager *self, NMActiveConnection *active, GError **error)
{
NMDevice *device, *master_device = NULL;
NMDevice *device;
NMDevice *master_device = NULL;
NMConnection *applied;
NMSettingsConnection *sett_conn;
NMSettingsConnection *master_connection = NULL;

View file

@ -1244,13 +1244,9 @@ _test_match_spec_device(const GSList *specs, const char *match_str)
{
if (match_str && g_str_has_prefix(match_str, MATCH_S390))
return nm_match_spec_device(specs,
NULL,
NULL,
NULL,
NULL,
NULL,
&match_str[NM_STRLEN(MATCH_S390)],
NULL);
&((const NMMatchSpecDeviceData){
.s390_subchannels = &match_str[NM_STRLEN(MATCH_S390)],
}));
if (match_str && g_str_has_prefix(match_str, MATCH_DRIVER)) {
gs_free char *s = g_strdup(&match_str[NM_STRLEN(MATCH_DRIVER)]);
char *t;
@ -1260,9 +1256,16 @@ _test_match_spec_device(const GSList *specs, const char *match_str)
t[0] = '\0';
t++;
}
return nm_match_spec_device(specs, NULL, NULL, s, t, NULL, NULL, NULL);
return nm_match_spec_device(specs,
&((const NMMatchSpecDeviceData){
.driver = s,
.driver_version = t,
}));
}
return nm_match_spec_device(specs, match_str, NULL, NULL, NULL, NULL, NULL, NULL);
return nm_match_spec_device(specs,
&((const NMMatchSpecDeviceData){
.interface_name = match_str,
}));
}
static void