Commit 82a9822b authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'ethtool-netlink-interface-part-3'



Michal Kubecek says:

====================
ethtool netlink interface, part 3

Implementation of more netlink request types:

  - netdev features (ethtool -k/-K, patches 3-6)
  - private flags (--show-priv-flags / --set-priv-flags, patches 7-9)
  - ring sizes (ethtool -g/-G, patches 10-12)
  - channel counts (ethtool -l/-L, patches 13-15)

Patch 1 is a style cleanup suggested in part 2 review and patch 2 updates
the mapping between netdev features and legacy ioctl requests (which are
still used by ethtool for backward compatibility).

Changes in v2:
  - fix netdev reference leaks in error path of ethnl_set_rings() and
    ethnl_set_channels() (found by Jakub Kicinski)
  - use __set_bit() rather than set_bit() (suggested by David Miller)
  - in replies to RINGS_GET and CHANNELS_GET requests, omit ring and
    channel types not supported by driver/device (suggested by Jakub
    Kicinski)
  - more descriptive message size calculations in rings_reply_size() and
    channels_reply_size() (suggested by Jakub Kicinski)
  - coding style cleanup (suggested by Jakub Kicinski)
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f8ab3047 546379b9
Loading
Loading
Loading
Loading
+248 −24
Original line number Diff line number Diff line
@@ -189,6 +189,14 @@ Userspace to kernel:
  ``ETHTOOL_MSG_DEBUG_SET``             set debugging settings
  ``ETHTOOL_MSG_WOL_GET``               get wake-on-lan settings
  ``ETHTOOL_MSG_WOL_SET``               set wake-on-lan settings
  ``ETHTOOL_MSG_FEATURES_GET``          get device features
  ``ETHTOOL_MSG_FEATURES_SET``          set device features
  ``ETHTOOL_MSG_PRIVFLAGS_GET``         get private flags
  ``ETHTOOL_MSG_PRIVFLAGS_SET``         set private flags
  ``ETHTOOL_MSG_RINGS_GET``             get ring sizes
  ``ETHTOOL_MSG_RINGS_SET``             set ring sizes
  ``ETHTOOL_MSG_CHANNELS_GET``          get channel counts
  ``ETHTOOL_MSG_CHANNELS_SET``          set channel counts
  ===================================== ================================

Kernel to userspace:
@@ -204,6 +212,15 @@ Kernel to userspace:
  ``ETHTOOL_MSG_DEBUG_NTF``             debugging settings notification
  ``ETHTOOL_MSG_WOL_GET_REPLY``         wake-on-lan settings
  ``ETHTOOL_MSG_WOL_NTF``               wake-on-lan settings notification
  ``ETHTOOL_MSG_FEATURES_GET_REPLY``    device features
  ``ETHTOOL_MSG_FEATURES_SET_REPLY``    optional reply to FEATURES_SET
  ``ETHTOOL_MSG_FEATURES_NTF``          netdev features notification
  ``ETHTOOL_MSG_PRIVFLAGS_GET_REPLY``   private flags
  ``ETHTOOL_MSG_PRIVFLAGS_NTF``         private flags
  ``ETHTOOL_MSG_RINGS_GET_REPLY``       ring sizes
  ``ETHTOOL_MSG_RINGS_NTF``             ring sizes
  ``ETHTOOL_MSG_CHANNELS_GET_REPLY``    channel counts
  ``ETHTOOL_MSG_CHANNELS_NTF``          channel counts
  ===================================== =================================

``GET`` requests are sent by userspace applications to retrieve device
@@ -521,6 +538,213 @@ Request contents:
``WAKE_MAGICSECURE`` mode.


FEATURES_GET
============

Gets netdev features like ``ETHTOOL_GFEATURES`` ioctl request.

Request contents:

  ====================================  ======  ==========================
  ``ETHTOOL_A_FEATURES_HEADER``         nested  request header
  ====================================  ======  ==========================

Kernel response contents:

  ====================================  ======  ==========================
  ``ETHTOOL_A_FEATURES_HEADER``         nested  reply header
  ``ETHTOOL_A_FEATURES_HW``             bitset  dev->hw_features
  ``ETHTOOL_A_FEATURES_WANTED``         bitset  dev->wanted_features
  ``ETHTOOL_A_FEATURES_ACTIVE``         bitset  dev->features
  ``ETHTOOL_A_FEATURES_NOCHANGE``       bitset  NETIF_F_NEVER_CHANGE
  ====================================  ======  ==========================

Bitmaps in kernel response have the same meaning as bitmaps used in ioctl
interference but attribute names are different (they are based on
corresponding members of struct net_device). Legacy "flags" are not provided,
if userspace needs them (most likely only ethtool for backward compatibility),
it can calculate their values from related feature bits itself.
ETHA_FEATURES_HW uses mask consisting of all features recognized by kernel (to
provide all names when using verbose bitmap format), the other three use no
mask (simple bit lists).


FEATURES_SET
============

Request to set netdev features like ``ETHTOOL_SFEATURES`` ioctl request.

Request contents:

  ====================================  ======  ==========================
  ``ETHTOOL_A_FEATURES_HEADER``         nested  request header
  ``ETHTOOL_A_FEATURES_WANTED``         bitset  requested features
  ====================================  ======  ==========================

Kernel response contents:

  ====================================  ======  ==========================
  ``ETHTOOL_A_FEATURES_HEADER``         nested  reply header
  ``ETHTOOL_A_FEATURES_WANTED``         bitset  diff wanted vs. result
  ``ETHTOOL_A_FEATURES_ACTIVE``         bitset  diff old vs. new active
  ====================================  ======  ==========================

Request constains only one bitset which can be either value/mask pair (request
to change specific feature bits and leave the rest) or only a value (request
to set all features to specified set).

As request is subject to netdev_change_features() sanity checks, optional
kernel reply (can be suppressed by ``ETHTOOL_FLAG_OMIT_REPLY`` flag in request
header) informs client about the actual result. ``ETHTOOL_A_FEATURES_WANTED``
reports the difference between client request and actual result: mask consists
of bits which differ between requested features and result (dev->features
after the operation), value consists of values of these bits in the request
(i.e. negated values from resulting features). ``ETHTOOL_A_FEATURES_ACTIVE``
reports the difference between old and new dev->features: mask consists of
bits which have changed, values are their values in new dev->features (after
the operation).

``ETHTOOL_MSG_FEATURES_NTF`` notification is sent not only if device features
are modified using ``ETHTOOL_MSG_FEATURES_SET`` request or on of ethtool ioctl
request but also each time features are modified with netdev_update_features()
or netdev_change_features().


PRIVFLAGS_GET
=============

Gets private flags like ``ETHTOOL_GPFLAGS`` ioctl request.

Request contents:

  ====================================  ======  ==========================
  ``ETHTOOL_A_PRIVFLAGS_HEADER``        nested  request header
  ====================================  ======  ==========================

Kernel response contents:

  ====================================  ======  ==========================
  ``ETHTOOL_A_PRIVFLAGS_HEADER``        nested  reply header
  ``ETHTOOL_A_PRIVFLAGS_FLAGS``         bitset  private flags
  ====================================  ======  ==========================

``ETHTOOL_A_PRIVFLAGS_FLAGS`` is a bitset with values of device private flags.
These flags are defined by driver, their number and names (and also meaning)
are device dependent. For compact bitset format, names can be retrieved as
``ETH_SS_PRIV_FLAGS`` string set. If verbose bitset format is requested,
response uses all private flags supported by the device as mask so that client
gets the full information without having to fetch the string set with names.


PRIVFLAGS_SET
=============

Sets or modifies values of device private flags like ``ETHTOOL_SPFLAGS``
ioctl request.

Request contents:

  ====================================  ======  ==========================
  ``ETHTOOL_A_PRIVFLAGS_HEADER``        nested  request header
  ``ETHTOOL_A_PRIVFLAGS_FLAGS``         bitset  private flags
  ====================================  ======  ==========================

``ETHTOOL_A_PRIVFLAGS_FLAGS`` can either set the whole set of private flags or
modify only values of some of them.


RINGS_GET
=========

Gets ring sizes like ``ETHTOOL_GRINGPARAM`` ioctl request.

Request contents:

  ====================================  ======  ==========================
  ``ETHTOOL_A_RINGS_HEADER``            nested  request header
  ====================================  ======  ==========================

Kernel response contents:

  ====================================  ======  ==========================
  ``ETHTOOL_A_RINGS_HEADER``            nested  reply header
  ``ETHTOOL_A_RINGS_RX_MAX``            u32     max size of RX ring
  ``ETHTOOL_A_RINGS_RX_MINI_MAX``       u32     max size of RX mini ring
  ``ETHTOOL_A_RINGS_RX_JUMBO_MAX``      u32     max size of RX jumbo ring
  ``ETHTOOL_A_RINGS_TX_MAX``            u32     max size of TX ring
  ``ETHTOOL_A_RINGS_RX``                u32     size of RX ring
  ``ETHTOOL_A_RINGS_RX_MINI``           u32     size of RX mini ring
  ``ETHTOOL_A_RINGS_RX_JUMBO``          u32     size of RX jumbo ring
  ``ETHTOOL_A_RINGS_TX``                u32     size of TX ring
  ====================================  ======  ==========================


RINGS_SET
=========

Sets ring sizes like ``ETHTOOL_SRINGPARAM`` ioctl request.

Request contents:

  ====================================  ======  ==========================
  ``ETHTOOL_A_RINGS_HEADER``            nested  reply header
  ``ETHTOOL_A_RINGS_RX``                u32     size of RX ring
  ``ETHTOOL_A_RINGS_RX_MINI``           u32     size of RX mini ring
  ``ETHTOOL_A_RINGS_RX_JUMBO``          u32     size of RX jumbo ring
  ``ETHTOOL_A_RINGS_TX``                u32     size of TX ring
  ====================================  ======  ==========================

Kernel checks that requested ring sizes do not exceed limits reported by
driver. Driver may impose additional constraints and may not suspport all
attributes.


CHANNELS_GET
============

Gets channel counts like ``ETHTOOL_GCHANNELS`` ioctl request.

Request contents:

  ====================================  ======  ==========================
  ``ETHTOOL_A_CHANNELS_HEADER``         nested  request header
  ====================================  ======  ==========================

Kernel response contents:

  =====================================  ======  ==========================
  ``ETHTOOL_A_CHANNELS_HEADER``          nested  reply header
  ``ETHTOOL_A_CHANNELS_RX_MAX``          u32     max receive channels
  ``ETHTOOL_A_CHANNELS_TX_MAX``          u32     max transmit channels
  ``ETHTOOL_A_CHANNELS_OTHER_MAX``       u32     max other channels
  ``ETHTOOL_A_CHANNELS_COMBINED_MAX``    u32     max combined channels
  ``ETHTOOL_A_CHANNELS_RX_COUNT``        u32     receive channel count
  ``ETHTOOL_A_CHANNELS_TX_COUNT``        u32     transmit channel count
  ``ETHTOOL_A_CHANNELS_OTHER_COUNT``     u32     other channel count
  ``ETHTOOL_A_CHANNELS_COMBINED_COUNT``  u32     combined channel count
  =====================================  ======  ==========================


CHANNELS_SET
============

Sets channel counts like ``ETHTOOL_SCHANNELS`` ioctl request.

Request contents:

  =====================================  ======  ==========================
  ``ETHTOOL_A_CHANNELS_HEADER``          nested  request header
  ``ETHTOOL_A_CHANNELS_RX_COUNT``        u32     receive channel count
  ``ETHTOOL_A_CHANNELS_TX_COUNT``        u32     transmit channel count
  ``ETHTOOL_A_CHANNELS_OTHER_COUNT``     u32     other channel count
  ``ETHTOOL_A_CHANNELS_COMBINED_COUNT``  u32     combined channel count
  =====================================  ======  ==========================

