From bf654ef39e5d394f6fa73b2fa402e7edc95bf5cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8D=C3=B1igo=20Huguet?= Date: Wed, 14 Feb 2024 10:09:56 +0100 Subject: [PATCH] devlink: get and set eswitch inline-mode and encap-mode The setter function allow to set to "preserve" to modify only some of them. --- src/libnm-base/nm-base.h | 21 +++- src/libnm-platform/devlink/nm-devlink.c | 145 ++++++++++++++---------- src/libnm-platform/devlink/nm-devlink.h | 12 +- src/libnm-platform/nm-linux-platform.c | 15 ++- 4 files changed, 123 insertions(+), 70 deletions(-) diff --git a/src/libnm-base/nm-base.h b/src/libnm-base/nm-base.h index c313bccf6e..d77ff9ec1e 100644 --- a/src/libnm-base/nm-base.h +++ b/src/libnm-base/nm-base.h @@ -278,12 +278,31 @@ typedef enum { } _NMVlanFlags; typedef enum { - /* Mirrors libnm's NMSriovEswitchMode */ + /* Mirrors libnm's NMSriovEswitchMode. + * Values >= 0 mirror kernel's enum devlink_eswitch_mode. */ _NM_SRIOV_ESWITCH_MODE_PRESERVE = -1, _NM_SRIOV_ESWITCH_MODE_LEGACY = 0, _NM_SRIOV_ESWITCH_MODE_SWITCHDEV = 1, } _NMSriovEswitchMode; +typedef enum { + /* Mirrors libnm's NMSriovEswitchInlineMode. + * Values >= 0 mirror kernel's enum devlink_eswitch_inline_mode. */ + _NM_SRIOV_ESWITCH_INLINE_MODE_PRESERVE = -1, + _NM_SRIOV_ESWITCH_INLINE_MODE_NONE = 0, + _NM_SRIOV_ESWITCH_INLINE_MODE_LINK = 1, + _NM_SRIOV_ESWITCH_INLINE_MODE_NETWORK = 2, + _NM_SRIOV_ESWITCH_INLINE_MODE_TRANSPORT = 3, +} _NMSriovEswitchInlineMode; + +typedef enum { + /* Mirrors libnm's NMSriovEswitchEncapMode. + * Values >= 0 mirror kernel's enum devlink_eswitch_encap_mode. */ + _NM_SRIOV_ESWITCH_ENCAP_MODE_PRESERVE = -1, + _NM_SRIOV_ESWITCH_ENCAP_MODE_NONE = 0, + _NM_SRIOV_ESWITCH_ENCAP_MODE_BASIC = 1, +} _NMSriovEswitchEncapMode; + /*****************************************************************************/ typedef enum { diff --git a/src/libnm-platform/devlink/nm-devlink.c b/src/libnm-platform/devlink/nm-devlink.c index dc68bafde5..a2fee3bcf3 100644 --- a/src/libnm-platform/devlink/nm-devlink.c +++ b/src/libnm-platform/devlink/nm-devlink.c @@ -58,7 +58,7 @@ struct _NMDevlink { NMDevlink * nm_devlink_new(NMPlatform *platform, struct nl_sock *genl_sock_sync, int ifindex) { - NMDevlink *self = g_new(NMDevlink, 1); + NMDevlink *self = g_new(NMDevlink, 1); self->plat = platform; self->genl_sock_sync = genl_sock_sync; @@ -230,81 +230,41 @@ static int devlink_parse_eswitch_mode(const struct nl_msg *msg, void *data) { static const struct nla_policy eswitch_policy[] = { - [DEVLINK_ATTR_ESWITCH_MODE] = {.type = NLA_U16}, + [DEVLINK_ATTR_ESWITCH_MODE] = {.type = NLA_U16}, + [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = {.type = NLA_U8}, + [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = {.type = NLA_U8}, }; - enum devlink_eswitch_mode *eswitch_mode = data; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct nlattr *tb[G_N_ELEMENTS(eswitch_policy)]; + NMDevlinkEswitchParams *params = data; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb[G_N_ELEMENTS(eswitch_policy)]; if (nla_parse_arr(tb, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), eswitch_policy) < 0) return NL_SKIP; - if (!tb[DEVLINK_ATTR_ESWITCH_MODE]) + if (!tb[DEVLINK_ATTR_ESWITCH_MODE] || !tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE] + || !tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) return NL_SKIP; - *eswitch_mode = nla_get_u16(tb[DEVLINK_ATTR_ESWITCH_MODE]); + params->mode = (_NMSriovEswitchMode) nla_get_u16(tb[DEVLINK_ATTR_ESWITCH_MODE]); + params->encap_mode = (_NMSriovEswitchEncapMode) nla_get_u8(tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]); + params->inline_mode = + (_NMSriovEswitchInlineMode) nla_get_u8(tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE]); return NL_OK; } /* - * nm_devlink_get_eswitch_mode: + * nm_devlink_get_eswitch_params: * @self: the #NMDevlink + * @out_params: the eswitch parameters read via Devlink * @error: the error location * - * Get the eswitch mode of the device related to the #NMDevlink instance. Note - * that this might be unsupported by the device (see nm_devlink_get_dev()). - * - * Returns: the eswitch mode of the device, or <0 in case of error - */ -int -nm_devlink_get_eswitch_mode(NMDevlink *self, GError **error) -{ - nm_auto_nlmsg struct nl_msg *msg = NULL; - gs_free char *bus = NULL; - gs_free char *addr = NULL; - enum devlink_eswitch_mode eswitch_mode; - gs_free char *err_msg = NULL; - int rc; - - if (!nm_devlink_get_dev_identifier(self, &bus, &addr, error)) - return -1; - - msg = devlink_alloc_msg(self, DEVLINK_CMD_ESWITCH_GET, 0); - NLA_PUT_STRING(msg, DEVLINK_ATTR_BUS_NAME, bus); - NLA_PUT_STRING(msg, DEVLINK_ATTR_DEV_NAME, addr); - - rc = devlink_send_and_recv(self, msg, devlink_parse_eswitch_mode, &eswitch_mode, &err_msg); - if (rc < 0) { - g_set_error(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "devlink: get-eswitch-mode: failed (%d) %s", - rc, - err_msg); - return rc; - } - - _LOGD("get-eswitch-mode: success"); - - return (int) eswitch_mode; - -nla_put_failure: - g_return_val_if_reached(-1); -} - -/* - * nm_devlink_set_eswitch_mode: - * @self: the #NMDevlink - * @mode: the eswitch mode to set - * @error: the error location - * - * Set the eswitch mode of the device related to the #NMDevlink instance. Note + * Get the eswitch configuration of the device related to the #NMDevlink instance. Note * that this might be unsupported by the device (see nm_devlink_get_dev()). * * Returns: FALSE in case of error, TRUE otherwise */ gboolean -nm_devlink_set_eswitch_mode(NMDevlink *self, enum devlink_eswitch_mode mode, GError **error) +nm_devlink_get_eswitch_params(NMDevlink *self, NMDevlinkEswitchParams *out_params, GError **error) { nm_auto_nlmsg struct nl_msg *msg = NULL; gs_free char *bus = NULL; @@ -312,26 +272,87 @@ nm_devlink_set_eswitch_mode(NMDevlink *self, enum devlink_eswitch_mode mode, GEr gs_free char *err_msg = NULL; int rc; + nm_assert(out_params); + if (!nm_devlink_get_dev_identifier(self, &bus, &addr, error)) return FALSE; - msg = devlink_alloc_msg(self, DEVLINK_CMD_ESWITCH_SET, 0); + msg = devlink_alloc_msg(self, DEVLINK_CMD_ESWITCH_GET, 0); NLA_PUT_STRING(msg, DEVLINK_ATTR_BUS_NAME, bus); NLA_PUT_STRING(msg, DEVLINK_ATTR_DEV_NAME, addr); - NLA_PUT_U16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode); - rc = devlink_send_and_recv(self, msg, NULL, NULL, &err_msg); + rc = devlink_send_and_recv(self, msg, devlink_parse_eswitch_mode, out_params, &err_msg); if (rc < 0) { g_set_error(error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "devlink: set-eswitch-mode: failed (%d) %s", + "devlink: eswitch get: failed (%d) %s", rc, err_msg); return FALSE; } - _LOGD("set-eswitch-mode: success"); + _LOGD("eswitch get: success"); + + return TRUE; + +nla_put_failure: + g_return_val_if_reached(FALSE); +} + +/* + * nm_devlink_set_eswitch_params: + * @self: the #NMDevlink + * @params: the eswitch parameters to set + * @error: the error location + * + * Set the eswitch configuration of the device related to the #NMDevlink instance. Note + * that this might be unsupported by the device (see nm_devlink_get_dev()). + * + * If any of the eswitch parameters is set to "preserve" it won't be modified. + * + * Returns: FALSE in case of error, TRUE otherwise + */ +gboolean +nm_devlink_set_eswitch_params(NMDevlink *self, NMDevlinkEswitchParams params, GError **error) +{ + nm_auto_nlmsg struct nl_msg *msg = NULL; + gs_free char *bus = NULL; + gs_free char *addr = NULL; + gs_free char *err_msg = NULL; + int rc; + + if (params.mode == _NM_SRIOV_ESWITCH_MODE_PRESERVE + && params.inline_mode == _NM_SRIOV_ESWITCH_INLINE_MODE_PRESERVE + && params.encap_mode == _NM_SRIOV_ESWITCH_ENCAP_MODE_PRESERVE) + return TRUE; + + if (!nm_devlink_get_dev_identifier(self, &bus, &addr, error)) + return FALSE; + + msg = devlink_alloc_msg(self, DEVLINK_CMD_ESWITCH_SET, 0); + NLA_PUT_STRING(msg, DEVLINK_ATTR_BUS_NAME, bus); + NLA_PUT_STRING(msg, DEVLINK_ATTR_DEV_NAME, addr); + + if (params.mode != _NM_SRIOV_ESWITCH_MODE_PRESERVE) + NLA_PUT_U16(msg, DEVLINK_ATTR_ESWITCH_MODE, params.mode); + if (params.inline_mode != _NM_SRIOV_ESWITCH_INLINE_MODE_PRESERVE) + NLA_PUT_U8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE, params.inline_mode); + if (params.encap_mode != _NM_SRIOV_ESWITCH_ENCAP_MODE_PRESERVE) + NLA_PUT_U8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, params.encap_mode); + + rc = devlink_send_and_recv(self, msg, NULL, NULL, &err_msg); + if (rc < 0) { + g_set_error(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + "devlink: eswitch set: failed (%d) %s", + rc, + err_msg); + return FALSE; + } + + _LOGD("eswitch set: success"); return TRUE; diff --git a/src/libnm-platform/devlink/nm-devlink.h b/src/libnm-platform/devlink/nm-devlink.h index 789b13d3ab..c626a1206d 100644 --- a/src/libnm-platform/devlink/nm-devlink.h +++ b/src/libnm-platform/devlink/nm-devlink.h @@ -6,17 +6,25 @@ #ifndef __NMP_DEVLINK_H__ #define __NMP_DEVLINK_H__ +#include "libnm-base/nm-base.h" #include struct nl_sock; typedef struct _NMPlatform NMPlatform; typedef struct _NMDevlink NMDevlink; +typedef struct { + _NMSriovEswitchMode mode; + _NMSriovEswitchInlineMode inline_mode; + _NMSriovEswitchEncapMode encap_mode; +} NMDevlinkEswitchParams; + NMDevlink *nm_devlink_new(NMPlatform *platform, struct nl_sock *genl_sock_sync, int ifindex); gboolean nm_devlink_get_dev_identifier(NMDevlink *self, char **out_bus, char **out_addr, GError **error); -int nm_devlink_get_eswitch_mode(NMDevlink *self, GError **error); gboolean -nm_devlink_set_eswitch_mode(NMDevlink *self, enum devlink_eswitch_mode mode, GError **error); +nm_devlink_get_eswitch_params(NMDevlink *self, NMDevlinkEswitchParams *out_params, GError **error); +gboolean +nm_devlink_set_eswitch_params(NMDevlink *self, NMDevlinkEswitchParams params, GError **error); #endif /* __NMP_DEVLINK_H__ */ \ No newline at end of file diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 1e92f60309..765b02e788 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -9076,16 +9076,20 @@ sriov_async_step2_set_eswitch_mode(SriovAsyncState *async_state) { NMPlatform *platform = async_state->platform; NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - enum devlink_eswitch_mode eswitch_mode = (enum devlink_eswitch_mode) async_state->eswitch_mode; gs_free NMDevlink *devlink = NULL; gs_free_error GError *error = NULL; + NMDevlinkEswitchParams eswitch_params; - _LOGD("setting eswitch-mode to '%d'", (int) eswitch_mode); + _LOGD("setting eswitch-mode to '%d'", (int) async_state->eswitch_mode); + + eswitch_params.mode = (_NMSriovEswitchMode) async_state->eswitch_mode; + eswitch_params.inline_mode = _NM_SRIOV_ESWITCH_INLINE_MODE_PRESERVE; + eswitch_params.encap_mode = _NM_SRIOV_ESWITCH_ENCAP_MODE_PRESERVE; /* We set eswitch mode as a sriov_async step because it's in the middle of * other steps that are async. However, this step itself is synchronous. */ devlink = nm_devlink_new(platform, priv->sk_genl_sync, async_state->ifindex); - if (!nm_devlink_set_eswitch_mode(devlink, eswitch_mode, &error)) { + if (!nm_devlink_set_eswitch_params(devlink, eswitch_params, &error)) { sriov_async_finish_err(async_state, g_steal_pointer(&error)); return; } @@ -9135,6 +9139,7 @@ link_set_sriov_params_async(NMPlatform *platform, int max_vfs; int current_num_vfs; int current_eswitch_mode = _NM_SRIOV_ESWITCH_MODE_PRESERVE; + NMDevlinkEswitchParams eswitch_params; gboolean need_change_eswitch_mode; gboolean need_change_vfs; gboolean need_destroy_vfs; @@ -9202,11 +9207,11 @@ link_set_sriov_params_async(NMPlatform *platform, if (eswitch_mode != _NM_SRIOV_ESWITCH_MODE_PRESERVE) { gs_free NMDevlink *devlink = nm_devlink_new(platform, priv->sk_genl_sync, ifindex); - current_eswitch_mode = nm_devlink_get_eswitch_mode(devlink, &error); - if (current_eswitch_mode < 0) { + if (!nm_devlink_get_eswitch_params(devlink, &eswitch_params, &error)) { sriov_async_finish_err(async_state, g_steal_pointer(&error)); return; } + current_eswitch_mode = eswitch_params.mode; } /* Decide what actions we must do. Note that we might need to destroy the VFs even