Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ethtool: provide netdev features with FEATURES_GET request

Implement FEATURES_GET request to get network device features. These are
traditionally available via ETHTOOL_GFEATURES ioctl request.

v2:
- style cleanup suggested by Jakub Kicinski

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
Reviewed-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Michal Kubecek and committed by
David S. Miller
0524399d f70bb065

+202 -12
+42 -9
Documentation/networking/ethtool-netlink.rst
··· 189 189 ``ETHTOOL_MSG_DEBUG_SET`` set debugging settings 190 190 ``ETHTOOL_MSG_WOL_GET`` get wake-on-lan settings 191 191 ``ETHTOOL_MSG_WOL_SET`` set wake-on-lan settings 192 + ``ETHTOOL_MSG_FEATURES_GET`` get device features 192 193 ===================================== ================================ 193 194 194 195 Kernel to userspace: ··· 205 204 ``ETHTOOL_MSG_DEBUG_NTF`` debugging settings notification 206 205 ``ETHTOOL_MSG_WOL_GET_REPLY`` wake-on-lan settings 207 206 ``ETHTOOL_MSG_WOL_NTF`` wake-on-lan settings notification 207 + ``ETHTOOL_MSG_FEATURES_GET_REPLY`` device features 208 208 ===================================== ================================= 209 209 210 210 ``GET`` requests are sent by userspace applications to retrieve device ··· 523 521 ``WAKE_MAGICSECURE`` mode. 524 522 525 523 524 + FEATURES_GET 525 + ============ 526 + 527 + Gets netdev features like ``ETHTOOL_GFEATURES`` ioctl request. 528 + 529 + Request contents: 530 + 531 + ==================================== ====== ========================== 532 + ``ETHTOOL_A_FEATURES_HEADER`` nested request header 533 + ==================================== ====== ========================== 534 + 535 + Kernel response contents: 536 + 537 + ==================================== ====== ========================== 538 + ``ETHTOOL_A_FEATURES_HEADER`` nested reply header 539 + ``ETHTOOL_A_FEATURES_HW`` bitset dev->hw_features 540 + ``ETHTOOL_A_FEATURES_WANTED`` bitset dev->wanted_features 541 + ``ETHTOOL_A_FEATURES_ACTIVE`` bitset dev->features 542 + ``ETHTOOL_A_FEATURES_NOCHANGE`` bitset NETIF_F_NEVER_CHANGE 543 + ==================================== ====== ========================== 544 + 545 + Bitmaps in kernel response have the same meaning as bitmaps used in ioctl 546 + interference but attribute names are different (they are based on 547 + corresponding members of struct net_device). Legacy "flags" are not provided, 548 + if userspace needs them (most likely only ethtool for backward compatibility), 549 + it can calculate their values from related feature bits itself. 550 + ETHA_FEATURES_HW uses mask consisting of all features recognized by kernel (to 551 + provide all names when using verbose bitmap format), the other three use no 552 + mask (simple bit lists). 553 + 554 + 526 555 Request translation 527 556 =================== 528 557 ··· 584 551 ``ETHTOOL_SRINGPARAM`` n/a 585 552 ``ETHTOOL_GPAUSEPARAM`` n/a 586 553 ``ETHTOOL_SPAUSEPARAM`` n/a 587 - ``ETHTOOL_GRXCSUM`` n/a 554 + ``ETHTOOL_GRXCSUM`` ``ETHTOOL_MSG_FEATURES_GET`` 588 555 ``ETHTOOL_SRXCSUM`` n/a 589 - ``ETHTOOL_GTXCSUM`` n/a 556 + ``ETHTOOL_GTXCSUM`` ``ETHTOOL_MSG_FEATURES_GET`` 590 557 ``ETHTOOL_STXCSUM`` n/a 591 - ``ETHTOOL_GSG`` n/a 558 + ``ETHTOOL_GSG`` ``ETHTOOL_MSG_FEATURES_GET`` 592 559 ``ETHTOOL_SSG`` n/a 593 560 ``ETHTOOL_TEST`` n/a 594 561 ``ETHTOOL_GSTRINGS`` ``ETHTOOL_MSG_STRSET_GET`` 595 562 ``ETHTOOL_PHYS_ID`` n/a 596 563 ``ETHTOOL_GSTATS`` n/a 597 - ``ETHTOOL_GTSO`` n/a 564 + ``ETHTOOL_GTSO`` ``ETHTOOL_MSG_FEATURES_GET`` 598 565 ``ETHTOOL_STSO`` n/a 599 566 ``ETHTOOL_GPERMADDR`` rtnetlink ``RTM_GETLINK`` 600 - ``ETHTOOL_GUFO`` n/a 567 + ``ETHTOOL_GUFO`` ``ETHTOOL_MSG_FEATURES_GET`` 601 568 ``ETHTOOL_SUFO`` n/a 602 - ``ETHTOOL_GGSO`` n/a 569 + ``ETHTOOL_GGSO`` ``ETHTOOL_MSG_FEATURES_GET`` 603 570 ``ETHTOOL_SGSO`` n/a 604 - ``ETHTOOL_GFLAGS`` n/a 571 + ``ETHTOOL_GFLAGS`` ``ETHTOOL_MSG_FEATURES_GET`` 605 572 ``ETHTOOL_SFLAGS`` n/a 606 573 ``ETHTOOL_GPFLAGS`` n/a 607 574 ``ETHTOOL_SPFLAGS`` n/a 608 575 ``ETHTOOL_GRXFH`` n/a 609 576 ``ETHTOOL_SRXFH`` n/a 610 - ``ETHTOOL_GGRO`` n/a 577 + ``ETHTOOL_GGRO`` ``ETHTOOL_MSG_FEATURES_GET`` 611 578 ``ETHTOOL_SGRO`` n/a 612 579 ``ETHTOOL_GRXRINGS`` n/a 613 580 ``ETHTOOL_GRXCLSRLCNT`` n/a ··· 622 589 ``ETHTOOL_GSSET_INFO`` ``ETHTOOL_MSG_STRSET_GET`` 623 590 ``ETHTOOL_GRXFHINDIR`` n/a 624 591 ``ETHTOOL_SRXFHINDIR`` n/a 625 - ``ETHTOOL_GFEATURES`` n/a 592 + ``ETHTOOL_GFEATURES`` ``ETHTOOL_MSG_FEATURES_GET`` 626 593 ``ETHTOOL_SFEATURES`` n/a 627 594 ``ETHTOOL_GCHANNELS`` n/a 628 595 ``ETHTOOL_SCHANNELS`` n/a
+17
include/uapi/linux/ethtool_netlink.h
··· 24 24 ETHTOOL_MSG_DEBUG_SET, 25 25 ETHTOOL_MSG_WOL_GET, 26 26 ETHTOOL_MSG_WOL_SET, 27 + ETHTOOL_MSG_FEATURES_GET, 27 28 28 29 /* add new constants above here */ 29 30 __ETHTOOL_MSG_USER_CNT, ··· 44 43 ETHTOOL_MSG_DEBUG_NTF, 45 44 ETHTOOL_MSG_WOL_GET_REPLY, 46 45 ETHTOOL_MSG_WOL_NTF, 46 + ETHTOOL_MSG_FEATURES_GET_REPLY, 47 47 48 48 /* add new constants above here */ 49 49 __ETHTOOL_MSG_KERNEL_CNT, ··· 228 226 /* add new constants above here */ 229 227 __ETHTOOL_A_WOL_CNT, 230 228 ETHTOOL_A_WOL_MAX = __ETHTOOL_A_WOL_CNT - 1 229 + }; 230 + 231 + /* FEATURES */ 232 + 233 + enum { 234 + ETHTOOL_A_FEATURES_UNSPEC, 235 + ETHTOOL_A_FEATURES_HEADER, /* nest - _A_HEADER_* */ 236 + ETHTOOL_A_FEATURES_HW, /* bitset */ 237 + ETHTOOL_A_FEATURES_WANTED, /* bitset */ 238 + ETHTOOL_A_FEATURES_ACTIVE, /* bitset */ 239 + ETHTOOL_A_FEATURES_NOCHANGE, /* bitset */ 240 + 241 + /* add new constants above here */ 242 + __ETHTOOL_A_FEATURES_CNT, 243 + ETHTOOL_A_FEATURES_MAX = __ETHTOOL_A_FEATURES_CNT - 1 231 244 }; 232 245 233 246 /* generic netlink info */
+1 -1
net/ethtool/Makefile
··· 5 5 obj-$(CONFIG_ETHTOOL_NETLINK) += ethtool_nl.o 6 6 7 7 ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o \ 8 - linkstate.o debug.o wol.o 8 + linkstate.o debug.o wol.o features.o
+2
net/ethtool/common.h
··· 6 6 #include <linux/netdevice.h> 7 7 #include <linux/ethtool.h> 8 8 9 + #define ETHTOOL_DEV_FEATURE_WORDS DIV_ROUND_UP(NETDEV_FEATURE_COUNT, 32) 10 + 9 11 /* compose link mode index from speed, type and duplex */ 10 12 #define ETHTOOL_LINK_MODE(speed, type, duplex) \ 11 13 ETHTOOL_LINK_MODE_ ## speed ## base ## type ## _ ## duplex ## _BIT
+131
net/ethtool/features.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include "netlink.h" 4 + #include "common.h" 5 + #include "bitset.h" 6 + 7 + struct features_req_info { 8 + struct ethnl_req_info base; 9 + }; 10 + 11 + struct features_reply_data { 12 + struct ethnl_reply_data base; 13 + u32 hw[ETHTOOL_DEV_FEATURE_WORDS]; 14 + u32 wanted[ETHTOOL_DEV_FEATURE_WORDS]; 15 + u32 active[ETHTOOL_DEV_FEATURE_WORDS]; 16 + u32 nochange[ETHTOOL_DEV_FEATURE_WORDS]; 17 + u32 all[ETHTOOL_DEV_FEATURE_WORDS]; 18 + }; 19 + 20 + #define FEATURES_REPDATA(__reply_base) \ 21 + container_of(__reply_base, struct features_reply_data, base) 22 + 23 + static const struct nla_policy 24 + features_get_policy[ETHTOOL_A_FEATURES_MAX + 1] = { 25 + [ETHTOOL_A_FEATURES_UNSPEC] = { .type = NLA_REJECT }, 26 + [ETHTOOL_A_FEATURES_HEADER] = { .type = NLA_NESTED }, 27 + [ETHTOOL_A_FEATURES_HW] = { .type = NLA_REJECT }, 28 + [ETHTOOL_A_FEATURES_WANTED] = { .type = NLA_REJECT }, 29 + [ETHTOOL_A_FEATURES_ACTIVE] = { .type = NLA_REJECT }, 30 + [ETHTOOL_A_FEATURES_NOCHANGE] = { .type = NLA_REJECT }, 31 + }; 32 + 33 + static void ethnl_features_to_bitmap32(u32 *dest, netdev_features_t src) 34 + { 35 + unsigned int i; 36 + 37 + for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; i++) 38 + dest[i] = src >> (32 * i); 39 + } 40 + 41 + static int features_prepare_data(const struct ethnl_req_info *req_base, 42 + struct ethnl_reply_data *reply_base, 43 + struct genl_info *info) 44 + { 45 + struct features_reply_data *data = FEATURES_REPDATA(reply_base); 46 + struct net_device *dev = reply_base->dev; 47 + netdev_features_t all_features; 48 + 49 + ethnl_features_to_bitmap32(data->hw, dev->hw_features); 50 + ethnl_features_to_bitmap32(data->wanted, dev->wanted_features); 51 + ethnl_features_to_bitmap32(data->active, dev->features); 52 + ethnl_features_to_bitmap32(data->nochange, NETIF_F_NEVER_CHANGE); 53 + all_features = GENMASK_ULL(NETDEV_FEATURE_COUNT - 1, 0); 54 + ethnl_features_to_bitmap32(data->all, all_features); 55 + 56 + return 0; 57 + } 58 + 59 + static int features_reply_size(const struct ethnl_req_info *req_base, 60 + const struct ethnl_reply_data *reply_base) 61 + { 62 + const struct features_reply_data *data = FEATURES_REPDATA(reply_base); 63 + bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS; 64 + unsigned int len = 0; 65 + int ret; 66 + 67 + ret = ethnl_bitset32_size(data->hw, data->all, NETDEV_FEATURE_COUNT, 68 + netdev_features_strings, compact); 69 + if (ret < 0) 70 + return ret; 71 + len += ret; 72 + ret = ethnl_bitset32_size(data->wanted, NULL, NETDEV_FEATURE_COUNT, 73 + netdev_features_strings, compact); 74 + if (ret < 0) 75 + return ret; 76 + len += ret; 77 + ret = ethnl_bitset32_size(data->active, NULL, NETDEV_FEATURE_COUNT, 78 + netdev_features_strings, compact); 79 + if (ret < 0) 80 + return ret; 81 + len += ret; 82 + ret = ethnl_bitset32_size(data->nochange, NULL, NETDEV_FEATURE_COUNT, 83 + netdev_features_strings, compact); 84 + if (ret < 0) 85 + return ret; 86 + len += ret; 87 + 88 + return len; 89 + } 90 + 91 + static int features_fill_reply(struct sk_buff *skb, 92 + const struct ethnl_req_info *req_base, 93 + const struct ethnl_reply_data *reply_base) 94 + { 95 + const struct features_reply_data *data = FEATURES_REPDATA(reply_base); 96 + bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS; 97 + int ret; 98 + 99 + ret = ethnl_put_bitset32(skb, ETHTOOL_A_FEATURES_HW, data->hw, 100 + data->all, NETDEV_FEATURE_COUNT, 101 + netdev_features_strings, compact); 102 + if (ret < 0) 103 + return ret; 104 + ret = ethnl_put_bitset32(skb, ETHTOOL_A_FEATURES_WANTED, data->wanted, 105 + NULL, NETDEV_FEATURE_COUNT, 106 + netdev_features_strings, compact); 107 + if (ret < 0) 108 + return ret; 109 + ret = ethnl_put_bitset32(skb, ETHTOOL_A_FEATURES_ACTIVE, data->active, 110 + NULL, NETDEV_FEATURE_COUNT, 111 + netdev_features_strings, compact); 112 + if (ret < 0) 113 + return ret; 114 + return ethnl_put_bitset32(skb, ETHTOOL_A_FEATURES_NOCHANGE, 115 + data->nochange, NULL, NETDEV_FEATURE_COUNT, 116 + netdev_features_strings, compact); 117 + } 118 + 119 + const struct ethnl_request_ops ethnl_features_request_ops = { 120 + .request_cmd = ETHTOOL_MSG_FEATURES_GET, 121 + .reply_cmd = ETHTOOL_MSG_FEATURES_GET_REPLY, 122 + .hdr_attr = ETHTOOL_A_FEATURES_HEADER, 123 + .max_attr = ETHTOOL_A_FEATURES_MAX, 124 + .req_info_size = sizeof(struct features_req_info), 125 + .reply_data_size = sizeof(struct features_reply_data), 126 + .request_policy = features_get_policy, 127 + 128 + .prepare_data = features_prepare_data, 129 + .reply_size = features_reply_size, 130 + .fill_reply = features_fill_reply, 131 + };
-2
net/ethtool/ioctl.c
··· 56 56 57 57 /* Handlers for each ethtool command */ 58 58 59 - #define ETHTOOL_DEV_FEATURE_WORDS ((NETDEV_FEATURE_COUNT + 31) / 32) 60 - 61 59 static int ethtool_get_features(struct net_device *dev, void __user *useraddr) 62 60 { 63 61 struct ethtool_gfeatures cmd = {
+8
net/ethtool/netlink.c
··· 215 215 [ETHTOOL_MSG_LINKSTATE_GET] = &ethnl_linkstate_request_ops, 216 216 [ETHTOOL_MSG_DEBUG_GET] = &ethnl_debug_request_ops, 217 217 [ETHTOOL_MSG_WOL_GET] = &ethnl_wol_request_ops, 218 + [ETHTOOL_MSG_FEATURES_GET] = &ethnl_features_request_ops, 218 219 }; 219 220 220 221 static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) ··· 695 694 .cmd = ETHTOOL_MSG_WOL_SET, 696 695 .flags = GENL_UNS_ADMIN_PERM, 697 696 .doit = ethnl_set_wol, 697 + }, 698 + { 699 + .cmd = ETHTOOL_MSG_FEATURES_GET, 700 + .doit = ethnl_default_doit, 701 + .start = ethnl_default_start, 702 + .dumpit = ethnl_default_dumpit, 703 + .done = ethnl_default_done, 698 704 }, 699 705 }; 700 706
+1
net/ethtool/netlink.h
··· 337 337 extern const struct ethnl_request_ops ethnl_linkstate_request_ops; 338 338 extern const struct ethnl_request_ops ethnl_debug_request_ops; 339 339 extern const struct ethnl_request_ops ethnl_wol_request_ops; 340 + extern const struct ethnl_request_ops ethnl_features_request_ops; 340 341 341 342 int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info); 342 343 int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info);