Kernel checks that requested channel counts do not exceed limits reported by
driver. Driver may impose additional constraints and may not suspport all
attributes.


Request translation
===================

@@ -547,35 +771,35 @@ have their netlink replacement yet.
  ``ETHTOOL_SEEPROM``                 n/a
  ``ETHTOOL_GCOALESCE``               n/a
  ``ETHTOOL_SCOALESCE``               n/a
  ``ETHTOOL_GRINGPARAM``              n/a
  ``ETHTOOL_SRINGPARAM``              n/a
  ``ETHTOOL_GRINGPARAM``              ``ETHTOOL_MSG_RINGS_GET``
  ``ETHTOOL_SRINGPARAM``              ``ETHTOOL_MSG_RINGS_SET``
  ``ETHTOOL_GPAUSEPARAM``             n/a
  ``ETHTOOL_SPAUSEPARAM``             n/a
  ``ETHTOOL_GRXCSUM``                 n/a
  ``ETHTOOL_SRXCSUM``                 n/a
  ``ETHTOOL_GTXCSUM``                 n/a
  ``ETHTOOL_STXCSUM``                 n/a
  ``ETHTOOL_GSG``                     n/a
  ``ETHTOOL_SSG``                     n/a
  ``ETHTOOL_GRXCSUM``                 ``ETHTOOL_MSG_FEATURES_GET``
  ``ETHTOOL_SRXCSUM``                 ``ETHTOOL_MSG_FEATURES_SET``
  ``ETHTOOL_GTXCSUM``                 ``ETHTOOL_MSG_FEATURES_GET``
  ``ETHTOOL_STXCSUM``                 ``ETHTOOL_MSG_FEATURES_SET``
  ``ETHTOOL_GSG``                     ``ETHTOOL_MSG_FEATURES_GET``
  ``ETHTOOL_SSG``                     ``ETHTOOL_MSG_FEATURES_SET``
  ``ETHTOOL_TEST``                    n/a
  ``ETHTOOL_GSTRINGS``                ``ETHTOOL_MSG_STRSET_GET``
  ``ETHTOOL_PHYS_ID``                 n/a
  ``ETHTOOL_GSTATS``                  n/a
  ``ETHTOOL_GTSO``                    n/a
  ``ETHTOOL_STSO``                    n/a
  ``ETHTOOL_GTSO``                    ``ETHTOOL_MSG_FEATURES_GET``
  ``ETHTOOL_STSO``                    ``ETHTOOL_MSG_FEATURES_SET``
  ``ETHTOOL_GPERMADDR``               rtnetlink ``RTM_GETLINK``
  ``ETHTOOL_GUFO``                    n/a
  ``ETHTOOL_SUFO``                    n/a
  ``ETHTOOL_GGSO``                    n/a
  ``ETHTOOL_SGSO``                    n/a
  ``ETHTOOL_GFLAGS``                  n/a
  ``ETHTOOL_SFLAGS``                  n/a
  ``ETHTOOL_GPFLAGS``                 n/a
  ``ETHTOOL_SPFLAGS``                 n/a
  ``ETHTOOL_GUFO``                    ``ETHTOOL_MSG_FEATURES_GET``
  ``ETHTOOL_SUFO``                    ``ETHTOOL_MSG_FEATURES_SET``
  ``ETHTOOL_GGSO``                    ``ETHTOOL_MSG_FEATURES_GET``
  ``ETHTOOL_SGSO``                    ``ETHTOOL_MSG_FEATURES_SET``
  ``ETHTOOL_GFLAGS``                  ``ETHTOOL_MSG_FEATURES_GET``
  ``ETHTOOL_SFLAGS``                  ``ETHTOOL_MSG_FEATURES_SET``
  ``ETHTOOL_GPFLAGS``                 ``ETHTOOL_MSG_PRIVFLAGS_GET``
  ``ETHTOOL_SPFLAGS``                 ``ETHTOOL_MSG_PRIVFLAGS_SET``
  ``ETHTOOL_GRXFH``                   n/a
  ``ETHTOOL_SRXFH``                   n/a
  ``ETHTOOL_GGRO``                    n/a
  ``ETHTOOL_SGRO``                    n/a
  ``ETHTOOL_GGRO``                    ``ETHTOOL_MSG_FEATURES_GET``
  ``ETHTOOL_SGRO``                    ``ETHTOOL_MSG_FEATURES_SET``
  ``ETHTOOL_GRXRINGS``                n/a
  ``ETHTOOL_GRXCLSRLCNT``             n/a
  ``ETHTOOL_GRXCLSRULE``              n/a
