diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2019-05-28 10:35:57 +0200 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2019-05-28 10:35:57 +0200 |
commit | 3a4a09b669b6d3498017fe5773af3e9aef2ae8a5 (patch) | |
tree | 2802d1f3bef0cfbffd5e1050a5bedf2e97109fb7 | |
parent | d6a51ced40e7276cc281459c662d59c0b5429044 (diff) | |
parent | 121c58f0c48de9fb64a87ef02e3e090d90d2e96e (diff) | |
download | NetworkManager-3a4a09b669b6d3498017fe5773af3e9aef2ae8a5.tar.gz |
core: merge branch 'bg/sriov-async'
https://github.com/NetworkManager/NetworkManager/pull/268
-rw-r--r-- | src/devices/nm-device.c | 224 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 362 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 90 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 211 | ||||
-rw-r--r-- | src/platform/tests/test-link.c | 88 |
5 files changed, 769 insertions, 206 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 493288c197..ca0114f522 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -128,6 +128,15 @@ typedef struct { int ifindex; } DeleteOnDeactivateData; +typedef struct { + NMDevice *device; + GCancellable *cancellable; + NMPlatformAsyncCallback callback; + gpointer callback_data; + guint num_vfs; + NMTernary autoprobe; +} SriovOp; + typedef void (*AcdCallback) (NMDevice *, NMIP4Config **, gboolean); typedef struct { @@ -576,12 +585,16 @@ typedef struct _NMDevicePrivate { guint check_delete_unrealized_id; struct { + SriovOp *pending; /* SR-IOV operation currently running */ + SriovOp *next; /* next SR-IOV operation scheduled */ + } sriov; + + struct { guint timeout_id; guint refresh_rate_ms; guint64 tx_bytes; guint64 rx_bytes; } stats; - } NMDevicePrivate; G_DEFINE_ABSTRACT_TYPE (NMDevice, nm_device, NM_TYPE_DBUS_OBJECT) @@ -4192,6 +4205,86 @@ nm_device_update_from_platform_link (NMDevice *self, const NMPlatformLink *plink } } +static void sriov_op_cb (GError *error, gpointer user_data); + +static void +sriov_op_start (NMDevice *self, SriovOp *op) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + nm_assert (!priv->sriov.pending); + + op->cancellable = g_cancellable_new (); + op->device = g_object_ref (self); + priv->sriov.pending = op; + + nm_platform_link_set_sriov_params_async (nm_device_get_platform (self), + priv->ifindex, + op->num_vfs, + op->autoprobe, + sriov_op_cb, + op, + op->cancellable); +} + +static void +sriov_op_cb (GError *error, gpointer user_data) +{ + SriovOp *op = user_data; + gs_unref_object NMDevice *self = op->device; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + nm_assert (op == priv->sriov.pending); + + priv->sriov.pending = NULL; + + if (op->callback) + op->callback (error, op->callback_data); + + g_clear_object (&op->cancellable); + g_slice_free (SriovOp, op); + + if (priv->sriov.next) { + sriov_op_start (self, + g_steal_pointer (&priv->sriov.next)); + } +} + +static void +sriov_op_queue (NMDevice *self, + guint num_vfs, + NMTernary autoprobe, + NMPlatformAsyncCallback callback, + gpointer callback_data) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + GError *error = NULL; + SriovOp *op; + + op = g_slice_new0 (SriovOp); + op->num_vfs = num_vfs; + op->autoprobe = autoprobe; + op->callback = callback; + op->callback_data = callback_data; + + if (priv->sriov.next) { + /* Cancel the next operation immediately */ + if (priv->sriov.next->callback) { + nm_utils_error_set_cancelled (&error, FALSE, NULL); + priv->sriov.next->callback (error, priv->sriov.next->callback_data); + g_clear_error (&error); + } + g_slice_free (SriovOp, priv->sriov.next); + priv->sriov.next = NULL; + } + + if (priv->sriov.pending) { + priv->sriov.next = op; + g_cancellable_cancel (priv->sriov.pending->cancellable); + } else + sriov_op_start (self, op); +} + static void device_init_static_sriov_num_vfs (NMDevice *self) { @@ -4206,10 +4299,8 @@ device_init_static_sriov_num_vfs (NMDevice *self) self, NULL); num_vfs = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXINT32, -1); - if (num_vfs >= 0) { - nm_platform_link_set_sriov_params (nm_device_get_platform (self), - priv->ifindex, num_vfs, NM_TERNARY_DEFAULT); - } + if (num_vfs >= 0) + sriov_op_queue (self, num_vfs, NM_TERNARY_DEFAULT, NULL, NULL); } } @@ -4223,11 +4314,11 @@ 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->state > NM_DEVICE_STATE_ACTIVATED) { priv->ignore_carrier = nm_config_data_get_ignore_carrier (config_data, self); - - if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_VALUES)) - device_init_static_sriov_num_vfs (self); + if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_VALUES)) + device_init_static_sriov_num_vfs (self); + } } static void @@ -6265,6 +6356,41 @@ sriov_vf_config_to_platform (NMDevice *self, return g_steal_pointer (&plat_vf); } +static void +sriov_params_cb (GError *error, gpointer data) +{ + NMDevice *self; + NMDevicePrivate *priv; + nm_auto_freev NMPlatformVF **plat_vfs = NULL; + + nm_utils_user_data_unpack (data, &self, &plat_vfs); + + if (nm_utils_error_is_cancelled (error, TRUE)) + return; + + priv = NM_DEVICE_GET_PRIVATE (self); + + if (error) { + _LOGE (LOGD_DEVICE, "failed to set SR-IOV parameters: %s", error->message); + nm_device_state_changed (self, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); + return; + } + + if (!nm_platform_link_set_sriov_vfs (nm_device_get_platform (self), + priv->ifindex, + (const NMPlatformVF *const *) plat_vfs)) { + _LOGE (LOGD_DEVICE, "failed to apply SR-IOV VFs"); + nm_device_state_changed (self, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); + return; + } + + nm_device_activate_schedule_stage2_device_config (self); +} + static NMActStageReturn act_stage1_prepare (NMDevice *self, NMDeviceStateReason *out_failure_reason) { @@ -6279,6 +6405,7 @@ act_stage1_prepare (NMDevice *self, NMDeviceStateReason *out_failure_reason) gs_free_error GError *error = NULL; NMSriovVF *vf; NMTernary autoprobe; + gpointer *data; autoprobe = nm_setting_sriov_get_autoprobe_drivers (s_sriov); if (autoprobe == NM_TERNARY_DEFAULT) { @@ -6305,24 +6432,19 @@ act_stage1_prepare (NMDevice *self, NMDeviceStateReason *out_failure_reason) } } - if (!nm_platform_link_set_sriov_params (nm_device_get_platform (self), - priv->ifindex, - nm_setting_sriov_get_total_vfs (s_sriov), - autoprobe)) { - _LOGE (LOGD_DEVICE, "failed to apply SR-IOV parameters"); - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - if (!nm_platform_link_set_sriov_vfs (nm_device_get_platform (self), - priv->ifindex, - (const NMPlatformVF *const *) plat_vfs)) { - _LOGE (LOGD_DEVICE, "failed to apply SR-IOV VFs"); - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } + /* When changing the number of VFs the kernel can block + * for very long time in the write to sysfs, especially + * if autoprobe-drivers is enabled. Do it asynchronously + * to avoid blocking the entire NM process. + */ + data = nm_utils_user_data_pack (self, g_steal_pointer (&plat_vfs)); + sriov_op_queue (self, + nm_setting_sriov_get_total_vfs (s_sriov), + autoprobe, + sriov_params_cb, + data); + return NM_ACT_STAGE_RETURN_POSTPONE; } - return NM_ACT_STAGE_RETURN_SUCCESS; } @@ -14801,6 +14923,34 @@ ip6_managed_setup (NMDevice *self) } static void +deactivate_ready (NMDevice *self, NMDeviceStateReason reason) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (priv->dispatcher.call_id) + return; + + if (priv->sriov.pending) + return; + nm_assert (!priv->sriov.next); + + nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason); +} + +static void +sriov_deactivate_cb (GError *error, gpointer user_data) +{ + NMDevice *self; + gpointer reason; + + if (nm_utils_error_is_cancelled (error, TRUE)) + return; + + nm_utils_user_data_unpack (user_data, &self, &reason); + deactivate_ready (self, (NMDeviceStateReason) reason); +} + +static void deactivate_async_ready (NMDevice *self, GError *error, gpointer user_data) @@ -14820,7 +14970,8 @@ deactivate_async_ready (NMDevice *self, _LOGW (LOGD_DEVICE, "Deactivation failed: %s", error->message); } - nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason); + + deactivate_ready (self, reason); } static void @@ -14833,7 +14984,7 @@ deactivate_dispatcher_complete (NMDispatcherCallId *call_id, gpointer user_data) g_return_if_fail (call_id == priv->dispatcher.call_id); g_return_if_fail (priv->dispatcher.post_state == NM_DEVICE_STATE_DISCONNECTED); - reason = priv->dispatcher.post_state_reason; + reason = priv->state_reason; priv->dispatcher.call_id = NULL; priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; @@ -14849,7 +15000,7 @@ deactivate_dispatcher_complete (NMDispatcherCallId *call_id, gpointer user_data) deactivate_async_ready, GUINT_TO_POINTER (reason)); } else - nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason); + deactivate_ready (self, reason); } static void @@ -15062,12 +15213,6 @@ _set_state_full (NMDevice *self, } break; case NM_DEVICE_STATE_DEACTIVATING: - if ( (s_sriov = nm_device_get_applied_setting (self, NM_TYPE_SETTING_SRIOV)) - && priv->ifindex > 0) { - nm_platform_link_set_sriov_params (nm_device_get_platform (self), - priv->ifindex, 0, NM_TERNARY_TRUE); - } - _cancel_activation (self); /* We cache the ignore_carrier state to not react on config-reloads while the connection @@ -15089,6 +15234,15 @@ _set_state_full (NMDevice *self, /* Just proceed on errors */ deactivate_dispatcher_complete (0, self); } + + if ( priv->ifindex > 0 + && (s_sriov = nm_device_get_applied_setting (self, NM_TYPE_SETTING_SRIOV))) { + sriov_op_queue (self, + 0, + NM_TERNARY_TRUE, + sriov_deactivate_cb, + nm_utils_user_data_pack (self, (gpointer) reason)); + } } nm_pacrunner_manager_remove_clear (&priv->pacrunner_conf_id); diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 13eda83109..ac8e869d8e 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -4375,6 +4375,14 @@ _genl_sock (NMLinuxPlatform *platform) } \ } G_STMT_END +/*****************************************************************************/ + +/* core sysctl-set functions can be called from a non-main thread. + * Hence, we require locking from nm-logging. Indicate that by + * setting NM_THREAD_SAFE_ON_MAIN_THREAD to zero. */ +#undef NM_THREAD_SAFE_ON_MAIN_THREAD +#define NM_THREAD_SAFE_ON_MAIN_THREAD 0 + static void _log_dbg_sysctl_set_impl (NMPlatform *platform, const char *pathid, int dirfd, const char *path, const char *value) { @@ -4385,18 +4393,18 @@ _log_dbg_sysctl_set_impl (NMPlatform *platform, const char *pathid, int dirfd, c if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024, NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, &contents, NULL, &error) < 0) { - _LOGD ("sysctl: setting '%s' to '%s' (current value cannot be read: %s)", pathid, value_escaped, error->message); + _LOGD ("sysctl: setting '%s' to '%s' (current value cannot be read: %s)", pathid ?: path, value_escaped, error->message); g_clear_error (&error); return; } g_strstrip (contents); if (nm_streq (contents, value)) - _LOGD ("sysctl: setting '%s' to '%s' (current value is identical)", pathid, value_escaped); + _LOGD ("sysctl: setting '%s' to '%s' (current value is identical)", pathid ?: path, value_escaped); else { gs_free char *contents_escaped = g_strescape (contents, NULL); - _LOGD ("sysctl: setting '%s' to '%s' (current value is '%s')", pathid, value_escaped, contents_escaped); + _LOGD ("sysctl: setting '%s' to '%s' (current value is '%s')", pathid ?: path, value_escaped, contents_escaped); } g_free (contents); } @@ -4409,9 +4417,12 @@ _log_dbg_sysctl_set_impl (NMPlatform *platform, const char *pathid, int dirfd, c } G_STMT_END static gboolean -sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *path, const char *value) +sysctl_set_internal (NMPlatform *platform, + const char *pathid, + int dirfd, + const char *path, + const char *value) { - nm_auto_pop_netns NMPNetns *netns = NULL; int fd, tries; gssize nwrote; gssize len; @@ -4419,17 +4430,7 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat gs_free char *actual_free = NULL; int errsv; - g_return_val_if_fail (path != NULL, FALSE); - g_return_val_if_fail (value != NULL, FALSE); - - ASSERT_SYSCTL_ARGS (pathid, dirfd, path); - if (dirfd < 0) { - if (!nm_platform_netns_push (platform, &netns)) { - errno = ENETDOWN; - return FALSE; - } - pathid = path; fd = open (path, O_WRONLY | O_TRUNC | O_CLOEXEC); @@ -4529,6 +4530,207 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat return TRUE; } +#undef NM_THREAD_SAFE_ON_MAIN_THREAD +#define NM_THREAD_SAFE_ON_MAIN_THREAD 1 + +/*****************************************************************************/ + +static gboolean +sysctl_set (NMPlatform *platform, + const char *pathid, + int dirfd, + const char *path, + const char *value) +{ + nm_auto_pop_netns NMPNetns *netns = NULL; + + g_return_val_if_fail (path, FALSE); + g_return_val_if_fail (value, FALSE); + + ASSERT_SYSCTL_ARGS (pathid, dirfd, path); + + if ( dirfd < 0 + && !nm_platform_netns_push (platform, &netns)) { + errno = ENETDOWN; + return FALSE; + } + + return sysctl_set_internal (platform, pathid, dirfd, path, value); +} + +typedef struct { + NMPlatform *platform; + char *pathid; + int dirfd; + char *path; + char **values; + GCancellable *cancellable; + NMPlatformAsyncCallback callback; + gpointer callback_data; +} SysctlAsyncInfo; + +static void +sysctl_async_info_free (SysctlAsyncInfo *info) +{ + g_object_unref (info->platform); + g_free (info->pathid); + if (info->dirfd >= 0) + nm_close (info->dirfd); + g_free (info->path); + g_strfreev (info->values); + g_object_unref (info->cancellable); + g_slice_free (SysctlAsyncInfo, info); +} + +static void +sysctl_async_cb (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + NMPlatform *platform; + GTask *task = G_TASK (res); + SysctlAsyncInfo *info; + gs_free_error GError *error = NULL; + gs_free char *values_str = NULL; + + info = g_task_get_task_data (task); + + if (g_task_propagate_boolean (task, &error)) { + platform = info->platform; + _LOGD ("sysctl: successfully set-async '%s' to values '%s'", + info->pathid ?: info->path, + (values_str = g_strjoinv (", ", info->values))); + } + + if (info->callback) + info->callback (error, info->callback_data); +} + +static void +sysctl_async_thread_fn (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + nm_auto_pop_netns NMPNetns *netns = NULL; + SysctlAsyncInfo *info = task_data; + GError *error = NULL; + char **value; + + if (g_task_return_error_if_cancelled (task)) + return; + + if ( info->dirfd < 0 + && !nm_platform_netns_push (info->platform, &netns)) { + g_set_error_literal (&error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + "sysctl: failed changing namespace"); + g_task_return_error (task, error); + return; + } + + for (value = info->values; *value; value++) { + if (!sysctl_set_internal (info->platform, + info->pathid, + info->dirfd, + info->path, + *value)) { + g_set_error (&error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + "sysctl: failed setting '%s' to value '%s': %s", + info->pathid ?: info->path, + *value, + nm_strerror_native (errno)); + g_task_return_error (task, error); + return; + } + if (g_task_return_error_if_cancelled (task)) + return; + } + g_task_return_boolean (task, TRUE); +} + +static void +sysctl_set_async_return_idle (gpointer user_data, + GCancellable *cancellable) +{ + gs_unref_object NMPlatform *platform = NULL; + gs_free_error GError *cancelled_error = NULL; + gs_free_error GError *error = NULL; + NMPlatformAsyncCallback callback; + gpointer callback_data; + + nm_utils_user_data_unpack (user_data, &platform, &callback, &callback_data, &error); + g_cancellable_set_error_if_cancelled (cancellable, &cancelled_error); + callback (cancelled_error ?: error, callback_data); +} + +static void +sysctl_set_async (NMPlatform *platform, + const char *pathid, + int dirfd, + const char *path, + const char *const *values, + NMPlatformAsyncCallback callback, + gpointer data, + GCancellable *cancellable) +{ + SysctlAsyncInfo *info; + GTask *task; + int dirfd_dup, errsv; + gpointer packed; + GError *error = NULL; + + g_return_if_fail (platform); + g_return_if_fail (path); + g_return_if_fail (values && values[0]); + g_return_if_fail (cancellable); + g_return_if_fail (!data || callback); + + ASSERT_SYSCTL_ARGS (pathid, dirfd, path); + + if (dirfd >= 0) { + dirfd_dup = fcntl (dirfd, F_DUPFD_CLOEXEC, 0); + if (dirfd_dup < 0) { + if (!callback) + return; + errsv = errno; + g_set_error (&error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + "sysctl: failure duplicating directory fd: %s", + nm_strerror_native (errsv)); + packed = nm_utils_user_data_pack (g_object_ref (platform), + callback, + data, + error); + nm_utils_invoke_on_idle (sysctl_set_async_return_idle, + packed, + cancellable); + return; + } + } else + dirfd_dup = -1; + + info = g_slice_new0 (SysctlAsyncInfo); + info->platform = g_object_ref (platform); + info->pathid = g_strdup (pathid); + info->dirfd = dirfd_dup; + info->path = g_strdup (path); + info->values = g_strdupv ((char **) values); + info->callback = callback; + info->callback_data = data; + info->cancellable = g_object_ref (cancellable); + + task = g_task_new (platform, cancellable, sysctl_async_cb, NULL); + g_task_set_task_data (task, info, (GDestroyNotify) sysctl_async_info_free); + g_task_set_return_on_cancel (task, FALSE); + g_task_run_in_thread (task, sysctl_async_thread_fn); + g_object_unref (task); +} + static GSList *sysctl_clear_cache_list; void @@ -6612,35 +6814,74 @@ nla_put_failure: g_return_val_if_reached (FALSE); } -static gboolean -link_set_sriov_params (NMPlatform *platform, - int ifindex, - guint num_vfs, - NMTernary autoprobe) +static void +sriov_idle_cb (gpointer user_data, + GCancellable *cancellable) +{ + gs_unref_object NMPlatform *platform = NULL; + gs_free_error GError *cancelled_error = NULL; + gs_free_error GError *error = NULL; + NMPlatformAsyncCallback callback; + gpointer callback_data; + + g_cancellable_set_error_if_cancelled (cancellable, &cancelled_error); + nm_utils_user_data_unpack (user_data, &platform, &error, &callback, &callback_data); + callback (cancelled_error ?: error, callback_data); +} + +static void +link_set_sriov_params_async (NMPlatform *platform, + int ifindex, + guint num_vfs, + NMTernary autoprobe, + NMPlatformAsyncCallback callback, + gpointer data, + GCancellable *cancellable) { nm_auto_pop_netns NMPNetns *netns = NULL; + gs_free_error GError *error = NULL; nm_auto_close int dirfd = -1; int current_autoprobe; - guint total; + guint i, total; gint64 current_num; char ifname[IFNAMSIZ]; + gpointer packed; + const char *values[3]; char buf[64]; - int errsv; - if (!nm_platform_netns_push (platform, &netns)) - return FALSE; + g_return_if_fail (callback || !data); + g_return_if_fail (cancellable); + + if (!nm_platform_netns_push (platform, &netns)) { + g_set_error_literal (&error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + "couldn't change namespace"); + goto out_idle; + } dirfd = nm_platform_sysctl_open_netdir (platform, ifindex, ifname); - if (!dirfd) - return FALSE; + if (!dirfd) { + g_set_error_literal (&error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + "couldn't open netdir"); + goto out_idle; + } total = nm_platform_sysctl_get_int_checked (platform, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "device/sriov_totalvfs"), 10, 0, G_MAXUINT, 0); - if (errno) - return FALSE; + if (errno) { + g_set_error (&error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + "failed reading sriov_totalvfs value: %s", + nm_strerror_native (errno)); + goto out_idle; + } if (num_vfs > total) { _LOGW ("link: %d only supports %u VFs (requested %u)", ifindex, total, num_vfs); num_vfs = total; @@ -6672,23 +6913,7 @@ link_set_sriov_params (NMPlatform *platform, if ( current_num == num_vfs && (autoprobe == NM_TERNARY_DEFAULT || current_autoprobe == autoprobe)) - return TRUE; - - if (current_num != 0) { - /* We need to destroy all other VFs before changing any value */ - if (!nm_platform_sysctl_set (NM_PLATFORM_GET, - NMP_SYSCTL_PATHID_NETDIR (dirfd, - ifname, - "device/sriov_numvfs"), - "0")) { - errsv = errno; - _LOGW ("link: couldn't reset SR-IOV num_vfs: %s", nm_strerror_native (errsv)); - return FALSE; - } - } - - if (num_vfs == 0) - return TRUE; + goto out_idle; if ( NM_IN_SET (autoprobe, NM_TERNARY_TRUE, NM_TERNARY_FALSE) && current_autoprobe != autoprobe @@ -6697,22 +6922,40 @@ link_set_sriov_params (NMPlatform *platform, ifname, "device/sriov_drivers_autoprobe"), nm_sprintf_buf (buf, "%d", (int) autoprobe))) { - errsv = errno; - _LOGW ("link: couldn't set SR-IOV drivers-autoprobe to %d: %s", (int) autoprobe, nm_strerror_native (errsv)); - return FALSE; + g_set_error (&error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + "couldn't set SR-IOV drivers-autoprobe to %d: %s", + (int) autoprobe, nm_strerror_native (errno)); + goto out_idle; } - if (!nm_platform_sysctl_set (NM_PLATFORM_GET, - NMP_SYSCTL_PATHID_NETDIR (dirfd, - ifname, - "device/sriov_numvfs"), - nm_sprintf_buf (buf, "%u", num_vfs))) { - errsv = errno; - _LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", num_vfs, nm_strerror_native (errsv)); - return FALSE; - } + if (current_num == 0 && num_vfs == 0) + goto out_idle; - return TRUE; + i = 0; + if (current_num != 0) + values[i++] = "0"; + if (num_vfs != 0) + values[i++] = nm_sprintf_bufa (32, "%u", num_vfs); + values[i++] = NULL; + + sysctl_set_async (platform, + NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "device/sriov_numvfs"), + values, + callback, + data, + cancellable); + return; + +out_idle: + if (callback) { + packed = nm_utils_user_data_pack (g_object_ref (platform), + g_steal_pointer (&error), + callback, + data); + nm_utils_invoke_on_idle (sriov_idle_cb, packed, cancellable); + } } static gboolean @@ -8997,6 +9240,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) object_class->finalize = finalize; platform_class->sysctl_set = sysctl_set; + platform_class->sysctl_set_async = sysctl_set_async; platform_class->sysctl_get = sysctl_get; platform_class->link_add = link_add; @@ -9020,7 +9264,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_get_permanent_address = link_get_permanent_address; platform_class->link_set_mtu = link_set_mtu; platform_class->link_set_name = link_set_name; - platform_class->link_set_sriov_params = link_set_sriov_params; + platform_class->link_set_sriov_params_async = link_set_sriov_params_async; platform_class->link_set_sriov_vfs = link_set_sriov_vfs; platform_class->link_set_bridge_vlans = link_set_bridge_vlans; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index a2d4116de1..4a98df84e8 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -481,6 +481,40 @@ nm_platform_sysctl_set (NMPlatform *self, const char *pathid, int dirfd, const c return klass->sysctl_set (self, pathid, dirfd, path, value); } +/** + * nm_platform_sysctl_set_async: + * @self: platform instance + * @pathid: if @dirfd is present, this must be the full path that is looked up + * @dirfd: optional file descriptor for parent directory for openat() + * @path: absolute option path + * @values: NULL-terminated array of strings to be written + * @callback: function called on termination + * @data: data passed to callback function + * @cancellable: to cancel the operation + * + * This function is intended to be used for writing values to sysctl-style + * virtual runtime configuration files. This includes not only /proc/sys + * but also for example /sys/class. The function does not block and returns + * immediately. The callback is always invoked, and asynchronously. The file + * is closed after writing each value and reopened to write the next one so + * that the function can be used safely on all /proc and /sys files, + * independently of how /proc/sys/kernel/sysctl_writes_strict is configured. + */ +void nm_platform_sysctl_set_async (NMPlatform *self, + const char *pathid, + int dirfd, + const char *path, + const char *const *values, + NMPlatformAsyncCallback callback, + gpointer data, + GCancellable *cancellable) +{ + _CHECK_SELF_VOID (self, klass); + + klass->sysctl_set_async (self, pathid, dirfd, path, values, callback, data, cancellable); +} + + gboolean nm_platform_sysctl_ip_conf_set_ipv6_hop_limit_safe (NMPlatform *self, const char *iface, @@ -623,14 +657,14 @@ nm_platform_sysctl_get_int_checked (NMPlatform *self, /*****************************************************************************/ char * -nm_platform_sysctl_ip_conf_get (NMPlatform *platform, +nm_platform_sysctl_ip_conf_get (NMPlatform *self, int addr_family, const char *ifname, const char *property) { char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE]; - return nm_platform_sysctl_get (platform, + return nm_platform_sysctl_get (self, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (addr_family, buf, ifname, @@ -638,7 +672,7 @@ nm_platform_sysctl_ip_conf_get (NMPlatform *platform, } gint64 -nm_platform_sysctl_ip_conf_get_int_checked (NMPlatform *platform, +nm_platform_sysctl_ip_conf_get_int_checked (NMPlatform *self, int addr_family, const char *ifname, const char *property, @@ -649,7 +683,7 @@ nm_platform_sysctl_ip_conf_get_int_checked (NMPlatform *platform, { char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE]; - return nm_platform_sysctl_get_int_checked (platform, + return nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (addr_family, buf, ifname, @@ -661,7 +695,7 @@ nm_platform_sysctl_ip_conf_get_int_checked (NMPlatform *platform, } gboolean -nm_platform_sysctl_ip_conf_set (NMPlatform *platform, +nm_platform_sysctl_ip_conf_set (NMPlatform *self, int addr_family, const char *ifname, const char *property, @@ -669,7 +703,7 @@ nm_platform_sysctl_ip_conf_set (NMPlatform *platform, { char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE]; - return nm_platform_sysctl_set (platform, + return nm_platform_sysctl_set (self, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (addr_family, buf, ifname, @@ -678,7 +712,7 @@ nm_platform_sysctl_ip_conf_set (NMPlatform *platform, } gboolean -nm_platform_sysctl_ip_conf_set_int64 (NMPlatform *platform, +nm_platform_sysctl_ip_conf_set_int64 (NMPlatform *self, int addr_family, const char *ifname, const char *property, @@ -687,7 +721,7 @@ nm_platform_sysctl_ip_conf_set_int64 (NMPlatform *platform, char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE]; char s[64]; - return nm_platform_sysctl_set (platform, + return nm_platform_sysctl_set (self, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (addr_family, buf, ifname, @@ -1553,19 +1587,35 @@ nm_platform_link_supports_sriov (NMPlatform *self, int ifindex) * @num_vfs: the number of VFs to create * @autoprobe: the new autoprobe-drivers value (pass * %NM_TERNARY_DEFAULT to keep current value) + * @callback: called when the operation finishes + * @callback_data: data passed to @callback + * @cancellable: cancellable to abort the operation + * + * Sets SR-IOV parameters asynchronously without + * blocking the main thread. The callback function is + * always invoked, and asynchronously. */ -gboolean -nm_platform_link_set_sriov_params (NMPlatform *self, - int ifindex, - guint num_vfs, - NMTernary autoprobe) +void +nm_platform_link_set_sriov_params_async (NMPlatform *self, + int ifindex, + guint num_vfs, + NMTernary autoprobe, + NMPlatformAsyncCallback callback, + gpointer callback_data, + GCancellable *cancellable) { - _CHECK_SELF (self, klass, FALSE); + _CHECK_SELF_VOID (self, klass); - g_return_val_if_fail (ifindex > 0, FALSE); + g_return_if_fail (ifindex > 0); _LOG3D ("link: setting %u total VFs and autoprobe %d", num_vfs, (int) autoprobe); - return klass->link_set_sriov_params (self, ifindex, num_vfs, autoprobe); + klass->link_set_sriov_params_async (self, + ifindex, + num_vfs, + autoprobe, + callback, + callback_data, + cancellable); } gboolean @@ -3402,21 +3452,21 @@ nm_platform_ethtool_set_features (NMPlatform *self, /*****************************************************************************/ const NMDedupMultiHeadEntry * -nm_platform_lookup_all (NMPlatform *platform, +nm_platform_lookup_all (NMPlatform *self, NMPCacheIdType cache_id_type, const NMPObject *obj) { - return nmp_cache_lookup_all (nm_platform_get_cache (platform), + return nmp_cache_lookup_all (nm_platform_get_cache (self), cache_id_type, obj); } const NMDedupMultiEntry * -nm_platform_lookup_entry (NMPlatform *platform, +nm_platform_lookup_entry (NMPlatform *self, NMPCacheIdType cache_id_type, const NMPObject *obj) { - return nmp_cache_lookup_entry_with_idx_type (nm_platform_get_cache (platform), + return nmp_cache_lookup_entry_with_idx_type (nm_platform_get_cache (self), cache_id_type, obj); } diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index a2d8e57ff6..a6b5f2c4c3 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -895,6 +895,8 @@ typedef enum { } NMPlatformWireGuardChangePeerFlags; +typedef void (*NMPlatformAsyncCallback) (GError *error, gpointer user_data); + /*****************************************************************************/ typedef enum { @@ -953,64 +955,75 @@ struct _NMPlatform { typedef struct { GObjectClass parent; - gboolean (*sysctl_set) (NMPlatform *, const char *pathid, int dirfd, const char *path, const char *value); - char * (*sysctl_get) (NMPlatform *, const char *pathid, int dirfd, const char *path); + gboolean (*sysctl_set) (NMPlatform *self, const char *pathid, int dirfd, const char *path, const char *value); + void (*sysctl_set_async) (NMPlatform *self, + const char *pathid, + int dirfd, + const char *path, + const char *const *values, + NMPlatformAsyncCallback callback, + gpointer data, + GCancellable *cancellable); + char * (*sysctl_get) (NMPlatform *self, const char *pathid, int dirfd, const char *path); + + void (*refresh_all) (NMPlatform *self, NMPObjectType obj_type); + void (*process_events) (NMPlatform *self); - int (*link_add) (NMPlatform *, + int (*link_add) (NMPlatform *self, const char *name, NMLinkType type, const char *veth_peer, const void *address, size_t address_len, const NMPlatformLink **out_link); - - gboolean (*link_delete) (NMPlatform *, int ifindex); - - gboolean (*link_refresh) (NMPlatform *, int ifindex); - - gboolean (*link_set_netns) (NMPlatform *, int ifindex, int netns_fd); - - void (*process_events) (NMPlatform *self); - - gboolean (*link_set_up) (NMPlatform *, int ifindex, gboolean *out_no_firmware); - gboolean (*link_set_down) (NMPlatform *, int ifindex); - gboolean (*link_set_arp) (NMPlatform *, int ifindex); - gboolean (*link_set_noarp) (NMPlatform *, int ifindex); + gboolean (*link_delete) (NMPlatform *self, int ifindex); + gboolean (*link_refresh) (NMPlatform *self, int ifindex); + gboolean (*link_set_netns) (NMPlatform *self, int ifindex, int netns_fd); + gboolean (*link_set_up) (NMPlatform *self, int ifindex, gboolean *out_no_firmware); + gboolean (*link_set_down) (NMPlatform *self, int ifindex); + gboolean (*link_set_arp) (NMPlatform *self, int ifindex); + gboolean (*link_set_noarp) (NMPlatform *self, int ifindex); const char *(*link_get_udi) (NMPlatform *self, int ifindex); struct udev_device *(*link_get_udev_device) (NMPlatform *self, int ifindex); - int (*link_set_user_ipv6ll_enabled) (NMPlatform *, int ifindex, gboolean enabled); - gboolean (*link_set_token) (NMPlatform *, int ifindex, NMUtilsIPv6IfaceId iid); + int (*link_set_user_ipv6ll_enabled) (NMPlatform *self, int ifindex, gboolean enabled); + gboolean (*link_set_token) (NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId iid); - gboolean (*link_get_permanent_address) (NMPlatform *, + gboolean (*link_get_permanent_address) (NMPlatform *self, int ifindex, guint8 *buf, size_t *length); - int (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length); - int (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu); - gboolean (*link_set_name) (NMPlatform *, int ifindex, const char *name); - gboolean (*link_set_sriov_params) (NMPlatform *, int ifindex, guint num_vfs, int autoprobe); + int (*link_set_address) (NMPlatform *self, int ifindex, gconstpointer address, size_t length); + int (*link_set_mtu) (NMPlatform *self, int ifindex, guint32 mtu); + gboolean (*link_set_name) (NMPlatform *self, int ifindex, const char *name); + void (*link_set_sriov_params_async) (NMPlatform *self, + int ifindex, + guint num_vfs, + int autoprobe, + NMPlatformAsyncCallback callback, + gpointer callback_data, + GCancellable *cancellable); gboolean (*link_set_sriov_vfs) (NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs); gboolean (*link_set_bridge_vlans) (NMPlatform *self, int ifindex, gboolean on_master, const NMPlatformBridgeVlan *const *vlans); - char * (*link_get_physical_port_id) (NMPlatform *, int ifindex); - guint (*link_get_dev_id) (NMPlatform *, int ifindex); - gboolean (*link_get_wake_on_lan) (NMPlatform *, int ifindex); - gboolean (*link_get_driver_info) (NMPlatform *, + char * (*link_get_physical_port_id) (NMPlatform *self, int ifindex); + guint (*link_get_dev_id) (NMPlatform *self, int ifindex); + gboolean (*link_get_wake_on_lan) (NMPlatform *self, int ifindex); + gboolean (*link_get_driver_info) (NMPlatform *self, int ifindex, char **out_driver_name, char **out_driver_version, char **out_fw_version); - gboolean (*link_supports_carrier_detect) (NMPlatform *, int ifindex); - gboolean (*link_supports_vlans) (NMPlatform *, int ifindex); - gboolean (*link_supports_sriov) (NMPlatform *, int ifindex); + gboolean (*link_supports_carrier_detect) (NMPlatform *self, int ifindex); + gboolean (*link_supports_vlans) (NMPlatform *self, int ifindex); + gboolean (*link_supports_sriov) (NMPlatform *self, int ifindex); - gboolean (*link_enslave) (NMPlatform *, int master, int slave); - gboolean (*link_release) (NMPlatform *, int master, int slave); + gboolean (*link_enslave) (NMPlatform *self, int master, int slave); + gboolean (*link_release) (NMPlatform *self, int master, int slave); - gboolean (*link_can_assume) (NMPlatform *, int ifindex); + gboolean (*link_can_assume) (NMPlatform *self, int ifindex); int (*link_wireguard_change) (NMPlatform *self, int ifindex, @@ -1020,7 +1033,7 @@ typedef struct { guint peers_len, NMPlatformWireGuardChangeFlags change_flags); - gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags, const NMPlatformLink **out_link); + gboolean (*vlan_add) (NMPlatform *self, const char *name, int parent, int vlanid, guint32 vlanflags, const NMPlatformLink **out_link); gboolean (*link_vlan_change) (NMPlatform *self, int ifindex, NMVlanFlags flags_mask, @@ -1031,81 +1044,79 @@ typedef struct { gboolean egress_reset_all, const NMVlanQosMapping *egress_map, gsize n_egress_map); - gboolean (*link_vxlan_add) (NMPlatform *, + gboolean (*link_vxlan_add) (NMPlatform *self, const char *name, const NMPlatformLnkVxlan *props, const NMPlatformLink **out_link); - gboolean (*link_gre_add) (NMPlatform *, + gboolean (*link_gre_add) (NMPlatform *self, const char *name, const NMPlatformLnkGre *props, const NMPlatformLink **out_link); - gboolean (*link_ip6tnl_add) (NMPlatform *, + gboolean (*link_ip6tnl_add) (NMPlatform *self, const char *name, const NMPlatformLnkIp6Tnl *props, const NMPlatformLink **out_link); - gboolean (*link_ip6gre_add) (NMPlatform *, + gboolean (*link_ip6gre_add) (NMPlatform *self, const char *name, const NMPlatformLnkIp6Tnl *props, const NMPlatformLink **out_link); - gboolean (*link_ipip_add) (NMPlatform *, + gboolean (*link_ipip_add) (NMPlatform *self, const char *name, const NMPlatformLnkIpIp *props, const NMPlatformLink **out_link); - gboolean (*link_macsec_add) (NMPlatform *, + gboolean (*link_macsec_add) (NMPlatform *self, const char *name, int parent, const NMPlatformLnkMacsec *props, const NMPlatformLink **out_link); - gboolean (*link_macvlan_add) (NMPlatform *, + gboolean (*link_macvlan_add) (NMPlatform *self, const char *name, int parent, const NMPlatformLnkMacvlan *props, const NMPlatformLink **out_link); - gboolean (*link_sit_add) (NMPlatform *, + gboolean (*link_sit_add) (NMPlatform *self, const char *name, const NMPlatformLnkSit *props, const NMPlatformLink **out_link); - - gboolean (*link_tun_add) (NMPlatform *platform, + gboolean (*link_tun_add) (NMPlatform *self, const char *name, const NMPlatformLnkTun *props, const NMPlatformLink **out_link, int *out_fd); - - gboolean (*link_6lowpan_add) (NMPlatform *platform, + gboolean (*link_6lowpan_add) (NMPlatform *self, const char *name, int parent, const NMPlatformLink **out_link); - gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key, const NMPlatformLink **out_link); - gboolean (*infiniband_partition_delete) (NMPlatform *, int parent, int p_key); - - gboolean (*wifi_get_capabilities) (NMPlatform *, int ifindex, NMDeviceWifiCapabilities *caps); - gboolean (*wifi_get_bssid) (NMPlatform *, int ifindex, guint8 *bssid); - guint32 (*wifi_get_frequency) (NMPlatform *, int ifindex); - int (*wifi_get_quality) (NMPlatform *, int ifindex); - guint32 (*wifi_get_rate) (NMPlatform *, int ifindex); - NM80211Mode (*wifi_get_mode) (NMPlatform *, int ifindex); - void (*wifi_set_mode) (NMPlatform *, int ifindex, NM80211Mode mode); - void (*wifi_set_powersave) (NMPlatform *, int ifindex, guint32 powersave); - guint32 (*wifi_find_frequency) (NMPlatform *, int ifindex, const guint32 *freqs); - void (*wifi_indicate_addressing_running) (NMPlatform *, int ifindex, gboolean running); - NMSettingWirelessWakeOnWLan (*wifi_get_wake_on_wlan) (NMPlatform *, int ifindex); - gboolean (*wifi_set_wake_on_wlan) (NMPlatform *, int ifindex, NMSettingWirelessWakeOnWLan wowl); - - guint32 (*mesh_get_channel) (NMPlatform *, int ifindex); - gboolean (*mesh_set_channel) (NMPlatform *, int ifindex, guint32 channel); - gboolean (*mesh_set_ssid) (NMPlatform *, int ifindex, const guint8 *ssid, gsize len); - - guint16 (*wpan_get_pan_id) (NMPlatform *, int ifindex); - gboolean (*wpan_set_pan_id) (NMPlatform *, int ifindex, guint16 pan_id); - guint16 (*wpan_get_short_addr) (NMPlatform *, int ifindex); - gboolean (*wpan_set_short_addr) (NMPlatform *, int ifindex, guint16 short_addr); - gboolean (*wpan_set_channel) (NMPlatform *, int ifindex, guint8 page, guint8 channel); - - gboolean (*object_delete) (NMPlatform *, const NMPObject *obj); - - gboolean (*ip4_address_add) (NMPlatform *, + gboolean (*infiniband_partition_add) (NMPlatform *self, int parent, int p_key, const NMPlatformLink **out_link); + gboolean (*infiniband_partition_delete) (NMPlatform *self, int parent, int p_key); + + gboolean (*wifi_get_capabilities) (NMPlatform *self, int ifindex, NMDeviceWifiCapabilities *caps); + gboolean (*wifi_get_bssid) (NMPlatform *self, int ifindex, guint8 *bssid); + guint32 (*wifi_get_frequency) (NMPlatform *self, int ifindex); + int (*wifi_get_quality) (NMPlatform *self, int ifindex); + guint32 (*wifi_get_rate) (NMPlatform *self, int ifindex); + NM80211Mode (*wifi_get_mode) (NMPlatform *self, int ifindex); + void (*wifi_set_mode) (NMPlatform *self, int ifindex, NM80211Mode mode); + void (*wifi_set_powersave) (NMPlatform *self, int ifindex, guint32 powersave); + guint32 (*wifi_find_frequency) (NMPlatform *self, int ifindex, const guint32 *freqs); + void (*wifi_indicate_addressing_running) (NMPlatform *self, int ifindex, gboolean running); + NMSettingWirelessWakeOnWLan (*wifi_get_wake_on_wlan) (NMPlatform *self, int ifindex); + gboolean (*wifi_set_wake_on_wlan) (NMPlatform *self, int ifindex, NMSettingWirelessWakeOnWLan wowl); + + guint32 (*mesh_get_channel) (NMPlatform *self, int ifindex); + gboolean (*mesh_set_channel) (NMPlatform *self, int ifindex, guint32 channel); + gboolean (*mesh_set_ssid) (NMPlatform *self, int ifindex, const guint8 *ssid, gsize len); + + guint16 (*wpan_get_pan_id) (NMPlatform *self, int ifindex); + gboolean (*wpan_set_pan_id) (NMPlatform *self, int ifindex, guint16 pan_id); + guint16 (*wpan_get_short_addr) (NMPlatform *self, int ifindex); + gboolean (*wpan_set_short_addr) (NMPlatform *self, int ifindex, guint16 short_addr); + gboolean (*wpan_set_channel) (NMPlatform *self, int ifindex, guint8 page, guint8 channel); + + gboolean (*object_delete) (NMPlatform *self, const NMPObject *obj); + + gboolean (*ip4_address_add) (NMPlatform *self, int ifindex, in_addr_t address, guint8 plen, @@ -1114,7 +1125,7 @@ typedef struct { guint32 preferred_lft, guint32 flags, const char *label); - gboolean (*ip6_address_add) (NMPlatform *, + gboolean (*ip6_address_add) (NMPlatform *self, int ifindex, struct in6_addr address, guint8 plen, @@ -1122,10 +1133,10 @@ typedef struct { guint32 lifetime, guint32 preferred_lft, guint32 flags); - gboolean (*ip4_address_delete) (NMPlatform *, int ifindex, in_addr_t address, guint8 plen, in_addr_t peer_address); - gboolean (*ip6_address_delete) (NMPlatform *, int ifindex, struct in6_addr address, guint8 plen); + gboolean (*ip4_address_delete) (NMPlatform *self, int ifindex, in_addr_t address, guint8 plen, in_addr_t peer_address); + gboolean (*ip6_address_delete) (NMPlatform *self, int ifindex, struct in6_addr address, guint8 plen); - int (*ip_route_add) (NMPlatform *, + int (*ip_route_add) (NMPlatform *self, NMPNlmFlags flags, int addr_family, const NMPlatformIPRoute *route); @@ -1268,7 +1279,7 @@ gboolean nm_platform_get_use_udev (NMPlatform *self); gboolean nm_platform_get_log_with_ptr (NMPlatform *self); NMPNetns *nm_platform_netns_get (NMPlatform *self); -gboolean nm_platform_netns_push (NMPlatform *platform, NMPNetns **netns); +gboolean nm_platform_netns_push (NMPlatform *self, NMPNetns **netns); const char *nm_link_type_to_string (NMLinkType link_type); @@ -1294,16 +1305,24 @@ const char *nm_link_type_to_string (NMLinkType link_type); int nm_platform_sysctl_open_netdir (NMPlatform *self, int ifindex, char *out_ifname); gboolean nm_platform_sysctl_set (NMPlatform *self, const char *pathid, int dirfd, const char *path, const char *value); +void nm_platform_sysctl_set_async (NMPlatform *self, + const char *pathid, + int dirfd, + const char *path, + const char *const *values, + NMPlatformAsyncCallback callback, + gpointer data, + GCancellable *cancellable); char *nm_platform_sysctl_get (NMPlatform *self, const char *pathid, int dirfd, const char *path); gint32 nm_platform_sysctl_get_int32 (NMPlatform *self, const char *pathid, int dirfd, const char *path, gint32 fallback); gint64 nm_platform_sysctl_get_int_checked (NMPlatform *self, const char *pathid, int dirfd, const char *path, guint base, gint64 min, gint64 max, gint64 fallback); -char *nm_platform_sysctl_ip_conf_get (NMPlatform *platform, +char *nm_platform_sysctl_ip_conf_get (NMPlatform *self, int addr_family, const char *ifname, const char *property); -gint64 nm_platform_sysctl_ip_conf_get_int_checked (NMPlatform *platform, +gint64 nm_platform_sysctl_ip_conf_get_int_checked (NMPlatform *self, int addr_family, const char *ifname, const char *property, @@ -1312,13 +1331,13 @@ gint64 nm_platform_sysctl_ip_conf_get_int_checked (NMPlatform *platform, gint64 max, gint64 fallback); -gboolean nm_platform_sysctl_ip_conf_set (NMPlatform *platform, +gboolean nm_platform_sysctl_ip_conf_set (NMPlatform *self, int addr_family, const char *ifname, const char *property, const char *value); -gboolean nm_platform_sysctl_ip_conf_set_int64 (NMPlatform *platform, +gboolean nm_platform_sysctl_ip_conf_set_int64 (NMPlatform *self, int addr_family, const char *ifname, const char *property, @@ -1351,7 +1370,7 @@ gboolean nm_platform_link_set_netns (NMPlatform *self, int ifindex, int netns_fd struct _NMDedupMultiHeadEntry; struct _NMPLookup; -const struct _NMDedupMultiHeadEntry *nm_platform_lookup (NMPlatform *platform, +const struct _NMDedupMultiHeadEntry *nm_platform_lookup (NMPlatform *self, const struct _NMPLookup *lookup); gboolean nm_platform_lookup_predicate_routes_main (const NMPObject *obj, @@ -1359,7 +1378,7 @@ gboolean nm_platform_lookup_predicate_routes_main (const NMPObject *obj, gboolean nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel (const NMPObject *obj, gpointer user_data); -GPtrArray *nm_platform_lookup_clone (NMPlatform *platform, +GPtrArray *nm_platform_lookup_clone (NMPlatform *self, const struct _NMPLookup *lookup, NMPObjectPredicateFunc predicate, gpointer user_data); @@ -1421,7 +1440,15 @@ gboolean nm_platform_link_get_permanent_address (NMPlatform *self, int ifindex, int nm_platform_link_set_address (NMPlatform *self, int ifindex, const void *address, size_t length); int nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu); gboolean nm_platform_link_set_name (NMPlatform *self, int ifindex, const char *name); -gboolean nm_platform_link_set_sriov_params (NMPlatform *self, int ifindex, guint num_vfs, int autoprobe); + +void nm_platform_link_set_sriov_params_async (NMPlatform *self, + int ifindex, + guint num_vfs, + int autoprobe, + NMPlatformAsyncCallback callback, + gpointer callback_data, + GCancellable *cancellable); + gboolean nm_platform_link_set_sriov_vfs (NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs); gboolean nm_platform_link_set_bridge_vlans (NMPlatform *self, int ifindex, gboolean on_master, const NMPlatformBridgeVlan *const *vlans); @@ -1519,11 +1546,11 @@ guint32 nm_platform_mesh_get_channel (NMPlatform *self, int ifindex); gboolean nm_platform_mesh_set_channel (NMPlatform *self, int ifindex, guint32 channel); gboolean nm_platform_mesh_set_ssid (NMPlatform *self, int ifindex, const guint8 *ssid, gsize len); -guint16 nm_platform_wpan_get_pan_id (NMPlatform *platform, int ifindex); -gboolean nm_platform_wpan_set_pan_id (NMPlatform *platform, int ifindex, guint16 pan_id); -guint16 nm_platform_wpan_get_short_addr (NMPlatform *platform, int ifindex); -gboolean nm_platform_wpan_set_short_addr (NMPlatform *platform, int ifindex, guint16 short_addr); -gboolean nm_platform_wpan_set_channel (NMPlatform *platform, int ifindex, guint8 page, guint8 channel); +guint16 nm_platform_wpan_get_pan_id (NMPlatform *self, int ifindex); +gboolean nm_platform_wpan_set_pan_id (NMPlatform *self, int ifindex, guint16 pan_id); +guint16 nm_platform_wpan_get_short_addr (NMPlatform *self, int ifindex); +gboolean nm_platform_wpan_set_short_addr (NMPlatform *self, int ifindex, guint16 short_addr); +gboolean nm_platform_wpan_set_channel (NMPlatform *self, int ifindex, guint8 page, guint8 channel); void nm_platform_ip4_address_set_addr (NMPlatformIP4Address *addr, in_addr_t address, guint8 plen); const struct in6_addr *nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr); diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index a2e3a6efb1..bff030bfd3 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -3015,6 +3015,92 @@ test_sysctl_netns_switch (void) nmtstp_link_delete (PL, FALSE, ifindex, NULL, TRUE); } +static void +sysctl_set_async_cb_assert_success (GError *error, gpointer data) +{ + g_assert_no_error (error); + g_main_loop_quit (data); +} + +static void +sysctl_set_async_cb_assert_failure (GError *error, gpointer data) +{ + g_assert (error); + g_main_loop_quit (data); +} + +static void +test_sysctl_set_async (void) +{ + NMPlatform *const PL = NM_PLATFORM_GET; + const char *const IFNAME = "nm-dummy-0"; + const char *const PATH = "/proc/sys/net/ipv4/conf/nm-dummy-0/rp_filter"; + gs_free GMainLoop *loop = NULL; + gs_unref_object GCancellable *cancellable = NULL; + int ifindex; + + ifindex = nmtstp_link_dummy_add (PL, -1, IFNAME)->ifindex; + loop = g_main_loop_new (NULL, FALSE); + cancellable = g_cancellable_new (); + + nm_platform_sysctl_set_async (PL, + NMP_SYSCTL_PATHID_ABSOLUTE (PATH), + (const char *[]) { "2", NULL}, + sysctl_set_async_cb_assert_success, + loop, + cancellable); + + if (!nmtst_main_loop_run (loop, 1000)) + g_assert_not_reached (); + + g_assert_cmpint (nm_platform_sysctl_get_int32 (PL, NMP_SYSCTL_PATHID_ABSOLUTE (PATH), -1), + ==, + 2); + + nm_platform_sysctl_set_async (PL, + NMP_SYSCTL_PATHID_ABSOLUTE (PATH), + (const char *[]) { "2", "0", "1", "0", "1", NULL}, + sysctl_set_async_cb_assert_success, + loop, + cancellable); + + if (!nmtst_main_loop_run (loop, 2000)) + g_assert_not_reached (); + + g_assert_cmpint (nm_platform_sysctl_get_int32 (PL, NMP_SYSCTL_PATHID_ABSOLUTE (PATH), -1), + ==, + 1); + + nmtstp_link_delete (NULL, -1, ifindex, IFNAME, TRUE); +} + +static void +test_sysctl_set_async_fail (void) +{ + NMPlatform *const PL = NM_PLATFORM_GET; + const char *const IFNAME = "nm-dummy-0"; + const char *const PATH = "/proc/sys/net/ipv4/conf/nm-dummy-0/does-not-exist"; + gs_free GMainLoop *loop = NULL; + gs_unref_object GCancellable *cancellable = NULL; + int ifindex; + + ifindex = nmtstp_link_dummy_add (PL, -1, IFNAME)->ifindex; + loop = g_main_loop_new (NULL, FALSE); + cancellable = g_cancellable_new (); + + nm_platform_sysctl_set_async (PL, + NMP_SYSCTL_PATHID_ABSOLUTE (PATH), + (const char *[]) { "2", NULL}, + sysctl_set_async_cb_assert_failure, + loop, + cancellable); + + if (!nmtst_main_loop_run (loop, 1000)) + g_assert_not_reached (); + + nmtstp_link_delete (NULL, -1, ifindex, IFNAME, TRUE); +} + /*****************************************************************************/ static gpointer @@ -3238,6 +3324,8 @@ _nmtstp_setup_tests (void) g_test_add_func ("/general/sysctl/rename", test_sysctl_rename); g_test_add_func ("/general/sysctl/netns-switch", test_sysctl_netns_switch); + g_test_add_func ("/general/sysctl/set-async", test_sysctl_set_async); + g_test_add_func ("/general/sysctl/set-async-fail", test_sysctl_set_async_fail); g_test_add_func ("/link/ethtool/features/get", test_ethtool_features_get); } |