mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-03-11 23:30:44 +01:00
merge: branch 'ih/perm_unmanaged'
add API to manage/unmanage devices in a persistent way https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2358
This commit is contained in:
commit
0e2b679afb
16 changed files with 995 additions and 70 deletions
3
NEWS
3
NEWS
|
|
@ -50,6 +50,9 @@ USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE!
|
|||
* Add support for GENEVE interface.
|
||||
* The DHCPv4 internal client now ignores option 3 (Router) if the lease
|
||||
contains option 121 (Classless Static Route), as recommended by RFC 3442.
|
||||
* Allow persisting the managed state across reboots from nmcli and the D-Bus API.
|
||||
* Allow changing the device's administrative state in the kernel at the same
|
||||
time as a change to the managed state from nmcli and the D-Bus API.
|
||||
|
||||
=============================================
|
||||
NetworkManager-1.56
|
||||
|
|
|
|||
|
|
@ -175,6 +175,9 @@
|
|||
property has a similar effect to configuring the device as unmanaged via
|
||||
the keyfile.unmanaged-devices setting in NetworkManager.conf. Changes to
|
||||
this value are not persistent and lost after NetworkManager restart.
|
||||
|
||||
DEPRECATED: 1.58: Use the SetManaged method instead, which supports
|
||||
additional features like persisting the state to disk
|
||||
-->
|
||||
<property name="Managed" type="b" access="readwrite"/>
|
||||
|
||||
|
|
@ -391,6 +394,20 @@
|
|||
-->
|
||||
<method name="Delete"/>
|
||||
|
||||
<!--
|
||||
SetManaged:
|
||||
@managed:(<link linkend="NMDeviceManaged">NMDeviceManaged</link>) Whether the device is managed. Possible values are "no" (0), "yes" (1) and "reset" (2).
|
||||
@flags: (<link linkend="NMDeviceManagedFlags">NMDeviceManagedFlags</link>) flags.
|
||||
@since: 1.58
|
||||
|
||||
Set the managed state of the device. With the flags argument different
|
||||
behaviors can be achieved, like storing the new managed state to disk.
|
||||
-->
|
||||
<method name="SetManaged">
|
||||
<arg name="managed" type="u" direction="in"/>
|
||||
<arg name="flags" type="u" direction="in"/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
StateChanged:
|
||||
@new_state: (<link linkend="NMDeviceState">NMDeviceState</link>) The new state of the device.
|
||||
|
|
|
|||
|
|
@ -1436,15 +1436,31 @@
|
|||
</arg>
|
||||
<arg>
|
||||
<option>managed</option>
|
||||
<group>
|
||||
<arg choice='plain'>--permanent</arg>
|
||||
<arg choice='plain'>--permanent-only</arg>
|
||||
</group>
|
||||
<group choice='req'>
|
||||
<arg choice='plain'>yes</arg>
|
||||
<arg choice='plain'>no</arg>
|
||||
<arg choice='plain'>up</arg>
|
||||
<arg choice='plain'>down</arg>
|
||||
<arg choice='plain'>reset</arg>
|
||||
</group>
|
||||
</arg>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
<para>Set device properties.</para>
|
||||
|
||||
<para>The <option>managed</option> property accepts a <option>--permanent</option>
|
||||
option to persist the managed state to disk, and not only in runtime. With
|
||||
<option>--permanent-only</option> only the permanent managed state is set, and not the
|
||||
runtime managed state. The special values <option>up</option> and <option>down</option>
|
||||
can be used to set the administrative state of the device at the same time as the runtime
|
||||
managed state. The <option>reset</option> value clears the explicit managed setting, and
|
||||
with <option>--permanent</option> or <option>--permanent-only</option> it also removes
|
||||
the persisted managed setting.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ src/core/NetworkManagerUtils.c
|
|||
src/core/devices/adsl/nm-device-adsl.c
|
||||
src/core/devices/bluetooth/nm-bluez-manager.c
|
||||
src/core/devices/bluetooth/nm-device-bt.c
|
||||
src/core/devices/nm-device.c
|
||||
src/core/devices/nm-device-6lowpan.c
|
||||
src/core/devices/nm-device-bond.c
|
||||
src/core/devices/nm-device-bridge.c
|
||||
|
|
|
|||
|
|
@ -14940,6 +14940,241 @@ impl_device_get_applied_connection(NMDBusObject *obj,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
NMDeviceManaged managed_state;
|
||||
NMDeviceManagedFlags managed_flags;
|
||||
} SetManagedData;
|
||||
|
||||
static gboolean
|
||||
get_managed_match_by_mac(NMDevice *self, NMDeviceManagedFlags flags, gboolean *out, GError **error)
|
||||
{
|
||||
gboolean is_fake_hwaddr;
|
||||
|
||||
nm_assert(out);
|
||||
|
||||
if ((flags & NM_DEVICE_MANAGED_FLAGS_PERMANENT_BY_MAC)
|
||||
&& (flags & NM_DEVICE_MANAGED_FLAGS_PERMANENT_BY_NAME)) {
|
||||
g_set_error_literal(error,
|
||||
NM_DEVICE_ERROR,
|
||||
NM_DEVICE_ERROR_INVALID_ARGUMENT,
|
||||
"cannot match both by 'mac' and by 'interface-name'");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
nm_device_get_permanent_hw_address_full(self, TRUE, &is_fake_hwaddr);
|
||||
|
||||
if ((flags & NM_DEVICE_MANAGED_FLAGS_PERMANENT_BY_MAC) && is_fake_hwaddr) {
|
||||
g_set_error_literal(
|
||||
error,
|
||||
NM_DEVICE_ERROR,
|
||||
NM_DEVICE_ERROR_INVALID_ARGUMENT,
|
||||
"cannot match by 'mac': the device doesn't have a permanent MAC address");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (flags & NM_DEVICE_MANAGED_FLAGS_PERMANENT_BY_MAC)
|
||||
*out = TRUE;
|
||||
else if (flags & NM_DEVICE_MANAGED_FLAGS_PERMANENT_BY_NAME)
|
||||
*out = FALSE;
|
||||
else
|
||||
*out = !is_fake_hwaddr;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* set_managed:
|
||||
* @self: the device
|
||||
* @managed: the new managed state to set.
|
||||
* @flags: flags to select different behaviors like storing to disk.
|
||||
* @error: return location for a #GError, or %NULL
|
||||
*
|
||||
* Sets the managed state of the device. It can affect the runtime managed state
|
||||
* if the %NM_DEVICE_MANAGED_FLAGS_RUNTIME is set, and to the value stored on disk
|
||||
* (persistent across reboots) state if the %NM_DEVICE_MANAGED_FLAGS_PERMANENT is set.
|
||||
*
|
||||
* Returns: %TRUE if the managed state was set successfully, %FALSE otherwise.
|
||||
*/
|
||||
static gboolean
|
||||
set_managed(NMDevice *self, NMDeviceManaged managed, NMDeviceManagedFlags flags, GError **error)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
|
||||
nm_assert(
|
||||
NM_IN_SET(managed, NM_DEVICE_MANAGED_NO, NM_DEVICE_MANAGED_YES, NM_DEVICE_MANAGED_RESET));
|
||||
nm_assert((flags & ~NM_DEVICE_MANAGED_FLAGS_ALL) == 0);
|
||||
|
||||
if (!NM_FLAGS_ANY(flags, NM_DEVICE_MANAGED_FLAGS_PERMANENT | NM_DEVICE_MANAGED_FLAGS_RUNTIME)) {
|
||||
g_set_error_literal(error,
|
||||
NM_DEVICE_ERROR,
|
||||
NM_DEVICE_ERROR_INVALID_ARGUMENT,
|
||||
_("set managed: no permanent or runtime was selected"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (flags & NM_DEVICE_MANAGED_FLAGS_PERMANENT) {
|
||||
NMTernary managed_to_disk, old = NM_TERNARY_DEFAULT;
|
||||
gboolean by_mac;
|
||||
|
||||
managed_to_disk = managed == NM_DEVICE_MANAGED_RESET ? NM_TERNARY_DEFAULT : !!managed;
|
||||
nm_config_get_device_managed(nm_manager_get_config(priv->manager), self, &old, NULL, error);
|
||||
if (!get_managed_match_by_mac(self, flags, &by_mac, error))
|
||||
return FALSE;
|
||||
|
||||
if (!nm_config_set_device_managed(nm_manager_get_config(priv->manager),
|
||||
self,
|
||||
managed_to_disk,
|
||||
by_mac,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
/* Update the unmanaged flags after the change on disk */
|
||||
nm_device_set_unmanaged_by_user_conf(self);
|
||||
|
||||
if (managed_to_disk != NM_TERNARY_DEFAULT
|
||||
&& managed_to_disk != !nm_device_get_unmanaged_flags(self, NM_UNMANAGED_USER_CONF)) {
|
||||
/* We failed to make the new state effective on disk. Maybe the new config
|
||||
* collides with other config. Try to revert and return error. Otherwise,
|
||||
* we would set the runtime state correctly, but get an unexpected state
|
||||
* after a reboot. */
|
||||
nm_config_set_device_managed(nm_manager_get_config(priv->manager),
|
||||
self,
|
||||
old,
|
||||
by_mac,
|
||||
NULL);
|
||||
g_set_error(error,
|
||||
NM_DEVICE_ERROR,
|
||||
NM_DEVICE_ERROR_FAILED,
|
||||
_("failed to persist 'managed=%d' on disk, other configurations may be "
|
||||
"overriding it"),
|
||||
managed);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & NM_DEVICE_MANAGED_FLAGS_RUNTIME) {
|
||||
if (managed == NM_DEVICE_MANAGED_RESET) {
|
||||
nm_device_set_unmanaged_by_flags(self,
|
||||
NM_UNMANAGED_USER_EXPLICIT,
|
||||
NM_UNMAN_FLAG_OP_FORGET,
|
||||
NM_DEVICE_STATE_REASON_UNMANAGED_USER_EXPLICIT);
|
||||
} else {
|
||||
g_object_set(self, NM_DEVICE_MANAGED, !!managed, NULL);
|
||||
|
||||
/* If requested, set the administrative state of the device to UP if the
|
||||
* new managed state is YES, and to DOWN if it's NO. */
|
||||
if (flags & NM_DEVICE_MANAGED_FLAGS_SET_ADMIN_STATE) {
|
||||
if (nm_device_get_ifindex(self))
|
||||
nm_platform_link_change_flags(nm_device_get_platform(self),
|
||||
nm_device_get_ifindex(self),
|
||||
IFF_UP,
|
||||
!!managed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
set_managed_cb(NMDevice *self,
|
||||
GDBusMethodInvocation *context,
|
||||
NMAuthSubject *subject,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
SetManagedData *set_managed_data = user_data;
|
||||
NMDeviceManaged managed;
|
||||
NMDeviceManagedFlags flags;
|
||||
GError *local = NULL;
|
||||
|
||||
managed = set_managed_data->managed_state;
|
||||
flags = set_managed_data->managed_flags;
|
||||
nm_g_slice_free(set_managed_data);
|
||||
|
||||
if (!error) {
|
||||
if (!NM_IN_SET(managed,
|
||||
NM_DEVICE_MANAGED_NO,
|
||||
NM_DEVICE_MANAGED_YES,
|
||||
NM_DEVICE_MANAGED_RESET))
|
||||
g_set_error_literal(&error,
|
||||
NM_DEVICE_ERROR,
|
||||
NM_DEVICE_ERROR_INVALID_ARGUMENT,
|
||||
"Invalid managed value");
|
||||
else if ((flags & ~NM_DEVICE_MANAGED_FLAGS_ALL) != 0)
|
||||
g_set_error_literal(&error,
|
||||
NM_DEVICE_ERROR,
|
||||
NM_DEVICE_ERROR_INVALID_ARGUMENT,
|
||||
"Invalid flags");
|
||||
}
|
||||
|
||||
if (error) {
|
||||
nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_MANAGED,
|
||||
self,
|
||||
FALSE,
|
||||
NULL,
|
||||
subject,
|
||||
error->message);
|
||||
g_dbus_method_invocation_return_gerror(context, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!set_managed(self, managed, flags, &local)) {
|
||||
nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_MANAGED,
|
||||
self,
|
||||
FALSE,
|
||||
NULL,
|
||||
subject,
|
||||
local->message);
|
||||
g_dbus_method_invocation_take_error(context, g_steal_pointer(&local));
|
||||
return;
|
||||
}
|
||||
|
||||
nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_MANAGED, self, TRUE, NULL, subject, NULL);
|
||||
g_dbus_method_invocation_return_value(context, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
impl_device_set_managed(NMDBusObject *obj,
|
||||
const NMDBusInterfaceInfoExtended *interface_info,
|
||||
const NMDBusMethodInfoExtended *method_info,
|
||||
GDBusConnection *connection,
|
||||
const char *sender,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GVariant *parameters)
|
||||
{
|
||||
NMDevice *self = NM_DEVICE(obj);
|
||||
gs_free_error GError *error = NULL;
|
||||
guint32 managed_u;
|
||||
NMDeviceManaged managed;
|
||||
guint32 flags_u;
|
||||
NMDeviceManagedFlags flags;
|
||||
SetManagedData *set_managed_data;
|
||||
|
||||
g_variant_get(parameters, "(uu)", &managed_u, &flags_u);
|
||||
|
||||
managed = managed_u;
|
||||
flags = flags_u;
|
||||
nm_assert(managed == managed_u && flags == flags_u);
|
||||
|
||||
set_managed_data = g_slice_new(SetManagedData);
|
||||
*set_managed_data = (SetManagedData) {
|
||||
.managed_state = managed,
|
||||
.managed_flags = flags,
|
||||
};
|
||||
|
||||
nm_device_auth_request(self,
|
||||
invocation,
|
||||
nm_device_get_applied_connection(self),
|
||||
NM_AUTH_PERMISSION_NETWORK_CONTROL,
|
||||
TRUE,
|
||||
NULL,
|
||||
set_managed_cb,
|
||||
set_managed_data);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
disconnect_cb(NMDevice *self,
|
||||
GDBusMethodInvocation *context,
|
||||
|
|
@ -19901,6 +20136,12 @@ static const NMDBusInterfaceInfoExtended interface_info_device = {
|
|||
NM_DEFINE_GDBUS_ARG_INFO("connection", "a{sa{sv}}"),
|
||||
NM_DEFINE_GDBUS_ARG_INFO("version_id", "t"), ), ),
|
||||
.handle = impl_device_get_applied_connection, ),
|
||||
NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(
|
||||
NM_DEFINE_GDBUS_METHOD_INFO_INIT("SetManaged",
|
||||
.in_args = NM_DEFINE_GDBUS_ARG_INFOS(
|
||||
NM_DEFINE_GDBUS_ARG_INFO("managed", "u"),
|
||||
NM_DEFINE_GDBUS_ARG_INFO("flags", "u"), ), ),
|
||||
.handle = impl_device_set_managed, ),
|
||||
NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(NM_DEFINE_GDBUS_METHOD_INFO_INIT("Disconnect", ),
|
||||
.handle = impl_device_disconnect, ),
|
||||
NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(NM_DEFINE_GDBUS_METHOD_INFO_INIT("Delete", ),
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ typedef struct {
|
|||
bool activation_lifetime_bound_to_profile_visibility : 1;
|
||||
bool settings_connection_is_unsaved : 1;
|
||||
bool settings_connection_is_shadowed_owned : 1;
|
||||
bool permanent_managed_by_mac : 1;
|
||||
NMUnmanFlagOp unmanaged_explicit;
|
||||
NMTernary permanent_managed;
|
||||
NMActivationReason activation_reason;
|
||||
gulong dev_exported_change_id;
|
||||
} DeviceCheckpoint;
|
||||
|
|
@ -496,14 +498,19 @@ nm_checkpoint_rollback(NMCheckpoint *self)
|
|||
/* Start rolling-back each device */
|
||||
g_hash_table_iter_init(&iter, priv->devices);
|
||||
while (g_hash_table_iter_next(&iter, (gpointer *) &device, (gpointer *) &dev_checkpoint)) {
|
||||
guint32 result = NM_ROLLBACK_RESULT_OK;
|
||||
guint32 result = NM_ROLLBACK_RESULT_OK;
|
||||
NMTernary perm_managed = NM_TERNARY_DEFAULT;
|
||||
gboolean perm_managed_by_mac = FALSE;
|
||||
gboolean force_perm_managed;
|
||||
|
||||
_LOGD("rollback: restoring device %s (state %d, realized %d, explicitly unmanaged %d, "
|
||||
"connection-unsaved %d, connection-shadowed %d, connection-shadowed-owned %d)",
|
||||
"permanently managed %d, connection-unsaved %d, connection-shadowed %d, "
|
||||
"connection-shadowed-owned %d)",
|
||||
dev_checkpoint->original_dev_name,
|
||||
(int) dev_checkpoint->state,
|
||||
dev_checkpoint->realized,
|
||||
dev_checkpoint->unmanaged_explicit,
|
||||
dev_checkpoint->permanent_managed,
|
||||
dev_checkpoint->settings_connection_is_unsaved,
|
||||
!!dev_checkpoint->settings_connection_shadowed,
|
||||
dev_checkpoint->settings_connection_is_shadowed_owned);
|
||||
|
|
@ -541,6 +548,43 @@ nm_checkpoint_rollback(NMCheckpoint *self)
|
|||
NM_DEVICE_STATE_REASON_NOW_MANAGED);
|
||||
}
|
||||
|
||||
force_perm_managed = !nm_config_get_device_managed(nm_config_get(),
|
||||
device,
|
||||
&perm_managed,
|
||||
&perm_managed_by_mac,
|
||||
NULL);
|
||||
|
||||
if (force_perm_managed || (perm_managed != dev_checkpoint->permanent_managed)
|
||||
|| (dev_checkpoint->permanent_managed != NM_TERNARY_DEFAULT
|
||||
&& perm_managed_by_mac != dev_checkpoint->permanent_managed_by_mac)) {
|
||||
gs_free_error GError *error = NULL;
|
||||
NMUnmanFlagOp set_op;
|
||||
|
||||
_LOGD("rollback: restore permanent managed state");
|
||||
|
||||
if (!nm_config_set_device_managed(nm_config_get(),
|
||||
device,
|
||||
dev_checkpoint->permanent_managed,
|
||||
dev_checkpoint->permanent_managed_by_mac,
|
||||
&error)) {
|
||||
_LOGE("rollback: failed to restore permanent managed state: %s", error->message);
|
||||
result = NM_ROLLBACK_RESULT_ERR_FAILED;
|
||||
/* even if this failed, we try to continue the rollback */
|
||||
}
|
||||
|
||||
if (dev_checkpoint->permanent_managed == NM_TERNARY_TRUE)
|
||||
set_op = NM_UNMAN_FLAG_OP_SET_MANAGED;
|
||||
else if (dev_checkpoint->permanent_managed == NM_TERNARY_FALSE)
|
||||
set_op = NM_UNMAN_FLAG_OP_SET_UNMANAGED;
|
||||
else
|
||||
set_op = NM_UNMAN_FLAG_OP_FORGET;
|
||||
|
||||
nm_device_set_unmanaged_by_flags_queue(device,
|
||||
NM_UNMANAGED_USER_CONF,
|
||||
set_op,
|
||||
NM_DEVICE_STATE_REASON_NOW_MANAGED);
|
||||
}
|
||||
|
||||
if (dev_checkpoint->state == NM_DEVICE_STATE_UNMANAGED) {
|
||||
if (nm_device_get_state(device) != NM_DEVICE_STATE_UNMANAGED
|
||||
|| dev_checkpoint->unmanaged_explicit == NM_UNMAN_FLAG_OP_SET_UNMANAGED) {
|
||||
|
|
@ -703,6 +747,8 @@ device_checkpoint_create(NMCheckpoint *self, NMDevice *device)
|
|||
NMSettingsConnection *settings_connection;
|
||||
const char *path;
|
||||
NMActRequest *act_request;
|
||||
gboolean perm_managed_by_mac;
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
nm_assert(NM_IS_DEVICE(device));
|
||||
nm_assert(nm_device_is_real(device));
|
||||
|
|
@ -728,12 +774,26 @@ device_checkpoint_create(NMCheckpoint *self, NMDevice *device)
|
|||
} else
|
||||
dev_checkpoint->unmanaged_explicit = NM_UNMAN_FLAG_OP_FORGET;
|
||||
|
||||
if (nm_config_get_device_managed(nm_config_get(),
|
||||
device,
|
||||
&dev_checkpoint->permanent_managed,
|
||||
&perm_managed_by_mac,
|
||||
NULL)) {
|
||||
dev_checkpoint->permanent_managed_by_mac = perm_managed_by_mac;
|
||||
} else {
|
||||
dev_checkpoint->permanent_managed = NM_TERNARY_DEFAULT;
|
||||
dev_checkpoint->permanent_managed_by_mac = FALSE;
|
||||
_LOGW("error getting permanent managed state for %s: %s",
|
||||
nm_device_get_iface(device),
|
||||
error->message);
|
||||
g_clear_error(&error);
|
||||
}
|
||||
|
||||
act_request = nm_device_get_act_request(device);
|
||||
if (act_request) {
|
||||
NMSettingsStorage *storage;
|
||||
gboolean shadowed_owned = FALSE;
|
||||
const char *shadowed_file;
|
||||
gs_free_error GError *error = NULL;
|
||||
NMSettingsStorage *storage;
|
||||
gboolean shadowed_owned = FALSE;
|
||||
const char *shadowed_file;
|
||||
|
||||
settings_connection = nm_act_request_get_settings_connection(act_request);
|
||||
applied_connection = nm_act_request_get_applied_connection(act_request);
|
||||
|
|
@ -764,6 +824,7 @@ device_checkpoint_create(NMCheckpoint *self, NMDevice *device)
|
|||
_LOGW("error reading shadowed connection file for %s: %s",
|
||||
nm_device_get_iface(device),
|
||||
error->message);
|
||||
g_clear_error(&error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2058,12 +2058,15 @@ _match_section_infos_construct(GKeyFile *keyfile, gboolean is_device)
|
|||
{
|
||||
char **groups;
|
||||
gsize i, j, ngroups;
|
||||
char *connection_tag = NULL;
|
||||
char *main_group = NULL;
|
||||
MatchSectionInfo *match_section_infos = NULL;
|
||||
const char *prefix;
|
||||
const char *prefix, *prefix_intern;
|
||||
|
||||
prefix =
|
||||
is_device ? NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE : NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION;
|
||||
prefix_intern =
|
||||
is_device ? NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE
|
||||
: NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION;
|
||||
|
||||
/* get the list of existing [connection.\+]/[device.\+] sections.
|
||||
*
|
||||
|
|
@ -2074,27 +2077,36 @@ _match_section_infos_construct(GKeyFile *keyfile, gboolean is_device)
|
|||
if (!groups)
|
||||
return NULL;
|
||||
|
||||
if (ngroups > 0) {
|
||||
gsize l = strlen(prefix);
|
||||
|
||||
for (i = 0, j = 0; i < ngroups; i++) {
|
||||
if (g_str_has_prefix(groups[i], prefix)) {
|
||||
if (groups[i][l] == '\0')
|
||||
connection_tag = groups[i];
|
||||
else
|
||||
groups[j++] = groups[i];
|
||||
} else
|
||||
g_free(groups[i]);
|
||||
for (i = 0, j = 0; i < ngroups; i++) {
|
||||
if (nm_streq0(groups[i], prefix)) {
|
||||
main_group = groups[i];
|
||||
} else if (nm_streq0(groups[i], prefix_intern)) {
|
||||
/* [.intern.connection] and [.intern.device] should not exist */
|
||||
_nm_log(LOGL_WARN,
|
||||
LOGD_CORE,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
"Invalid [.intern.*] section 'connection' or 'device' found");
|
||||
g_free(groups[i]);
|
||||
continue;
|
||||
} else if (g_str_has_prefix(groups[i], prefix)) {
|
||||
groups[j++] = groups[i];
|
||||
} else if (g_str_has_prefix(groups[i], prefix_intern)) {
|
||||
/* [.intern.connection-whatever] and [.intern.device-whatever] can exist */
|
||||
groups[j++] = groups[i];
|
||||
} else {
|
||||
g_free(groups[i]);
|
||||
}
|
||||
ngroups = j;
|
||||
}
|
||||
ngroups = j;
|
||||
|
||||
if (ngroups == 0 && !connection_tag) {
|
||||
if (ngroups == 0 && !main_group) {
|
||||
g_free(groups);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
match_section_infos = g_new0(MatchSectionInfo, ngroups + 1 + (connection_tag ? 1 : 0));
|
||||
match_section_infos = g_new0(MatchSectionInfo, ngroups + 1 + (main_group ? 1 : 0));
|
||||
match_section_infos->is_device = is_device;
|
||||
for (i = 0; i < ngroups; i++) {
|
||||
/* pass ownership of @group on... */
|
||||
|
|
@ -2103,9 +2115,9 @@ _match_section_infos_construct(GKeyFile *keyfile, gboolean is_device)
|
|||
groups[ngroups - i - 1],
|
||||
is_device);
|
||||
}
|
||||
if (connection_tag) {
|
||||
/* pass ownership of @connection_tag on... */
|
||||
_match_section_info_init(&match_section_infos[i], keyfile, connection_tag, is_device);
|
||||
if (main_group) {
|
||||
/* pass ownership of @main_group on... */
|
||||
_match_section_info_init(&match_section_infos[i], keyfile, main_group, is_device);
|
||||
}
|
||||
g_free(groups);
|
||||
|
||||
|
|
|
|||
|
|
@ -2076,6 +2076,210 @@ nm_config_set_connectivity_check_enabled(NMConfig *self, gboolean enabled)
|
|||
g_key_file_unref(keyfile);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
normalize_hwaddr_for_group_name(const char *hwaddr, char *out, GError **error)
|
||||
{
|
||||
guint8 hwaddr_bin[NM_UTILS_HWADDR_LEN_MAX];
|
||||
gsize hwaddr_bin_len;
|
||||
|
||||
if (!_nm_utils_hwaddr_aton(hwaddr, hwaddr_bin, sizeof(hwaddr_bin), &hwaddr_bin_len)) {
|
||||
g_set_error(error,
|
||||
NM_DEVICE_ERROR,
|
||||
NM_DEVICE_ERROR_INVALID_ARGUMENT,
|
||||
"Invalid MAC address: %s",
|
||||
hwaddr);
|
||||
return FALSE;
|
||||
}
|
||||
nm_utils_bin2hexstr_full(hwaddr_bin, hwaddr_bin_len, '-', TRUE, out);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_config_get_device_managed:
|
||||
* @self: the NMConfig instance
|
||||
* @device: the interface
|
||||
* @out: (out): the managed state of the device
|
||||
* @error: return location for a #GError, or %NULL
|
||||
*
|
||||
* Returns: TRUE if there were no errors, FALSE otherwise.
|
||||
*/
|
||||
gboolean
|
||||
nm_config_get_device_managed(NMConfig *self,
|
||||
NMDevice *device,
|
||||
NMTernary *out_managed,
|
||||
gboolean *out_by_mac,
|
||||
GError **error)
|
||||
{
|
||||
NMConfigPrivate *priv;
|
||||
const GKeyFile *keyfile = NULL;
|
||||
gs_free char *group_by_name = NULL;
|
||||
gs_free char *group_by_mac = NULL;
|
||||
const char *ifname = nm_device_get_iface(device);
|
||||
const char *hwaddr = nm_device_get_permanent_hw_address(device);
|
||||
char mac_group_name[NM_UTILS_HWADDR_LEN_MAX * 3 + 1];
|
||||
NMTernary val_by_name, val_by_mac = NM_TERNARY_DEFAULT;
|
||||
|
||||
g_return_val_if_fail(NM_IS_CONFIG(self), FALSE);
|
||||
g_return_val_if_fail(NM_CONFIG_GET_PRIVATE(self)->config_data, FALSE);
|
||||
g_return_val_if_fail(out_managed, FALSE);
|
||||
g_return_val_if_fail(ifname, FALSE);
|
||||
|
||||
priv = NM_CONFIG_GET_PRIVATE(self);
|
||||
keyfile = _nm_config_data_get_keyfile_intern(priv->config_data);
|
||||
|
||||
if (!keyfile) {
|
||||
NM_SET_OUT(out_managed, NM_TERNARY_DEFAULT);
|
||||
NM_SET_OUT(out_by_mac, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
group_by_name =
|
||||
g_strdup_printf(NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_DEVICE "-manage-%s", ifname);
|
||||
|
||||
val_by_name = (NMTernary) nm_config_keyfile_get_boolean(keyfile,
|
||||
group_by_name,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED,
|
||||
NM_TERNARY_DEFAULT);
|
||||
|
||||
/* Devices without a kernel link (i.e. OVS ports) don't have a MAC address */
|
||||
if (hwaddr) {
|
||||
if (!normalize_hwaddr_for_group_name(hwaddr, mac_group_name, error))
|
||||
return FALSE;
|
||||
|
||||
group_by_mac = g_strdup_printf(NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_DEVICE "-manage-%s",
|
||||
mac_group_name);
|
||||
|
||||
val_by_mac = (NMTernary) nm_config_keyfile_get_boolean(keyfile,
|
||||
group_by_mac,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED,
|
||||
NM_TERNARY_DEFAULT);
|
||||
}
|
||||
|
||||
if (val_by_name != NM_TERNARY_DEFAULT && val_by_mac == NM_TERNARY_DEFAULT) {
|
||||
NM_SET_OUT(out_managed, val_by_name);
|
||||
NM_SET_OUT(out_by_mac, FALSE);
|
||||
return TRUE;
|
||||
} else if (val_by_mac != NM_TERNARY_DEFAULT && val_by_name == NM_TERNARY_DEFAULT) {
|
||||
NM_SET_OUT(out_managed, val_by_mac);
|
||||
NM_SET_OUT(out_by_mac, TRUE);
|
||||
return TRUE;
|
||||
} else if (val_by_name == NM_TERNARY_DEFAULT && val_by_mac == NM_TERNARY_DEFAULT) {
|
||||
NM_SET_OUT(out_managed, NM_TERNARY_DEFAULT);
|
||||
NM_SET_OUT(out_by_mac, FALSE);
|
||||
return TRUE;
|
||||
} else if (val_by_name == val_by_mac) {
|
||||
NM_SET_OUT(out_managed, val_by_name);
|
||||
NM_SET_OUT(out_by_mac, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_set_error(error,
|
||||
NM_DEVICE_ERROR,
|
||||
NM_DEVICE_ERROR_FAILED,
|
||||
"Multiple managed states found for device: %s",
|
||||
nm_device_get_iface(device));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_config_set_device_managed:
|
||||
* @self: the NMConfig instance
|
||||
* @device: the NMDevice instance associated with this config change
|
||||
* @managed: the managed state to set
|
||||
* @by_mac: if %TRUE, match by MAC address, otherwise by interface name. This is
|
||||
* only used when @managed = TRUE.
|
||||
* @error: return location for a #GError, or %NULL
|
||||
*
|
||||
* Sets the managed state of the device to the intern keyfile. Here we store the
|
||||
* configuration received via the D-Bus API. Configurations from other config
|
||||
* files are still in place and may have higher precedence.
|
||||
*
|
||||
* Prior to setting the new state, the existing configuration is removed. If
|
||||
* @managed is set to %NM_TERNARY_DEFAULT, we only do the removal of the previous
|
||||
* configuration.
|
||||
*/
|
||||
gboolean
|
||||
nm_config_set_device_managed(NMConfig *self,
|
||||
NMDevice *device,
|
||||
NMTernary managed,
|
||||
gboolean by_mac,
|
||||
GError **error)
|
||||
{
|
||||
NMConfigPrivate *priv;
|
||||
g_autoptr(GKeyFile) keyfile = NULL;
|
||||
char *group;
|
||||
gs_free char *group_by_name = NULL;
|
||||
gs_free char *group_by_mac = NULL;
|
||||
gs_free char *match_value = NULL;
|
||||
gboolean changed = FALSE;
|
||||
const char *ifname = nm_device_get_iface(device);
|
||||
const char *hwaddr = nm_device_get_permanent_hw_address(device);
|
||||
char mac_group_name[NM_UTILS_HWADDR_LEN_MAX * 3 + 1];
|
||||
|
||||
g_return_val_if_fail(NM_IS_CONFIG(self), FALSE);
|
||||
g_return_val_if_fail(NM_CONFIG_GET_PRIVATE(self)->config_data, FALSE);
|
||||
g_return_val_if_fail(ifname, FALSE);
|
||||
|
||||
if (by_mac && !hwaddr) {
|
||||
g_set_error(error,
|
||||
NM_DEVICE_ERROR,
|
||||
NM_DEVICE_ERROR_INVALID_ARGUMENT,
|
||||
"the device has no MAC address, but match by MAC was requested");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (hwaddr && !normalize_hwaddr_for_group_name(hwaddr, mac_group_name, error))
|
||||
return FALSE;
|
||||
|
||||
priv = NM_CONFIG_GET_PRIVATE(self);
|
||||
keyfile = nm_config_data_clone_keyfile_intern(priv->config_data);
|
||||
|
||||
/* Remove existing configs. Search them by group name [.intern.device-manage-*]. In
|
||||
* the intern file, 'device-manage' sections are only used for this purpose, so we
|
||||
* won't remove any other device's config. */
|
||||
group_by_name =
|
||||
g_strdup_printf(NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_DEVICE "-manage-%s", ifname);
|
||||
|
||||
if (g_key_file_remove_group(keyfile, group_by_name, NULL))
|
||||
changed = TRUE;
|
||||
|
||||
/* Devices without a kernel link (i.e. OVS ports) don't have a MAC address */
|
||||
if (hwaddr) {
|
||||
group_by_mac = g_strdup_printf(NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_DEVICE "-manage-%s",
|
||||
mac_group_name);
|
||||
|
||||
if (g_key_file_remove_group(keyfile, group_by_mac, NULL))
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
/* If the new state is not explicitly TRUE of FALSE, we only remove the configs */
|
||||
if (managed == NM_TERNARY_DEFAULT)
|
||||
goto done;
|
||||
|
||||
/* Set new values */
|
||||
if (by_mac) {
|
||||
group = group_by_mac;
|
||||
match_value = g_strdup_printf("mac:%s", hwaddr);
|
||||
} else {
|
||||
group = group_by_name;
|
||||
match_value = g_strdup_printf("interface-name:=%s", ifname);
|
||||
}
|
||||
|
||||
g_key_file_set_value(keyfile, group, NM_CONFIG_KEYFILE_KEY_MATCH_DEVICE, match_value);
|
||||
g_key_file_set_value(keyfile, group, NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED, managed ? "1" : "0");
|
||||
changed = TRUE;
|
||||
|
||||
done:
|
||||
if (changed)
|
||||
nm_config_set_values(self, keyfile, TRUE, FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* nm_config_set_values:
|
||||
* @self: the NMConfig instance
|
||||
|
|
|
|||
|
|
@ -142,6 +142,17 @@ gboolean nm_config_set_global_dns(NMConfig *self, NMGlobalDnsConfig *global_dns,
|
|||
|
||||
void nm_config_set_connectivity_check_enabled(NMConfig *self, gboolean enabled);
|
||||
|
||||
gboolean nm_config_get_device_managed(NMConfig *self,
|
||||
NMDevice *device,
|
||||
NMTernary *out_managed,
|
||||
gboolean *out_by_mac,
|
||||
GError **error);
|
||||
gboolean nm_config_set_device_managed(NMConfig *self,
|
||||
NMDevice *device,
|
||||
NMTernary managed,
|
||||
gboolean by_mac,
|
||||
GError **error);
|
||||
|
||||
/* internal defines ... */
|
||||
extern guint _nm_config_match_nm_version;
|
||||
extern char *_nm_config_match_env;
|
||||
|
|
|
|||
|
|
@ -311,6 +311,108 @@ test_config_override(void)
|
|||
g_assert_cmpstr(plugins[3], ==, "delta");
|
||||
}
|
||||
|
||||
static void
|
||||
test_config_managed(void)
|
||||
{
|
||||
NMConfig *config;
|
||||
const char *CONFIG_USER = BUILD_DIR "/test-config-managed.conf";
|
||||
const char *CONFIG_INTERN = BUILD_DIR "/test-config-managed-intern.conf";
|
||||
NMDevice *dev;
|
||||
gs_free char *group_by_name = NULL;
|
||||
const char *ifname, *group_by_mac;
|
||||
NMTernary managed;
|
||||
gboolean by_mac;
|
||||
GKeyFile *kf = nm_config_create_keyfile();
|
||||
|
||||
dev = nm_test_device_new("11:11:11:11:11:11");
|
||||
ifname = nm_device_get_iface(dev);
|
||||
group_by_name =
|
||||
g_strdup_printf(NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_DEVICE "-manage-%s", ifname);
|
||||
group_by_mac = NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_DEVICE "-manage-11-11-11-11-11-11";
|
||||
|
||||
g_assert(g_file_set_contents(CONFIG_USER, "", 0, NULL));
|
||||
g_assert(g_file_set_contents(CONFIG_INTERN, "", 0, NULL));
|
||||
|
||||
config = setup_config(NULL, CONFIG_USER, CONFIG_INTERN, NULL, "/no/such/dir", "", NULL);
|
||||
|
||||
g_assert(nm_config_get_device_managed(config, dev, &managed, NULL, NULL));
|
||||
g_assert_cmpint(managed, ==, NM_TERNARY_DEFAULT);
|
||||
|
||||
/* Matching by name */
|
||||
NMTST_EXPECT_NM_INFO("config: signal: *");
|
||||
g_assert(nm_config_set_device_managed(config, dev, NM_TERNARY_TRUE, FALSE, NULL));
|
||||
g_assert(nm_config_get_device_managed(config, dev, &managed, &by_mac, NULL));
|
||||
g_assert_cmpint(managed, ==, NM_TERNARY_TRUE);
|
||||
g_assert_false(by_mac);
|
||||
g_key_file_load_from_file(kf, CONFIG_INTERN, G_KEY_FILE_NONE, NULL);
|
||||
g_assert_false(g_key_file_has_key(kf, group_by_mac, "managed", NULL));
|
||||
g_assert_true(g_key_file_has_key(kf, group_by_name, "managed", NULL));
|
||||
g_assert_cmpint(g_key_file_get_integer(kf, group_by_name, "managed", NULL), ==, 1);
|
||||
|
||||
NMTST_EXPECT_NM_INFO("config: signal: *");
|
||||
g_assert(nm_config_set_device_managed(config, dev, NM_TERNARY_FALSE, FALSE, NULL));
|
||||
g_assert(nm_config_get_device_managed(config, dev, &managed, &by_mac, NULL));
|
||||
g_assert_cmpint(managed, ==, NM_TERNARY_FALSE);
|
||||
g_assert_false(by_mac);
|
||||
g_key_file_load_from_file(kf, CONFIG_INTERN, G_KEY_FILE_NONE, NULL);
|
||||
g_assert_false(g_key_file_has_key(kf, group_by_mac, "managed", NULL));
|
||||
g_assert_true(g_key_file_has_key(kf, group_by_name, "managed", NULL));
|
||||
g_assert_cmpint(g_key_file_get_integer(kf, group_by_name, "managed", NULL), ==, 0);
|
||||
|
||||
/* Matching by MAC address */
|
||||
NMTST_EXPECT_NM_INFO("config: signal: *");
|
||||
g_assert(nm_config_set_device_managed(config, dev, NM_TERNARY_TRUE, TRUE, NULL));
|
||||
g_assert(nm_config_get_device_managed(config, dev, &managed, &by_mac, NULL));
|
||||
g_assert_cmpint(managed, ==, NM_TERNARY_TRUE);
|
||||
g_assert_true(by_mac);
|
||||
g_key_file_load_from_file(kf, CONFIG_INTERN, G_KEY_FILE_NONE, NULL);
|
||||
g_assert_false(g_key_file_has_key(kf, group_by_name, "managed", NULL));
|
||||
g_assert_true(g_key_file_has_key(kf, group_by_mac, "managed", NULL));
|
||||
g_assert_cmpint(g_key_file_get_integer(kf, group_by_mac, "managed", NULL), ==, 1);
|
||||
|
||||
NMTST_EXPECT_NM_INFO("config: signal: *");
|
||||
g_assert(nm_config_set_device_managed(config, dev, NM_TERNARY_FALSE, TRUE, NULL));
|
||||
g_assert(nm_config_get_device_managed(config, dev, &managed, &by_mac, NULL));
|
||||
g_assert_cmpint(managed, ==, NM_TERNARY_FALSE);
|
||||
g_assert_true(by_mac);
|
||||
g_key_file_load_from_file(kf, CONFIG_INTERN, G_KEY_FILE_NONE, NULL);
|
||||
g_assert_false(g_key_file_has_key(kf, group_by_name, "managed", NULL));
|
||||
g_assert_true(g_key_file_has_key(kf, group_by_mac, "managed", NULL));
|
||||
g_assert_cmpint(g_key_file_get_integer(kf, group_by_mac, "managed", NULL), ==, 0);
|
||||
|
||||
/* Resetting the managed state */
|
||||
NMTST_EXPECT_NM_INFO("config: signal: *");
|
||||
g_assert(nm_config_set_device_managed(config, dev, NM_TERNARY_DEFAULT, FALSE, NULL));
|
||||
g_assert(nm_config_get_device_managed(config, dev, &managed, NULL, NULL));
|
||||
g_assert_cmpint(managed, ==, NM_TERNARY_DEFAULT);
|
||||
g_key_file_load_from_file(kf, CONFIG_INTERN, G_KEY_FILE_NONE, NULL);
|
||||
g_assert_false(g_key_file_has_key(kf, group_by_name, "managed", NULL));
|
||||
g_assert_false(g_key_file_has_key(kf, group_by_mac, "managed", NULL));
|
||||
|
||||
g_object_unref(config);
|
||||
|
||||
/* Both values set in the intern config file, different values */
|
||||
g_key_file_set_string(kf, group_by_name, "managed", "1");
|
||||
g_key_file_set_string(kf, group_by_mac, "managed", "0");
|
||||
g_assert(g_key_file_save_to_file(kf, CONFIG_INTERN, NULL));
|
||||
config = setup_config(NULL, CONFIG_USER, CONFIG_INTERN, NULL, "/no/such/dir", "", NULL);
|
||||
g_assert(!nm_config_get_device_managed(config, dev, &managed, NULL, NULL));
|
||||
|
||||
g_object_unref(config);
|
||||
|
||||
/* Both values set in the intern config file, same values */
|
||||
g_key_file_set_string(kf, group_by_name, "managed", "1");
|
||||
g_key_file_set_string(kf, group_by_mac, "managed", "1");
|
||||
g_assert(g_key_file_save_to_file(kf, CONFIG_INTERN, NULL));
|
||||
config = setup_config(NULL, CONFIG_USER, CONFIG_INTERN, NULL, "/no/such/dir", "", NULL);
|
||||
g_assert(nm_config_get_device_managed(config, dev, &managed, NULL, NULL));
|
||||
g_assert_cmpint(managed, ==, NM_TERNARY_TRUE);
|
||||
|
||||
g_key_file_unref(kf);
|
||||
g_object_unref(dev);
|
||||
g_object_unref(config);
|
||||
}
|
||||
|
||||
static void
|
||||
test_config_global_dns(void)
|
||||
{
|
||||
|
|
@ -1412,6 +1514,7 @@ main(int argc, char **argv)
|
|||
|
||||
g_test_add_func("/config/set-values", test_config_set_values);
|
||||
g_test_add_func("/config/global-dns", test_config_global_dns);
|
||||
g_test_add_func("/config/managed", test_config_managed);
|
||||
g_test_add_func("/config/connectivity-check", test_config_connectivity_check);
|
||||
|
||||
g_test_add_func("/config/signal", test_config_signal);
|
||||
|
|
|
|||
|
|
@ -90,4 +90,7 @@
|
|||
#define NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_GLOBAL_DNS_DOMAIN \
|
||||
NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN NM_CONFIG_KEYFILE_GROUPPREFIX_GLOBAL_DNS_DOMAIN
|
||||
|
||||
#define NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_DEVICE \
|
||||
NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE
|
||||
|
||||
#endif /* __NM_CONFIG_BASE_H__ */
|
||||
|
|
|
|||
|
|
@ -2114,6 +2114,10 @@ global:
|
|||
nm_device_geneve_get_tos;
|
||||
nm_device_geneve_get_ttl;
|
||||
nm_device_geneve_get_type;
|
||||
nm_device_managed_flags_get_type;
|
||||
nm_device_managed_get_type;
|
||||
nm_device_set_managed_async;
|
||||
nm_device_set_managed_finish;
|
||||
nm_ip_config_get_clat_address;
|
||||
nm_ip_config_get_clat_pref64;
|
||||
nm_setting_geneve_df_get_type;
|
||||
|
|
|
|||
|
|
@ -1446,9 +1446,7 @@ nm_device_get_managed(NMDevice *device)
|
|||
*
|
||||
* Since: 1.2
|
||||
*
|
||||
* Deprecated: 1.22: Use the async command nm_client_dbus_set_property() on
|
||||
* nm_object_get_path(), interface %NM_DBUS_INTERFACE_DEVICE to set the
|
||||
* "Managed" property to a "(b)" boolean value.
|
||||
* Deprecated: 1.22: Use nm_device_set_managed_async() instead.
|
||||
* This function is deprecated because it calls a synchronous D-Bus method
|
||||
* and modifies the content of the NMClient cache client side. Also, it does
|
||||
* not emit a property changed signal.
|
||||
|
|
@ -1470,6 +1468,72 @@ nm_device_set_managed(NMDevice *device, gboolean managed)
|
|||
managed);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_device_set_managed_async:
|
||||
* @device: a #NMDevice
|
||||
* @managed: the managed state
|
||||
* @flags: the flags argument. See #NMDeviceManagedFlags.
|
||||
* @cancellable: a #GCancellable, or %NULL
|
||||
* @callback: callback to be called when the set_managed operation completes
|
||||
* @user_data: caller-specific data passed to @callback
|
||||
*
|
||||
* Asynchronously begins setting the managed state of the device. With the flags
|
||||
* argument different behaviors can be achieved, such as persisting the state to
|
||||
* disk or matching the device by MAC address.
|
||||
*
|
||||
* Since: 1.58
|
||||
**/
|
||||
void
|
||||
nm_device_set_managed_async(NMDevice *device,
|
||||
NMDeviceManaged managed,
|
||||
NMDeviceManagedFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_return_if_fail(NM_IS_DEVICE(device));
|
||||
g_return_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable));
|
||||
|
||||
_nm_client_dbus_call(_nm_object_get_client(device),
|
||||
device,
|
||||
nm_device_set_managed_async,
|
||||
cancellable,
|
||||
callback,
|
||||
user_data,
|
||||
_nm_object_get_path(device),
|
||||
NM_DBUS_INTERFACE_DEVICE,
|
||||
"SetManaged",
|
||||
g_variant_new("(uu)", managed, flags),
|
||||
G_VARIANT_TYPE("()"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
NM_DBUS_DEFAULT_TIMEOUT_MSEC,
|
||||
nm_dbus_connection_call_finish_void_strip_dbus_error_cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_device_set_managed_finish:
|
||||
* @device: a #NMDevice
|
||||
* @result: the result passed to the #GAsyncReadyCallback
|
||||
* @error: location for a #GError, or %NULL
|
||||
*
|
||||
* Gets the result of a call to nm_device_set_managed_async().
|
||||
*
|
||||
* Returns: %TRUE on success, %FALSE on error, in which case @error
|
||||
* will be set.
|
||||
*
|
||||
* Since: 1.58
|
||||
**/
|
||||
gboolean
|
||||
nm_device_set_managed_finish(NMDevice *device, GAsyncResult *result, GError **error)
|
||||
{
|
||||
g_return_val_if_fail(NM_IS_DEVICE(device), FALSE);
|
||||
g_return_val_if_fail(nm_g_task_is_valid(result, device, nm_device_set_managed_async), FALSE);
|
||||
|
||||
return g_task_propagate_boolean(G_TASK(result), error);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* nm_device_get_autoconnect:
|
||||
* @device: a #NMDevice
|
||||
|
|
|
|||
|
|
@ -150,6 +150,15 @@ NM_AVAILABLE_IN_1_2
|
|||
NM_DEPRECATED_IN_1_22
|
||||
_NM_DEPRECATED_SYNC_METHOD
|
||||
void nm_device_set_managed(NMDevice *device, gboolean managed);
|
||||
NM_AVAILABLE_IN_1_58
|
||||
void nm_device_set_managed_async(NMDevice *device,
|
||||
NMDeviceManaged managed,
|
||||
NMDeviceManagedFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
NM_AVAILABLE_IN_1_58
|
||||
gboolean nm_device_set_managed_finish(NMDevice *device, GAsyncResult *result, GError **error);
|
||||
|
||||
gboolean nm_device_get_autoconnect(NMDevice *device);
|
||||
|
||||
|
|
|
|||
|
|
@ -1248,6 +1248,54 @@ typedef enum /*< flags >*/ {
|
|||
NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP = 0x1,
|
||||
} NMDeviceReapplyFlags;
|
||||
|
||||
/**
|
||||
* NMDeviceManaged:
|
||||
* @NM_DEVICE_MANAGED_NO: the device is not managed.
|
||||
* @NM_DEVICE_MANAGED_YES: the device is managed.
|
||||
* @NM_DEVICE_MANAGED_RESET: reset the device managed state to the default value.
|
||||
*
|
||||
* Values for the SetManaged() D-Bus call of a device and nm_device_set_managed_async().
|
||||
*
|
||||
* Since: 1.58
|
||||
*/
|
||||
typedef enum {
|
||||
NM_DEVICE_MANAGED_NO = 0,
|
||||
NM_DEVICE_MANAGED_YES = 1,
|
||||
NM_DEVICE_MANAGED_RESET = 2,
|
||||
} NMDeviceManaged;
|
||||
|
||||
/**
|
||||
* NMDeviceManagedFlags:
|
||||
* @NM_DEVICE_MANAGED_FLAGS_NONE: no flag set.
|
||||
* @NM_DEVICE_MANAGED_FLAGS_RUNTIME: to set the device managed state to the runtime value.
|
||||
* @NM_DEVICE_MANAGED_FLAGS_PERMANENT: to set the device managed state to the permanent (on disk) value.
|
||||
* @NM_DEVICE_MANAGED_FLAGS_PERMANENT_BY_NAME: to match the device by name, not by MAC address.
|
||||
* @NM_DEVICE_MANAGED_FLAGS_PERMANENT_BY_MAC: to match the device by MAC address, not by name.
|
||||
* @NM_DEVICE_MANAGED_FLAGS_SET_ADMIN_STATE: to set the administrative state of the
|
||||
* device to up if the managed state is %NM_DEVICE_MANAGED_YES, and down if the managed state
|
||||
* is %NM_DEVICE_MANAGED_NO. If the flag is not set, the administrative state is not changed.
|
||||
* The flag is ignored for %NM_DEVICE_MANAGED_RESET.
|
||||
* @NM_DEVICE_MANAGED_FLAGS_ALL: all flags.
|
||||
*
|
||||
* Flags for the SetManaged() D-Bus call of a device and nm_device_set_managed_async().
|
||||
*
|
||||
* %NM_DEVICE_MANAGED_FLAGS_PERMANENT_BY_NAME and %NM_DEVICE_MANAGED_FLAGS_PERMANENT_BY_MAC
|
||||
* are mutually exclusive, and they only make sense together with %NM_DEVICE_MANAGED_FLAGS_PERMANENT.
|
||||
* If none is set, the matching criteria is selected automatically.
|
||||
*
|
||||
* Since: 1.58
|
||||
*/
|
||||
typedef enum /*< flags >*/ {
|
||||
NM_DEVICE_MANAGED_FLAGS_NONE = 0,
|
||||
NM_DEVICE_MANAGED_FLAGS_RUNTIME = 0x1,
|
||||
NM_DEVICE_MANAGED_FLAGS_PERMANENT = 0x2,
|
||||
NM_DEVICE_MANAGED_FLAGS_PERMANENT_BY_NAME = 0x4,
|
||||
NM_DEVICE_MANAGED_FLAGS_PERMANENT_BY_MAC = 0x8,
|
||||
NM_DEVICE_MANAGED_FLAGS_SET_ADMIN_STATE = 0x10,
|
||||
|
||||
NM_DEVICE_MANAGED_FLAGS_ALL = 0x1F, /* <skip> */
|
||||
} NMDeviceManagedFlags;
|
||||
|
||||
/**
|
||||
* NMTernary:
|
||||
* @NM_TERNARY_DEFAULT: use the globally-configured default value.
|
||||
|
|
|
|||
|
|
@ -857,7 +857,8 @@ usage(void)
|
|||
"delete | monitor | wifi | lldp }\n\n"
|
||||
" status\n\n"
|
||||
" show [<ifname>]\n\n"
|
||||
" set [ifname] <ifname> [autoconnect yes|no] [managed yes|no]\n\n"
|
||||
" set [ifname] <ifname> [autoconnect yes|no] [managed [--permanent|--permanent-only] "
|
||||
"yes|no|up|down|reset]\n\n"
|
||||
" connect <ifname>\n\n"
|
||||
" reapply <ifname>\n\n"
|
||||
" modify <ifname> ([+|-]<setting>.<property> <value>)+\n\n"
|
||||
|
|
@ -975,14 +976,15 @@ usage_device_delete(void)
|
|||
static void
|
||||
usage_device_set(void)
|
||||
{
|
||||
nmc_printerr(_("Usage: nmcli device set { ARGUMENTS | help }\n"
|
||||
"\n"
|
||||
"ARGUMENTS := DEVICE { PROPERTY [ PROPERTY ... ] }\n"
|
||||
"DEVICE := [ifname] <ifname> \n"
|
||||
"PROPERTY := { autoconnect { yes | no } |\n"
|
||||
" { managed { yes | no }\n"
|
||||
"\n"
|
||||
"Modify device properties.\n\n"));
|
||||
nmc_printerr(_(
|
||||
"Usage: nmcli device set { ARGUMENTS | help }\n"
|
||||
"\n"
|
||||
"ARGUMENTS := DEVICE { PROPERTY [ PROPERTY ... ] }\n"
|
||||
"DEVICE := [ifname] <ifname> \n"
|
||||
"PROPERTY := { autoconnect { yes | no } |\n"
|
||||
" { managed [--permanent | --permanent-only] { yes | no | up | down | reset }\n"
|
||||
"\n"
|
||||
"Modify device properties.\n\n"));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -2816,20 +2818,62 @@ do_devices_delete(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const
|
|||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
NmCli *nmc;
|
||||
GSource *timeout_source;
|
||||
} DeviceSetCbInfo;
|
||||
|
||||
static void
|
||||
device_set_cb_info_finish(DeviceSetCbInfo *info)
|
||||
{
|
||||
nm_clear_g_source_inst(&info->timeout_source);
|
||||
g_slice_free(DeviceSetCbInfo, info);
|
||||
quit();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
device_set_timeout_cb(gpointer user_data)
|
||||
{
|
||||
DeviceSetCbInfo *cb_info = user_data;
|
||||
|
||||
timeout_cb(cb_info->nmc);
|
||||
device_set_cb_info_finish(cb_info);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
device_set_cb(GObject *object, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
NMDevice *device = NM_DEVICE(object);
|
||||
DeviceSetCbInfo *info = (DeviceSetCbInfo *) user_data;
|
||||
NmCli *nmc = info->nmc;
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
/* Only 'managed' is treated asynchronously, 'autoconnect' is treated synchronously */
|
||||
if (!nm_device_set_managed_finish(device, result, &error)) {
|
||||
g_string_printf(nmc->return_text, _("Error: set managed failed: %s."), error->message);
|
||||
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
device_set_cb_info_finish(info);
|
||||
}
|
||||
|
||||
static void
|
||||
do_device_set(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv)
|
||||
{
|
||||
#define DEV_SET_AUTOCONNECT 0
|
||||
#define DEV_SET_MANAGED 1
|
||||
NMDevice *device = NULL;
|
||||
int i;
|
||||
NMDevice *device = NULL;
|
||||
DeviceSetCbInfo *cb_info = NULL;
|
||||
int i;
|
||||
struct {
|
||||
int idx;
|
||||
gboolean value;
|
||||
} values[2] = {
|
||||
[DEV_SET_AUTOCONNECT] = {-1},
|
||||
[DEV_SET_MANAGED] = {-1},
|
||||
};
|
||||
} autoconnect_data = {-1};
|
||||
struct {
|
||||
int idx;
|
||||
NMDeviceManaged value;
|
||||
guint32 flags;
|
||||
} managed_data = {-1};
|
||||
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
next_arg(nmc, &argc, &argv, NULL);
|
||||
|
|
@ -2851,49 +2895,120 @@ do_device_set(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *ar
|
|||
|
||||
i = 0;
|
||||
do {
|
||||
gboolean flag;
|
||||
|
||||
if (argc == 1 && nmc->complete)
|
||||
nmc_complete_strings(*argv, "managed", "autoconnect");
|
||||
|
||||
if (matches(*argv, "managed")) {
|
||||
NMDeviceManaged val;
|
||||
guint32 flags = 0;
|
||||
gboolean val_bool;
|
||||
gboolean perm = FALSE, perm_only = FALSE;
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
if (argc == 1 && nmc->complete) {
|
||||
nmc_complete_strings(*argv,
|
||||
"true",
|
||||
"yes",
|
||||
"on",
|
||||
"false",
|
||||
"no",
|
||||
"off",
|
||||
"up",
|
||||
"down",
|
||||
"reset",
|
||||
"--permanent",
|
||||
"--permanent-only");
|
||||
}
|
||||
|
||||
if (managed_data.idx != -1) {
|
||||
g_string_printf(nmc->return_text, _("Error: 'managed' can only be set once."));
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return;
|
||||
}
|
||||
|
||||
while (argc > 0) {
|
||||
/* --perm matches with --permanent, the most common,
|
||||
* but --permanent-only requires a exact match */
|
||||
if (nm_streq0(*argv, "--permanent-only"))
|
||||
perm_only = TRUE;
|
||||
else if (matches(*argv, "--permanent"))
|
||||
perm = TRUE;
|
||||
else
|
||||
break;
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (perm_only && perm) {
|
||||
g_string_printf(
|
||||
nmc->return_text,
|
||||
_("Error: '--permanent-only' and '--permanent' cannot be used together."));
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return;
|
||||
} else if (perm) {
|
||||
flags |= NM_DEVICE_MANAGED_FLAGS_RUNTIME | NM_DEVICE_MANAGED_FLAGS_PERMANENT;
|
||||
} else if (perm_only) {
|
||||
flags |= NM_DEVICE_MANAGED_FLAGS_PERMANENT;
|
||||
} else {
|
||||
/* If --permanent/--permanent-only are missing, set only the runtime flag, as this
|
||||
* is how it used to work when these options didn't exist. */
|
||||
flags |= NM_DEVICE_MANAGED_FLAGS_RUNTIME;
|
||||
}
|
||||
|
||||
if (!argc) {
|
||||
g_string_printf(nmc->return_text,
|
||||
_("Error: '%s' argument is missing."),
|
||||
*(argv - 1));
|
||||
g_string_printf(nmc->return_text, _("Error: 'managed' argument is missing."));
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return;
|
||||
}
|
||||
if (argc == 1 && nmc->complete)
|
||||
nmc_complete_bool(*argv);
|
||||
if (!nmc_string_to_bool(*argv, &flag, &error)) {
|
||||
g_string_printf(nmc->return_text, _("Error: 'managed': %s."), error->message);
|
||||
|
||||
if (matches(*argv, "up") || matches(*argv, "down")) {
|
||||
flags |= NM_DEVICE_MANAGED_FLAGS_SET_ADMIN_STATE;
|
||||
val = matches(*argv, "up") ? NM_DEVICE_MANAGED_YES : NM_DEVICE_MANAGED_NO;
|
||||
} else if (matches(*argv, "reset")) {
|
||||
val = NM_DEVICE_MANAGED_RESET;
|
||||
} else if (nmc_string_to_bool(*argv, &val_bool, NULL)) {
|
||||
val = val_bool ? NM_DEVICE_MANAGED_YES : NM_DEVICE_MANAGED_NO;
|
||||
} else {
|
||||
g_string_printf(
|
||||
nmc->return_text,
|
||||
_("Error: 'managed': '%s' is not valid, use 'yes/no/up/down/reset'."),
|
||||
*argv);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return;
|
||||
}
|
||||
values[DEV_SET_MANAGED].idx = ++i;
|
||||
values[DEV_SET_MANAGED].value = flag;
|
||||
|
||||
managed_data.idx = i++;
|
||||
managed_data.value = val;
|
||||
managed_data.flags = flags;
|
||||
} else if (matches(*argv, "autoconnect")) {
|
||||
gboolean val;
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
if (!argc) {
|
||||
g_string_printf(nmc->return_text,
|
||||
_("Error: '%s' argument is missing."),
|
||||
*(argv - 1));
|
||||
g_string_printf(nmc->return_text, _("Error: 'autoconnect' argument is missing."));
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return;
|
||||
}
|
||||
if (autoconnect_data.idx != -1) {
|
||||
g_string_printf(nmc->return_text, _("Error: 'autoconnect' can only be set once."));
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc == 1 && nmc->complete)
|
||||
nmc_complete_bool(*argv);
|
||||
if (!nmc_string_to_bool(*argv, &flag, &error)) {
|
||||
|
||||
if (!nmc_string_to_bool(*argv, &val, &error)) {
|
||||
g_string_printf(nmc->return_text, _("Error: 'autoconnect': %s."), error->message);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
return;
|
||||
}
|
||||
values[DEV_SET_AUTOCONNECT].idx = ++i;
|
||||
values[DEV_SET_AUTOCONNECT].value = flag;
|
||||
autoconnect_data.idx = i++;
|
||||
autoconnect_data.value = val;
|
||||
} else {
|
||||
g_string_printf(nmc->return_text, _("Error: property '%s' is not known."), *argv);
|
||||
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||
|
|
@ -2906,15 +3021,28 @@ do_device_set(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *ar
|
|||
|
||||
/* when multiple properties are specified, set them in the order as they
|
||||
* are specified on the command line. */
|
||||
if (values[DEV_SET_AUTOCONNECT].idx >= 0 && values[DEV_SET_MANAGED].idx >= 0
|
||||
&& values[DEV_SET_MANAGED].idx < values[DEV_SET_AUTOCONNECT].idx) {
|
||||
nm_device_set_managed(device, values[DEV_SET_MANAGED].value);
|
||||
values[DEV_SET_MANAGED].idx = -1;
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (autoconnect_data.idx == i) {
|
||||
nm_device_set_autoconnect(device, autoconnect_data.value);
|
||||
}
|
||||
if (managed_data.idx == i) {
|
||||
cb_info = g_slice_new0(DeviceSetCbInfo);
|
||||
cb_info->nmc = nmc;
|
||||
if (nmc->timeout > 0)
|
||||
cb_info->timeout_source =
|
||||
nm_g_timeout_add_seconds_source(nmc->timeout, device_set_timeout_cb, cb_info);
|
||||
|
||||
nmc->nowait_flag = (nmc->timeout == 0);
|
||||
nmc->should_wait++;
|
||||
|
||||
nm_device_set_managed_async(device,
|
||||
managed_data.value,
|
||||
managed_data.flags,
|
||||
NULL,
|
||||
device_set_cb,
|
||||
cb_info);
|
||||
}
|
||||
}
|
||||
if (values[DEV_SET_AUTOCONNECT].idx >= 0)
|
||||
nm_device_set_autoconnect(device, values[DEV_SET_AUTOCONNECT].value);
|
||||
if (values[DEV_SET_MANAGED].idx >= 0)
|
||||
nm_device_set_managed(device, values[DEV_SET_MANAGED].value);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue