Received: by 2002:ac0:946b:0:0:0:0:0 with SMTP id j40csp2742302imj; Mon, 18 Feb 2019 11:18:54 -0800 (PST) X-Google-Smtp-Source: AHgI3IbOzvpqbp6JkWE9s1CYK3z7eejVHflRRHwvg9Ba2Y8Img8wc+lQ1dMb2Eb9RU0h/nwSnuk5 X-Received: by 2002:a63:4f61:: with SMTP id p33mr6909599pgl.303.1550517534588; Mon, 18 Feb 2019 11:18:54 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1550517534; cv=none; d=google.com; s=arc-20160816; b=BBm5zTgg218EVRNwr2cN2QXIjJzftKFmke1eEqskIakjQ8dz6L8FSMZsEKlOgmbWQo x6L4pWKtyMIbW4zP+qBxkz810UwApDxcHWuNxs2Ka/BK6F5tVHrkEYdcOpzQ9JNHJE1w puZO2ZQTPhQrMDCesT4t0wZlixrfi4YeIzEqyrbvfYP8G1RIrKqX8lUSDtBCu5Fo6Ovy Tcj1BtgBLx5jZW83F62hXH52XH2yKujiY5CEZDKikOvxhgWPwIJ3YnyIYpZ4UcHY4YLL lifnoiqRS2TcOBiiYvFf/W80x/Dr8WRTkKRHrFDTzn7TRHqxcPud10OgJCYDcYxDBESJ fnZw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:date:cc:to:subject:from:references :in-reply-to:message-id; bh=Tbnt0Qcukm6OeFOg8JIUyDRcxxKgnmbleieyL2+aF6w=; b=hBY2P8vvo2H/NQUXKiFgLL5XR24WWb08P+1TEEWN8OwJ3eyD9RiyeNTeH0HrgDRgt0 B6iSPe1iSF2b7/MtAHydmwLG9+DUA518/JygXxu6zIkHEfB1rSGQfb0OXy8renZb1jJ8 ja7CPlKPSaJsivXRZ0/Mo5XYp2L2Vx9mhah81817fH2OMdJOZIj5eGU/uLjD1yGjW7yf XMNuIbCZldEcA+11PrApJTqls8coyDAJNkv2L4bpVzhOrWTlkvdPo3AlkUG52/Ha82S7 3CEkFQqCooFdpRHWdd72J0MgL/04NHVB8P5IOtC8ugusKA9CxJ+IpRlNaUxzu6iQ6jen XZjw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id w24si2820345ply.32.2019.02.18.11.18.39; Mon, 18 Feb 2019 11:18:54 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404018AbfBRSXK (ORCPT + 99 others); Mon, 18 Feb 2019 13:23:10 -0500 Received: from mx2.suse.de ([195.135.220.15]:47082 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2392500AbfBRSXI (ORCPT ); Mon, 18 Feb 2019 13:23:08 -0500 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 64B88AEBB; Mon, 18 Feb 2019 18:23:05 +0000 (UTC) Received: by unicorn.suse.cz (Postfix, from userid 1000) id 150ACE0122; Mon, 18 Feb 2019 19:23:05 +0100 (CET) Message-Id: In-Reply-To: References: From: Michal Kubecek Subject: [RFC PATCH net-next v3 20/21] ethtool: provide private flags in GET_SETTINGS request To: netdev@vger.kernel.org Cc: David Miller , Andrew Lunn , Jakub Kicinski , Jiri Pirko , linux-kernel@vger.kernel.org Date: Mon, 18 Feb 2019 19:23:05 +0100 (CET) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add information about device private flags (as provided by ETHTOOL_GPFLAGS ioctl command) in GET_SETTINGS reply when ETH_SETTINGS_IM_PRIVFLAGS flag is set in the request. Signed-off-by: Michal Kubecek --- Documentation/networking/ethtool-netlink.txt | 9 +- include/uapi/linux/ethtool_netlink.h | 4 +- net/ethtool/settings.c | 98 ++++++++++++++++++++ 3 files changed, 109 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt index 664c922a05eb..290008aaed0a 100644 --- a/Documentation/networking/ethtool-netlink.txt +++ b/Documentation/networking/ethtool-netlink.txt @@ -287,6 +287,7 @@ Info mask bits meaning: ETH_SETTINGS_IM_MSGLEVEL msglevel ETH_SETTINGS_IM_LINK link state ETH_SETTINGS_IM_FEATURES features + ETH_SETTINGS_IM_PRIVFLAGS device private flags Response contents: @@ -312,6 +313,7 @@ Response contents: ETHA_FEATURES_WANTED (bitset) dev->wanted_features ETHA_FEATURES_ACTIVE (bitset) dev->features ETHA_FEATURES_NOCHANGE (bitset) NETIF_F_NEVER_CHANGE + ETHA_SETTINGS_PRIV_FLAGS (bitset) device private flags Most of the attributes and their values have the same meaning as matching members of the corresponding ioctl structures. For ETHA_SETTINGS_LINK_MODES, @@ -333,6 +335,11 @@ itself. ETHA_FEATURES_HW uses mask consisting of all features recognized by kernel (to provide all names when using verbose bitmap format), remaining three use mask equal to value (to save space). +ETHA_SETTINGS_PRIV_FLAGS is a bitset with values of device private flags. +These flags are defined by driver, their number and names (as well as meaning) +are device dependent. For compact bitset format, names can be retrieved as +ETH_SS_PRIV_FLAGS string set. + GET_SETTINGS request is allowed for unprivileged user but ETHA_SETTINGS_SOPASS is only provided by kernel in response to privileged (netns CAP_NET_ADMIN) requests. @@ -389,7 +396,7 @@ ETHTOOL_GGSO ETHNL_CMD_GET_SETTINGS ETHTOOL_SGSO n/a ETHTOOL_GFLAGS ETHNL_CMD_GET_SETTINGS ETHTOOL_SFLAGS n/a -ETHTOOL_GPFLAGS n/a +ETHTOOL_GPFLAGS ETHNL_CMD_GET_SETTINGS ETHTOOL_SPFLAGS n/a ETHTOOL_GRXFH n/a ETHTOOL_SRXFH n/a diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h index 154d7e6a59dd..afd61d36bcf8 100644 --- a/include/uapi/linux/ethtool_netlink.h +++ b/include/uapi/linux/ethtool_netlink.h @@ -205,6 +205,7 @@ enum { ETHA_SETTINGS_MSGLEVEL, /* bitfield32 */ ETHA_SETTINGS_LINK, /* u8 */ ETHA_SETTINGS_FEATURES, /* nest - ETHA_FEATURES_* */ + ETHA_SETTINGS_PRIV_FLAGS, /* nest - ETHA_BITSET_* */ __ETHA_SETTINGS_CNT, ETHA_SETTINGS_MAX = (__ETHA_SETTINGS_CNT - 1) @@ -216,8 +217,9 @@ enum { #define ETH_SETTINGS_IM_MSGLEVEL 0x08 #define ETH_SETTINGS_IM_LINK 0x10 #define ETH_SETTINGS_IM_FEATURES 0x20 +#define ETH_SETTINGS_IM_PRIVFLAGS 0x40 -#define ETH_SETTINGS_IM_ALL 0x3f +#define ETH_SETTINGS_IM_ALL 0x7f enum { ETHA_FEATURES_UNSPEC, diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c index 32ee273de879..7f72f4250306 100644 --- a/net/ethtool/settings.c +++ b/net/ethtool/settings.c @@ -22,6 +22,9 @@ struct settings_data { u32 active[ETHTOOL_DEV_FEATURE_WORDS]; u32 nochange[ETHTOOL_DEV_FEATURE_WORDS]; } features; + char (*priv_flag_names)[ETH_GSTRING_LEN]; + u32 priv_flags; + unsigned int n_priv_flags; }; static const struct nla_policy get_settings_policy[ETHA_SETTINGS_MAX + 1] = { @@ -36,6 +39,7 @@ static const struct nla_policy get_settings_policy[ETHA_SETTINGS_MAX + 1] = { [ETHA_SETTINGS_MSGLEVEL] = { .type = NLA_REJECT }, [ETHA_SETTINGS_LINK] = { .type = NLA_REJECT }, [ETHA_SETTINGS_FEATURES] = { .type = NLA_REJECT }, + [ETHA_SETTINGS_PRIV_FLAGS] = { .type = NLA_REJECT }, }; static int parse_settings(struct common_req_info *req_info, @@ -114,6 +118,58 @@ static int ethnl_get_features(struct net_device *dev, return 0; } +static int get_priv_flags_info(struct net_device *dev, unsigned int *count, + void **names) +{ + const struct ethtool_ops *ops = dev->ethtool_ops; + int nflags; + + if (!ops->get_priv_flags || !ops->get_sset_count || !ops->get_strings) + return -EOPNOTSUPP; + nflags = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS); + if (nflags < 0) + return nflags; + + if (names) { + *names = kcalloc(nflags, ETH_GSTRING_LEN, GFP_KERNEL); + if (!*names) + return -ENOMEM; + ops->get_strings(dev, ETH_SS_PRIV_FLAGS, *names); + } + + /* We can easily pass more than 32 private flags to userspace via + * netlink but we cannot get more with ethtool_ops::get_priv_flags(). + * Note that we must not adjust nflags before allocating the space + * for flag names as the buffer must be large enough for all flags. + */ + if (WARN_ONCE(nflags > 32, + "device %s reports more than 32 private flags (%d)\n", + netdev_name(dev), nflags)) + nflags = 32; + + *count = nflags; + return 0; +} + +static int ethnl_get_priv_flags(struct genl_info *info, + struct settings_data *data) +{ + struct net_device *dev = data->repdata_base.dev; + const struct ethtool_ops *ops = dev->ethtool_ops; + unsigned int nflags; + void *names; + int ret; + + ret = get_priv_flags_info(dev, &nflags, &names); + if (ret < 0) + return ret; + + data->priv_flags = ops->get_priv_flags(dev); + data->priv_flag_names = names; + data->n_priv_flags = nflags; + return 0; +} + static int prepare_settings(struct common_req_info *req_info, struct genl_info *info) { @@ -163,6 +219,11 @@ static int prepare_settings(struct common_req_info *req_info, data->link = __ethtool_get_link(dev); if (req_mask & ETH_SETTINGS_IM_FEATURES) ethnl_get_features(dev, data); + if (req_mask & ETH_SETTINGS_IM_PRIVFLAGS) { + ret = ethnl_get_priv_flags(info, data); + if (ret < 0) + req_mask &= ~ETH_SETTINGS_IM_PRIVFLAGS; + } ethnl_after_ops(dev); data->repdata_base.info_mask = req_mask; @@ -281,6 +342,17 @@ static int settings_size(const struct common_req_info *req_info) return ret; len += ret; } + if (info_mask & ETH_SETTINGS_IM_PRIVFLAGS) { + const unsigned int flags = + (compact ? ETHNL_BITSET_COMPACT : 0) | + ETHNL_BITSET_LEGACY_NAMES; + + ret = ethnl_bitset32_size(data->n_priv_flags, &data->priv_flags, + NULL, data->priv_flag_names, flags); + if (ret < 0) + return ret; + len += ret; + } return len; } @@ -404,6 +476,18 @@ static int fill_features(struct sk_buff *skb, const struct settings_data *data) return 0; } +static int fill_priv_flags(struct sk_buff *skb, + const struct settings_data *data) +{ + const unsigned int bitset_flags = + (data->reqinfo_base.compact ? ETHNL_BITSET_COMPACT : 0) | + ETHNL_BITSET_LEGACY_NAMES; + + return ethnl_put_bitset32(skb, ETHA_SETTINGS_PRIV_FLAGS, + data->n_priv_flags, &data->priv_flags, NULL, + data->priv_flag_names, bitset_flags); +} + static int fill_settings(struct sk_buff *skb, const struct common_req_info *req_info) { @@ -443,10 +527,23 @@ static int fill_settings(struct sk_buff *skb, if (ret < 0) return ret; } + if (info_mask & ETH_SETTINGS_IM_PRIVFLAGS) { + ret = fill_priv_flags(skb, data); + if (ret < 0) + return ret; + } return 0; } +static void settings_cleanup(struct common_req_info *req_info) +{ + const struct settings_data *data = + container_of(req_info, struct settings_data, reqinfo_base); + + kfree(data->priv_flag_names); +} + const struct get_request_ops settings_request_ops = { .request_cmd = ETHNL_CMD_GET_SETTINGS, .reply_cmd = ETHNL_CMD_SET_SETTINGS, @@ -458,4 +555,5 @@ const struct get_request_ops settings_request_ops = { .prepare_data = prepare_settings, .reply_size = settings_size, .fill_reply = fill_settings, + .cleanup = settings_cleanup, }; -- 2.20.1