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

Merge branch 'netlink-auto-integers'

Jakub Kicinski says:

====================
netlink: add variable-length / auto integers

Add netlink support for "common" / variable-length / auto integers
which are carried at the message level as either 4B or 8B depending
on the exact value. This saves space and will hopefully decrease
the number of instances where we realize that we needed more bits
after uAPI is set is stone. It also loosens the alignment requirements,
avoiding the need for padding.

This mini-series is a fuller version of the previous RFC:
https://lore.kernel.org/netdev/20121204.130914.1457976839967676240.davem@davemloft.net/


No user included here. I have tested (and will use) it
in the upcoming page pool API but the assumption is that
it will be widely applicable. So sending without a user.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a10f9bfe 7d4caf54
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -149,7 +149,8 @@ properties:
              name:
                type: string
              type: &attr-type
                enum: [ unused, pad, flag, binary, u8, u16, u32, u64, s32, s64,
                enum: [ unused, pad, flag, binary,
                        uint, sint, u8, u16, u32, u64, s32, s64,
                        string, nest, array-nest, nest-type-value ]
              doc:
                description: Documentation of the attribute.
+2 −1
Original line number Diff line number Diff line
@@ -192,7 +192,8 @@ properties:
                type: string
              type: &attr-type
                description: The netlink attribute type
                enum: [ unused, pad, flag, binary, u8, u16, u32, u64, s32, s64,
                enum: [ unused, pad, flag, binary,
                        uint, sint, u8, u16, u32, u64, s32, s64,
                        string, nest, array-nest, nest-type-value ]
              doc:
                description: Documentation of the attribute.
+2 −1
Original line number Diff line number Diff line
@@ -122,7 +122,8 @@ properties:
              name:
                type: string
              type: &attr-type
                enum: [ unused, pad, flag, binary, u8, u16, u32, u64, s32, s64,
                enum: [ unused, pad, flag, binary,
                        uint, sint, u8, u16, u32, u64, s32, s64,
                        string, nest, array-nest, nest-type-value ]
              doc:
                description: Documentation of the attribute.
+16 −2
Original line number Diff line number Diff line
@@ -403,10 +403,21 @@ This section describes the attribute types supported by the ``genetlink``
compatibility level. Refer to documentation of different levels for additional
attribute types.

Scalar integer types
Common integer types
--------------------

Fixed-width integer types:
``sint`` and ``uint`` represent signed and unsigned 64 bit integers.
If the value can fit on 32 bits only 32 bits are carried in netlink
messages, otherwise full 64 bits are carried. Note that the payload
is only aligned to 4B, so the full 64 bit value may be unaligned!

Common integer types should be preferred over fix-width types in majority
of cases.

Fix-width integer types
-----------------------

Fixed-width integer types include:
``u8``, ``u16``, ``u32``, ``u64``, ``s8``, ``s16``, ``s32``, ``s64``.

Note that types smaller than 32 bit should be avoided as using them
@@ -416,6 +427,9 @@ See :ref:`pad_type` for padding of 64 bit attributes.
The payload of the attribute is the integer in host order unless ``byte-order``
specifies otherwise.

64 bit values are usually aligned by the kernel but it is recommended
that the user space is able to deal with unaligned values.

.. _pad_type:

pad
+67 −2
Original line number Diff line number Diff line
@@ -128,6 +128,8 @@
 *   nla_len(nla)			length of attribute payload
 *
 * Attribute Payload Access for Basic Types:
 *   nla_get_uint(nla)			get payload for a uint attribute
 *   nla_get_sint(nla)			get payload for a sint attribute
 *   nla_get_u8(nla)			get payload for a u8 attribute
 *   nla_get_u16(nla)			get payload for a u16 attribute
 *   nla_get_u32(nla)			get payload for a u32 attribute
@@ -183,6 +185,8 @@ enum {
	NLA_REJECT,
	NLA_BE16,
	NLA_BE32,
	NLA_SINT,
	NLA_UINT,
	__NLA_TYPE_MAX,
};

@@ -229,6 +233,7 @@ enum nla_policy_validation {
 *                         nested header (or empty); len field is used if
 *                         nested_policy is also used, for the max attr
 *                         number in the nested policy.
 *    NLA_SINT, NLA_UINT,
 *    NLA_U8, NLA_U16,
 *    NLA_U32, NLA_U64,
 *    NLA_S8, NLA_S16,
@@ -260,12 +265,14 @@ enum nla_policy_validation {
 *                         while an array has the nested attributes at another
 *                         level down and the attribute types directly in the
 *                         nesting don't matter.
 *    NLA_UINT,
 *    NLA_U8,
 *    NLA_U16,
 *    NLA_U32,
 *    NLA_U64,
 *    NLA_BE16,
 *    NLA_BE32,
 *    NLA_SINT,
 *    NLA_S8,
 *    NLA_S16,
 *    NLA_S32,
@@ -280,6 +287,7 @@ enum nla_policy_validation {
 *                         or NLA_POLICY_FULL_RANGE_SIGNED() macros instead.
 *                         Use the NLA_POLICY_MIN(), NLA_POLICY_MAX() and
 *                         NLA_POLICY_RANGE() macros.
 *    NLA_UINT,
 *    NLA_U8,
 *    NLA_U16,
 *    NLA_U32,
@@ -288,6 +296,7 @@ enum nla_policy_validation {
 *                         to a struct netlink_range_validation that indicates
 *                         the min/max values.
 *                         Use NLA_POLICY_FULL_RANGE().
 *    NLA_SINT,
 *    NLA_S8,
 *    NLA_S16,
 *    NLA_S32,
@@ -377,9 +386,11 @@ struct nla_policy {

#define __NLA_IS_UINT_TYPE(tp)					\
	(tp == NLA_U8 || tp == NLA_U16 || tp == NLA_U32 ||	\
	 tp == NLA_U64 || tp == NLA_BE16 || tp == NLA_BE32)
	 tp == NLA_U64 || tp == NLA_UINT ||			\
	 tp == NLA_BE16 || tp == NLA_BE32)
#define __NLA_IS_SINT_TYPE(tp)						\
	(tp == NLA_S8 || tp == NLA_S16 || tp == NLA_S32 || tp == NLA_S64)
	(tp == NLA_S8 || tp == NLA_S16 || tp == NLA_S32 || tp == NLA_S64 || \
	 tp == NLA_SINT)

#define __NLA_ENSURE(condition) BUILD_BUG_ON_ZERO(!(condition))
#define NLA_ENSURE_UINT_TYPE(tp)			\
@@ -1357,6 +1368,22 @@ static inline int nla_put_u32(struct sk_buff *skb, int attrtype, u32 value)
	return nla_put(skb, attrtype, sizeof(u32), &tmp);
}

/**
 * nla_put_uint - Add a variable-size unsigned int to a socket buffer
 * @skb: socket buffer to add attribute to
 * @attrtype: attribute type
 * @value: numeric value
 */
static inline int nla_put_uint(struct sk_buff *skb, int attrtype, u64 value)
{
	u64 tmp64 = value;
	u32 tmp32 = value;

	if (tmp64 == tmp32)
		return nla_put_u32(skb, attrtype, tmp32);
	return nla_put(skb, attrtype, sizeof(u64), &tmp64);
}

/**
 * nla_put_be32 - Add a __be32 netlink attribute to a socket buffer
 * @skb: socket buffer to add attribute to
@@ -1511,6 +1538,22 @@ static inline int nla_put_s64(struct sk_buff *skb, int attrtype, s64 value,
	return nla_put_64bit(skb, attrtype, sizeof(s64), &tmp, padattr);
}

/**
 * nla_put_sint - Add a variable-size signed int to a socket buffer
 * @skb: socket buffer to add attribute to
 * @attrtype: attribute type
 * @value: numeric value
 */
static inline int nla_put_sint(struct sk_buff *skb, int attrtype, s64 value)
{
	s64 tmp64 = value;
	s32 tmp32 = value;

	if (tmp64 == tmp32)
		return nla_put_s32(skb, attrtype, tmp32);
	return nla_put(skb, attrtype, sizeof(s64), &tmp64);
}

/**
 * nla_put_string - Add a string netlink attribute to a socket buffer
 * @skb: socket buffer to add attribute to
@@ -1667,6 +1710,17 @@ static inline u64 nla_get_u64(const struct nlattr *nla)
	return tmp;
}

/**
 * nla_get_uint - return payload of uint attribute
 * @nla: uint netlink attribute
 */
static inline u64 nla_get_uint(const struct nlattr *nla)
{
	if (nla_len(nla) == sizeof(u32))
		return nla_get_u32(nla);
	return nla_get_u64(nla);
}

/**
 * nla_get_be64 - return payload of __be64 attribute
 * @nla: __be64 netlink attribute
@@ -1729,6 +1783,17 @@ static inline s64 nla_get_s64(const struct nlattr *nla)
	return tmp;
}

/**
 * nla_get_sint - return payload of uint attribute
 * @nla: uint netlink attribute
 */
static inline s64 nla_get_sint(const struct nlattr *nla)
{
	if (nla_len(nla) == sizeof(s32))
		return nla_get_s32(nla);
	return nla_get_s64(nla);
}

/**
 * nla_get_flag - return payload of flag attribute
 * @nla: flag netlink attribute
Loading