diff options
Diffstat (limited to 'src/core/devices/nm-device.c')
| -rw-r--r-- | src/core/devices/nm-device.c | 246 |
1 files changed, 244 insertions, 2 deletions
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 46fb2339..a0cf1ee6 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -5900,7 +5900,6 @@ nm_device_get_route_metric_default(NMDeviceType device_type) * in some aspects a VPN. */ case NM_DEVICE_TYPE_WIREGUARD: return NM_VPN_ROUTE_METRIC_DEFAULT; - case NM_DEVICE_TYPE_ETHERNET: case NM_DEVICE_TYPE_VETH: return 100; @@ -5934,6 +5933,8 @@ nm_device_get_route_metric_default(NMDeviceType device_type) return 470; case NM_DEVICE_TYPE_VXLAN: return 500; + case NM_DEVICE_TYPE_GENEVE: + return 525; case NM_DEVICE_TYPE_DUMMY: return 550; case NM_DEVICE_TYPE_WIFI: @@ -14841,6 +14842,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, @@ -19535,7 +19771,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps nm_assert(priv->type == NM_DEVICE_TYPE_UNKNOWN); priv->type = g_value_get_uint(value); nm_assert(priv->type > NM_DEVICE_TYPE_UNKNOWN); - nm_assert(priv->type <= NM_DEVICE_TYPE_IPVLAN); + nm_assert(priv->type <= NM_DEVICE_TYPE_GENEVE); break; case PROP_LINK_TYPE: /* construct-only */ @@ -19864,6 +20100,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", ), |