@@ -589,10 +813,10 @@ have their netlink replacement yet.
  ``ETHTOOL_GSSET_INFO``              ``ETHTOOL_MSG_STRSET_GET``
  ``ETHTOOL_GRXFHINDIR``              n/a
  ``ETHTOOL_SRXFHINDIR``              n/a
  ``ETHTOOL_GFEATURES``               n/a
  ``ETHTOOL_SFEATURES``               n/a
  ``ETHTOOL_GCHANNELS``               n/a
  ``ETHTOOL_SCHANNELS``               n/a
  ``ETHTOOL_GFEATURES``               ``ETHTOOL_MSG_FEATURES_GET``
  ``ETHTOOL_SFEATURES``               ``ETHTOOL_MSG_FEATURES_SET``
  ``ETHTOOL_GCHANNELS``               ``ETHTOOL_MSG_CHANNELS_GET``
  ``ETHTOOL_SCHANNELS``               ``ETHTOOL_MSG_CHANNELS_SET``
  ``ETHTOOL_SET_DUMP``                n/a
  ``ETHTOOL_GET_DUMP_FLAG``           n/a
  ``ETHTOOL_GET_DUMP_DATA``           n/a
+82 −0
Original line number Diff line number Diff line
@@ -24,6 +24,14 @@ enum {
	ETHTOOL_MSG_DEBUG_SET,
	ETHTOOL_MSG_WOL_GET,
	ETHTOOL_MSG_WOL_SET,
	ETHTOOL_MSG_FEATURES_GET,
	ETHTOOL_MSG_FEATURES_SET,
	ETHTOOL_MSG_PRIVFLAGS_GET,
	ETHTOOL_MSG_PRIVFLAGS_SET,
	ETHTOOL_MSG_RINGS_GET,
	ETHTOOL_MSG_RINGS_SET,
	ETHTOOL_MSG_CHANNELS_GET,
	ETHTOOL_MSG_CHANNELS_SET,

	/* add new constants above here */
	__ETHTOOL_MSG_USER_CNT,
@@ -43,6 +51,15 @@ enum {
	ETHTOOL_MSG_DEBUG_NTF,
	ETHTOOL_MSG_WOL_GET_REPLY,
	ETHTOOL_MSG_WOL_NTF,
	ETHTOOL_MSG_FEATURES_GET_REPLY,
	ETHTOOL_MSG_FEATURES_SET_REPLY,
	ETHTOOL_MSG_FEATURES_NTF,
	ETHTOOL_MSG_PRIVFLAGS_GET_REPLY,
	ETHTOOL_MSG_PRIVFLAGS_NTF,
	ETHTOOL_MSG_RINGS_GET_REPLY,
	ETHTOOL_MSG_RINGS_NTF,
	ETHTOOL_MSG_CHANNELS_GET_REPLY,
	ETHTOOL_MSG_CHANNELS_NTF,

	/* add new constants above here */
	__ETHTOOL_MSG_KERNEL_CNT,
@@ -228,6 +245,71 @@ enum {
	ETHTOOL_A_WOL_MAX = __ETHTOOL_A_WOL_CNT - 1
};

/* FEATURES */

enum {
	ETHTOOL_A_FEATURES_UNSPEC,
	ETHTOOL_A_FEATURES_HEADER,			/* nest - _A_HEADER_* */
	ETHTOOL_A_FEATURES_HW,				/* bitset */
	ETHTOOL_A_FEATURES_WANTED,			/* bitset */
	ETHTOOL_A_FEATURES_ACTIVE,			/* bitset */
	ETHTOOL_A_FEATURES_NOCHANGE,			/* bitset */

	/* add new constants above here */
	__ETHTOOL_A_FEATURES_CNT,
	ETHTOOL_A_FEATURES_MAX = __ETHTOOL_A_FEATURES_CNT - 1
};

/* PRIVFLAGS */

enum {
	ETHTOOL_A_PRIVFLAGS_UNSPEC,
	ETHTOOL_A_PRIVFLAGS_HEADER,			/* nest - _A_HEADER_* */
	ETHTOOL_A_PRIVFLAGS_FLAGS,			/* bitset */

	/* add new constants above here */
	__ETHTOOL_A_PRIVFLAGS_CNT,
	ETHTOOL_A_PRIVFLAGS_MAX = __ETHTOOL_A_PRIVFLAGS_CNT - 1
};

/* RINGS */

enum {
	ETHTOOL_A_RINGS_UNSPEC,
	ETHTOOL_A_RINGS_HEADER,				/* nest - _A_HEADER_* */
	ETHTOOL_A_RINGS_RX_MAX,				/* u32 */
	ETHTOOL_A_RINGS_RX_MINI_MAX,			/* u32 */
	ETHTOOL_A_RINGS_RX_JUMBO_MAX,			/* u32 */
	ETHTOOL_A_RINGS_TX_MAX,				/* u32 */
	ETHTOOL_A_RINGS_RX,				/* u32 */
	ETHTOOL_A_RINGS_RX_MINI,			/* u32 */
	ETHTOOL_A_RINGS_RX_JUMBO,			/* u32 */
	ETHTOOL_A_RINGS_TX,				/* u32 */

	/* add new constants above here */
	__ETHTOOL_A_RINGS_CNT,
	ETHTOOL_A_RINGS_MAX = (__ETHTOOL_A_RINGS_CNT - 1)
};

/* CHANNELS */

enum {
	ETHTOOL_A_CHANNELS_UNSPEC,
	ETHTOOL_A_CHANNELS_HEADER,			/* nest - _A_HEADER_* */
	ETHTOOL_A_CHANNELS_RX_MAX,			/* u32 */
	ETHTOOL_A_CHANNELS_TX_MAX,			/* u32 */
	ETHTOOL_A_CHANNELS_OTHER_MAX,			/* u32 */
	ETHTOOL_A_CHANNELS_COMBINED_MAX,		/* u32 */
	ETHTOOL_A_CHANNELS_RX_COUNT,			/* u32 */
	ETHTOOL_A_CHANNELS_TX_COUNT,			/* u32 */
	ETHTOOL_A_CHANNELS_OTHER_COUNT,			/* u32 */
	ETHTOOL_A_CHANNELS_COMBINED_COUNT,		/* u32 */

	/* add new constants above here */
	__ETHTOOL_A_CHANNELS_CNT,
	ETHTOOL_A_CHANNELS_MAX = (__ETHTOOL_A_CHANNELS_CNT - 1)
};

/* generic netlink info */
#define ETHTOOL_GENL_NAME "ethtool"
#define ETHTOOL_GENL_VERSION 1
+2 −1
Original line number Diff line number Diff line
@@ -5,4 +5,5 @@ obj-y += ioctl.o common.o
obj-$(CONFIG_ETHTOOL_NETLINK)	+= ethtool_nl.o

ethtool_nl-y	:= netlink.o bitset.o strset.o linkinfo.o linkmodes.o \
		   linkstate.o debug.o wol.o
		   linkstate.o debug.o wol.o features.o privflags.o rings.o \
		   channels.o
+94 −0
Original line number Diff line number Diff line
@@ -588,6 +588,100 @@ int ethnl_update_bitset32(u32 *bitmap, unsigned int nbits,
	return 0;
}

/**
 * ethnl_parse_bitset() - Compute effective value and mask from bitset nest
 * @val:     unsigned long based bitmap to put value into
 * @mask:    unsigned long based bitmap to put mask into
 * @nbits:   size of @val and @mask bitmaps
 * @attr:    nest attribute to parse and apply
 * @names:   array of bit names; may be null for compact format
 * @extack:  extack for error reporting
 *
 * Provide @nbits size long bitmaps for value and mask so that
 * x = (val & mask) | (x & ~mask) would modify any @nbits sized bitmap x
 * the same way ethnl_update_bitset() with the same bitset attribute would.
 *
 * Return:   negative error code on failure, 0 on success
 */
int ethnl_parse_bitset(unsigned long *val, unsigned long *mask,
		       unsigned int nbits, const struct nlattr *attr,
		       ethnl_string_array_t names,
		       struct netlink_ext_ack *extack)
{
	struct nlattr *tb[ETHTOOL_A_BITSET_MAX + 1];
	const struct nlattr *bit_attr;
	bool no_mask;
	int rem;
	int ret;

	if (!attr)
		return 0;
	ret = nla_parse_nested(tb, ETHTOOL_A_BITSET_MAX, attr, bitset_policy,
			       extack);
	if (ret < 0)
		return ret;
	no_mask = tb[ETHTOOL_A_BITSET_NOMASK];

	if (!tb[ETHTOOL_A_BITSET_BITS]) {
		unsigned int change_bits;

		ret = ethnl_compact_sanity_checks(nbits, attr, tb, extack);
		if (ret < 0)
			return ret;

		change_bits = nla_get_u32(tb[ETHTOOL_A_BITSET_SIZE]);
		bitmap_from_arr32(val, nla_data(tb[ETHTOOL_A_BITSET_VALUE]),
				  change_bits);
		if (change_bits < nbits)
			bitmap_clear(val, change_bits, nbits - change_bits);
		if (no_mask) {
			bitmap_fill(mask, nbits);
		} else {
			bitmap_from_arr32(mask,
					  nla_data(tb[ETHTOOL_A_BITSET_MASK]),
					  change_bits);
			if (change_bits < nbits)
				bitmap_clear(mask, change_bits,
					     nbits - change_bits);
		}

		return 0;
	}

	if (tb[ETHTOOL_A_BITSET_VALUE]) {
		NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_VALUE],
				    "value only allowed in compact bitset");
		return -EINVAL;
	}
	if (tb[ETHTOOL_A_BITSET_MASK]) {
		NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK],
				    "mask only allowed in compact bitset");
		return -EINVAL;
	}

	bitmap_zero(val, nbits);
	if (no_mask)
		bitmap_fill(mask, nbits);
	else
		bitmap_zero(mask, nbits);

	nla_for_each_nested(bit_attr, tb[ETHTOOL_A_BITSET_BITS], rem) {
		unsigned int idx;
		bool bit_val;

		ret = ethnl_parse_bit(&idx, &bit_val, nbits, bit_attr, no_mask,
				      names, extack);
		if (ret < 0)
			return ret;
		if (bit_val)
			__set_bit(idx, val);
		if (!no_mask)
			__set_bit(idx, mask);
	}

	return 0;
}

#if BITS_PER_LONG == 64 && defined(__BIG_ENDIAN)

/* 64-bit big endian architectures are the only case when u32 based bitmaps
+4 −0
Original line number Diff line number Diff line
@@ -26,5 +26,9 @@ int ethnl_update_bitset(unsigned long *bitmap, unsigned int nbits,
int ethnl_update_bitset32(u32 *bitmap, unsigned int nbits,
			  const struct nlattr *attr, ethnl_string_array_t names,
			  struct netlink_ext_ack *extack, bool *mod);
int ethnl_parse_bitset(unsigned long *val, unsigned long *mask,
		       unsigned int nbits, const struct nlattr *attr,
		       ethnl_string_array_t names,
		       struct netlink_ext_ack *extack);

#endif /* _NET_ETHTOOL_BITSET_H */
Loading