@@ -40,6 +40,18 @@ definitions:
doc:
This feature informs if netdev implements non-linear XDP buffer
support in ndo_xdp_xmit callback.
+ -
+ type: enum
+ name: xdp-act-bit
+ render-max: true
+ entries:
+ - name: basic-bit
+ - name: redirect-bit
+ - name: ndo-xmit-bit
+ - name: xsk-zerocopy-bit
+ - name: hw-offload-bit
+ - name: rx-sg-bit
+ - name: ndo-xmit-sg-bit
attribute-sets:
-
@@ -681,6 +681,7 @@ enum ethtool_link_ext_substate_module {
* @ETH_SS_STATS_ETH_MAC: names of IEEE 802.3 MAC statistics
* @ETH_SS_STATS_ETH_CTRL: names of IEEE 802.3 MAC Control statistics
* @ETH_SS_STATS_RMON: names of RMON statistics
+ * @ETH_SS_XDP_FEATURES: names of XDP supported features
*
* @ETH_SS_COUNT: number of defined string sets
*/
@@ -706,6 +707,7 @@ enum ethtool_stringset {
ETH_SS_STATS_ETH_MAC,
ETH_SS_STATS_ETH_CTRL,
ETH_SS_STATS_RMON,
+ ETH_SS_XDP_FEATURES,
/* add new constants above here */
ETH_SS_COUNT
@@ -1429,6 +1431,18 @@ struct ethtool_sfeatures {
struct ethtool_set_features_block features[];
};
+/**
+ * struct ethtool_xdp_gfeatures - command to get supported XDP features
+ * @cmd: command number = %ETHTOOL_XDP_GFEATURES
+ * size: array size of the features[] array
+ * @features: XDP feature masks
+ */
+struct ethtool_xdp_gfeatures {
+ __u32 cmd;
+ __u32 size;
+ __u32 features[];
+};
+
/**
* struct ethtool_ts_info - holds a device's timestamping and PHC association
* @cmd: command number = %ETHTOOL_GET_TS_INFO
@@ -1670,6 +1684,7 @@ enum ethtool_fec_config_bits {
#define ETHTOOL_PHY_STUNABLE 0x0000004f /* Set PHY tunable configuration */
#define ETHTOOL_GFECPARAM 0x00000050 /* Get FEC settings */
#define ETHTOOL_SFECPARAM 0x00000051 /* Set FEC settings */
+#define ETHTOOL_XDP_GFEATURES 0x00000052 /* Get XDP features */
/* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET
@@ -57,6 +57,7 @@ enum {
ETHTOOL_MSG_PLCA_GET_STATUS,
ETHTOOL_MSG_MM_GET,
ETHTOOL_MSG_MM_SET,
+ ETHTOOL_MSG_XDP_FEATURES_GET,
/* add new constants above here */
__ETHTOOL_MSG_USER_CNT,
@@ -109,6 +110,7 @@ enum {
ETHTOOL_MSG_PLCA_NTF,
ETHTOOL_MSG_MM_GET_REPLY,
ETHTOOL_MSG_MM_NTF,
+ ETHTOOL_MSG_XDP_FEATURES_GET_REPLY,
/* add new constants above here */
__ETHTOOL_MSG_KERNEL_CNT,
@@ -973,6 +975,18 @@ enum {
ETHTOOL_A_MM_MAX = (__ETHTOOL_A_MM_CNT - 1)
};
+/* XDP */
+
+enum {
+ ETHTOOL_A_XDP_FEATURES_UNSPEC,
+ ETHTOOL_A_XDP_FEATURES_HEADER, /* nest - _A_HEADER_* */
+ ETHTOOL_A_XDP_FEATURES_DATA, /* bitsets */
+
+ /* add new constants above here */
+ __ETHTOOL_A_XDP_FEATURES_CNT,
+ ETHTOOL_A_XDP_FEATURES_MAX = __ETHTOOL_A_XDP_FEATURES_CNT - 1
+};
+
/* generic netlink info */
#define ETHTOOL_GENL_NAME "ethtool"
#define ETHTOOL_GENL_VERSION 1
@@ -37,6 +37,19 @@ enum netdev_xdp_act {
NETDEV_XDP_ACT_MASK = 127,
};
+enum netdev_xdp_act_bit {
+ NETDEV_XDP_ACT_BIT_BASIC_BIT,
+ NETDEV_XDP_ACT_BIT_REDIRECT_BIT,
+ NETDEV_XDP_ACT_BIT_NDO_XMIT_BIT,
+ NETDEV_XDP_ACT_BIT_XSK_ZEROCOPY_BIT,
+ NETDEV_XDP_ACT_BIT_HW_OFFLOAD_BIT,
+ NETDEV_XDP_ACT_BIT_RX_SG_BIT,
+ NETDEV_XDP_ACT_BIT_NDO_XMIT_SG_BIT,
+
+ __NETDEV_XDP_ACT_BIT_MAX,
+ NETDEV_XDP_ACT_BIT_MAX = (__NETDEV_XDP_ACT_BIT_MAX - 1)
+};
+
enum {
NETDEV_A_DEV_IFINDEX = 1,
NETDEV_A_DEV_PAD,
@@ -8,4 +8,4 @@ ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o rss.o \
linkstate.o debug.o wol.o features.o privflags.o rings.o \
channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \
tunnels.o fec.o eeprom.o stats.o phc_vclocks.o mm.o \
- module.o pse-pd.o plca.o mm.o
+ module.o pse-pd.o plca.o mm.o xdp.o
@@ -465,6 +465,17 @@ const char udp_tunnel_type_names[][ETH_GSTRING_LEN] = {
static_assert(ARRAY_SIZE(udp_tunnel_type_names) ==
__ETHTOOL_UDP_TUNNEL_TYPE_CNT);
+const char xdp_features_strings[][ETH_GSTRING_LEN] = {
+ [NETDEV_XDP_ACT_BIT_BASIC_BIT] = "xdp-basic",
+ [NETDEV_XDP_ACT_BIT_REDIRECT_BIT] = "xdp-redirect",
+ [NETDEV_XDP_ACT_BIT_NDO_XMIT_BIT] = "xdp-ndo-xmit",
+ [NETDEV_XDP_ACT_BIT_XSK_ZEROCOPY_BIT] = "xdp-xsk-zerocopy",
+ [NETDEV_XDP_ACT_BIT_HW_OFFLOAD_BIT] = "xdp-hw-offload",
+ [NETDEV_XDP_ACT_BIT_RX_SG_BIT] = "xdp-rx-sg",
+ [NETDEV_XDP_ACT_BIT_NDO_XMIT_SG_BIT] = "xdp-ndo-xmit-sg",
+};
+static_assert(ARRAY_SIZE(xdp_features_strings) == __NETDEV_XDP_ACT_BIT_MAX);
+
/* return false if legacy contained non-0 deprecated fields
* maxtxpkt/maxrxpkt. rest of ksettings always updated
*/
@@ -7,6 +7,7 @@
#include <linux/ethtool.h>
#define ETHTOOL_DEV_FEATURE_WORDS DIV_ROUND_UP(NETDEV_FEATURE_COUNT, 32)
+#define ETHTOOL_XDP_FEATURES_WORDS DIV_ROUND_UP(__NETDEV_XDP_ACT_BIT_MAX, 32)
/* compose link mode index from speed, type and duplex */
#define ETHTOOL_LINK_MODE(speed, type, duplex) \
@@ -36,6 +37,7 @@ extern const char sof_timestamping_names[][ETH_GSTRING_LEN];
extern const char ts_tx_type_names[][ETH_GSTRING_LEN];
extern const char ts_rx_filter_names[][ETH_GSTRING_LEN];
extern const char udp_tunnel_type_names[][ETH_GSTRING_LEN];
+extern const char xdp_features_strings[__NETDEV_XDP_ACT_BIT_MAX][ETH_GSTRING_LEN];
int __ethtool_get_link(struct net_device *dev);
@@ -170,6 +170,9 @@ static int __ethtool_get_sset_count(struct net_device *dev, int sset)
if (sset == ETH_SS_PHY_TUNABLES)
return ARRAY_SIZE(phy_tunable_strings);
+ if (sset == ETH_SS_XDP_FEATURES)
+ return __NETDEV_XDP_ACT_BIT_MAX;
+
if (sset == ETH_SS_PHY_STATS && dev->phydev &&
!ops->get_ethtool_phy_stats &&
phy_ops && phy_ops->get_sset_count)
@@ -200,6 +203,8 @@ static void __ethtool_get_strings(struct net_device *dev,
memcpy(data, tunable_strings, sizeof(tunable_strings));
else if (stringset == ETH_SS_PHY_TUNABLES)
memcpy(data, phy_tunable_strings, sizeof(phy_tunable_strings));
+ else if (stringset == ETH_SS_XDP_FEATURES)
+ memcpy(data, xdp_features_strings, sizeof(xdp_features_strings));
else if (stringset == ETH_SS_PHY_STATS && dev->phydev &&
!ops->get_ethtool_phy_stats && phy_ops &&
phy_ops->get_strings)
@@ -2749,6 +2754,37 @@ static int ethtool_set_fecparam(struct net_device *dev, void __user *useraddr)
return dev->ethtool_ops->set_fecparam(dev, &fecparam);
}
+static int ethtool_get_xdp_features(struct net_device *dev,
+ void __user *useraddr)
+{
+ u32 copy_size, features[ETHTOOL_XDP_FEATURES_WORDS];
+ struct ethtool_gfeatures cmd = {
+ .cmd = ETHTOOL_XDP_GFEATURES,
+ .size = ETHTOOL_XDP_FEATURES_WORDS,
+ };
+ u32 __user *sizeaddr;
+
+ BUILD_BUG_ON(ETHTOOL_XDP_FEATURES_WORDS != 1);
+ features[0] = dev->xdp_features;
+
+ sizeaddr = useraddr + offsetof(struct ethtool_xdp_gfeatures, size);
+ if (get_user(copy_size, sizeaddr))
+ return -EFAULT;
+
+ if (copy_size > ETHTOOL_XDP_FEATURES_WORDS)
+ copy_size = ETHTOOL_XDP_FEATURES_WORDS;
+
+ if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
+ return -EFAULT;
+
+ useraddr += sizeof(cmd);
+ if (copy_to_user(useraddr, features,
+ array_size(copy_size, sizeof(*features))))
+ return -EFAULT;
+
+ return 0;
+}
+
/* The main entry point in this file. Called from net/core/dev_ioctl.c */
static int
@@ -2808,6 +2844,7 @@ __dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr,
case ETHTOOL_PHY_GTUNABLE:
case ETHTOOL_GLINKSETTINGS:
case ETHTOOL_GFECPARAM:
+ case ETHTOOL_XDP_GFEATURES:
break;
default:
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
@@ -3035,6 +3072,9 @@ __dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr,
case ETHTOOL_SFECPARAM:
rc = ethtool_set_fecparam(dev, useraddr);
break;
+ case ETHTOOL_XDP_GFEATURES:
+ rc = ethtool_get_xdp_features(dev, useraddr);
+ break;
default:
rc = -EOPNOTSUPP;
}
@@ -306,6 +306,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = {
[ETHTOOL_MSG_PLCA_GET_STATUS] = ðnl_plca_status_request_ops,
[ETHTOOL_MSG_MM_GET] = ðnl_mm_request_ops,
[ETHTOOL_MSG_MM_SET] = ðnl_mm_request_ops,
+ [ETHTOOL_MSG_XDP_FEATURES_GET] = ðnl_xdp_request_ops,
};
static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
@@ -1156,6 +1157,15 @@ static const struct genl_ops ethtool_genl_ops[] = {
.policy = ethnl_mm_set_policy,
.maxattr = ARRAY_SIZE(ethnl_mm_set_policy) - 1,
},
+ {
+ .cmd = ETHTOOL_MSG_XDP_FEATURES_GET,
+ .doit = ethnl_default_doit,
+ .start = ethnl_default_start,
+ .dumpit = ethnl_default_dumpit,
+ .done = ethnl_default_done,
+ .policy = ethnl_xdp_features_get_policy,
+ .maxattr = ARRAY_SIZE(ethnl_xdp_features_get_policy) - 1,
+ }
};
static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
@@ -395,6 +395,7 @@ extern const struct ethnl_request_ops ethnl_rss_request_ops;
extern const struct ethnl_request_ops ethnl_plca_cfg_request_ops;
extern const struct ethnl_request_ops ethnl_plca_status_request_ops;
extern const struct ethnl_request_ops ethnl_mm_request_ops;
+extern const struct ethnl_request_ops ethnl_xdp_request_ops;
extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1];
extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1];
@@ -441,6 +442,7 @@ extern const struct nla_policy ethnl_plca_set_cfg_policy[ETHTOOL_A_PLCA_MAX + 1]
extern const struct nla_policy ethnl_plca_get_status_policy[ETHTOOL_A_PLCA_HEADER + 1];
extern const struct nla_policy ethnl_mm_get_policy[ETHTOOL_A_MM_HEADER + 1];
extern const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1];
+extern const struct nla_policy ethnl_xdp_features_get_policy[ETHTOOL_A_XDP_FEATURES_HEADER + 1];
int ethnl_set_features(struct sk_buff *skb, struct genl_info *info);
int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info);
@@ -105,6 +105,11 @@ static const struct strset_info info_template[] = {
.count = __ETHTOOL_A_STATS_RMON_CNT,
.strings = stats_rmon_names,
},
+ [ETH_SS_XDP_FEATURES] = {
+ .per_dev = false,
+ .count = ARRAY_SIZE(xdp_features_strings),
+ .strings = xdp_features_strings,
+ },
};
struct strset_req_info {
new file mode 100644
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include "netlink.h"
+#include "common.h"
+#include "bitset.h"
+
+const struct nla_policy ethnl_xdp_features_get_policy[] = {
+ [ETHTOOL_A_XDP_FEATURES_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
+};
+
+struct xdp_feature_req_info {
+ struct ethnl_req_info base;
+};
+
+#define XDP_FEATURES_REPDATA(__reply_base) \
+ container_of(__reply_base, struct xdp_feature_reply_data, base)
+
+struct xdp_feature_reply_data {
+ struct ethnl_reply_data base;
+ u32 features[ETHTOOL_XDP_FEATURES_WORDS];
+};
+
+static int xdp_features_prepare_data(const struct ethnl_req_info *req_base,
+ struct ethnl_reply_data *reply_base,
+ struct genl_info *info)
+{
+ struct xdp_feature_reply_data *data = XDP_FEATURES_REPDATA(reply_base);
+ struct net_device *dev = reply_base->dev;
+
+ BUILD_BUG_ON(ETHTOOL_XDP_FEATURES_WORDS != 1);
+ data->features[0] = dev->xdp_features;
+
+ return 0;
+}
+
+static int xdp_features_reply_size(const struct ethnl_req_info *req_base,
+ const struct ethnl_reply_data *reply_base)
+{
+ bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
+ const struct xdp_feature_reply_data *data;
+
+ data = XDP_FEATURES_REPDATA(reply_base);
+ return ethnl_bitset32_size(data->features, NULL, __NETDEV_XDP_ACT_BIT_MAX,
+ xdp_features_strings, compact);
+}
+
+static int xdp_features_fill_reply(struct sk_buff *skb,
+ const struct ethnl_req_info *req_base,
+ const struct ethnl_reply_data *reply_base)
+{
+ bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
+ const struct xdp_feature_reply_data *data;
+
+ data = XDP_FEATURES_REPDATA(reply_base);
+ return ethnl_put_bitset32(skb, ETHTOOL_A_XDP_FEATURES_DATA,
+ data->features, NULL, __NETDEV_XDP_ACT_BIT_MAX,
+ xdp_features_strings, compact);
+}
+
+const struct ethnl_request_ops ethnl_xdp_request_ops = {
+ .request_cmd = ETHTOOL_MSG_XDP_FEATURES_GET,
+ .reply_cmd = ETHTOOL_MSG_XDP_FEATURES_GET_REPLY,
+ .hdr_attr = ETHTOOL_A_XDP_FEATURES_HEADER,
+ .req_info_size = sizeof(struct xdp_feature_req_info),
+ .reply_data_size = sizeof(struct xdp_feature_reply_data),
+ .prepare_data = xdp_features_prepare_data,
+ .reply_size = xdp_features_reply_size,
+ .fill_reply = xdp_features_fill_reply,
+};
@@ -37,6 +37,19 @@ enum netdev_xdp_act {
NETDEV_XDP_ACT_MASK = 127,
};
+enum netdev_xdp_act_bit {
+ NETDEV_XDP_ACT_BIT_BASIC_BIT,
+ NETDEV_XDP_ACT_BIT_REDIRECT_BIT,
+ NETDEV_XDP_ACT_BIT_NDO_XMIT_BIT,
+ NETDEV_XDP_ACT_BIT_XSK_ZEROCOPY_BIT,
+ NETDEV_XDP_ACT_BIT_HW_OFFLOAD_BIT,
+ NETDEV_XDP_ACT_BIT_RX_SG_BIT,
+ NETDEV_XDP_ACT_BIT_NDO_XMIT_SG_BIT,
+
+ __NETDEV_XDP_ACT_BIT_MAX,
+ NETDEV_XDP_ACT_BIT_MAX = (__NETDEV_XDP_ACT_BIT_MAX - 1)
+};
+
enum {
NETDEV_A_DEV_IFINDEX = 1,
NETDEV_A_DEV_PAD,