diff --git a/include/net/netlink.h b/include/net/netlink.h
index 7a2a9d3144ba..87fcb8d0cbe8 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -2,7 +2,7 @@
 #ifndef __NET_NETLINK_H
 #define __NET_NETLINK_H
 
-#include <linux/types.h>
+#include <linux/bitmap.h>
 #include <linux/netlink.h>
 #include <linux/jiffies.h>
 #include <linux/in6.h>
@@ -180,6 +180,7 @@ enum {
 	NLA_S32,
 	NLA_S64,
 	NLA_BITFIELD32,
+	NLA_BITMAP,
 	NLA_REJECT,
 	__NLA_TYPE_MAX,
 };
@@ -235,12 +236,16 @@ enum nla_policy_validation {
  *                         given type fits, using it verifies minimum length
  *                         just like "All other"
  *    NLA_BITFIELD32       Unused
+ *    NLA_BITMAP           Number of bits in the bitmap
  *    NLA_REJECT           Unused
  *    All other            Minimum length of attribute payload
  *
  * Meaning of validation union:
  *    NLA_BITFIELD32       This is a 32-bit bitmap/bitselector attribute and
  *                         `bitfield32_valid' is the u32 value of valid flags
+ *    NLA_BITMAP           `bitmap_mask` is a pointer to the mask of the valid
+ *                         bits of the given bitmap to perform the validation,
+ *                         its lowest 2 bits specify its type (u64/be64/le64).
  *    NLA_REJECT           This attribute is always rejected and `reject_message'
  *                         may point to a string to report as the error instead
  *                         of the generic one in extended ACK.
@@ -326,6 +331,7 @@ struct nla_policy {
 		struct {
 			s16 min, max;
 		};
+		const unsigned long *bitmap_mask;
 		int (*validate)(const struct nlattr *attr,
 				struct netlink_ext_ack *extack);
 		/* This entry is special, and used for the attribute at index 0
@@ -442,6 +448,47 @@ struct nla_policy {
 }
 #define NLA_POLICY_MIN_LEN(_len)	NLA_POLICY_MIN(NLA_BINARY, _len)
 
+/* `unsigned long` has alignment of 4 or 8 bytes, so [1:0] are always zero.
+ * We put bitmap type (%BITMAP_ARR_*64) there to not inflate &nla_policy
+ * (one new `u32` field adds 10 Kb to kernel data). Bitmap type is 0 (native)
+ * in most cases, which means no pointer modifications.
+ * The variable arguments can take only one optional argument: pointer to
+ * the bitmap mask used for validation. If it's not present, ::bitmap_mask
+ * carries only bitmap type.
+ * The first cast here ensures that the passed mask bitmap is compatible with
+ * `const unsigned long *`, the second -- that @_type is scalar.
+ */
+#define __NLA_POLICY_BITMAP_MASK(_type, ...)				 \
+	((typeof((__VA_ARGS__ + 0) ? : NULL))				 \
+	 ((typeof((_type) + 0UL))(__VA_ARGS__ + 0) + (_type)))
+
+static_assert(__BITMAP_ARR_TYPE_NUM <= __alignof__(long));
+
+/**
+ * __NLA_POLICY_BITMAP - represent &nla_policy for a bitmap attribute
+ * @_nbits - number of bits in the bitmap
+ * @_type - type of the an arr64 used for communication (%BITMAP_ARR_*64)
+ * @... - optional pointer to a bitmap carrying mask of supported bits
+ */
+#define __NLA_POLICY_BITMAP(_nbits, _type, ...) {			 \
+	.type = NLA_BITMAP,						 \
+	.len = (_nbits),						 \
+	.bitmap_mask = __NLA_POLICY_BITMAP_MASK((_type), ##__VA_ARGS__), \
+	.validation_type = (__VA_ARGS__ + 0) ? NLA_VALIDATE_MASK : 0,	 \
+}
+
+#define NLA_POLICY_BITMAP(nbits, ...)					 \
+	__NLA_POLICY_BITMAP((nbits), BITMAP_ARR_U64, ##__VA_ARGS__)
+
+#define nla_policy_bitmap_mask(pt)					 \
+	((typeof((pt)->bitmap_mask))					 \
+	 ((size_t)(pt)->bitmap_mask & ~(__alignof__(long) - 1)))
+
+#define nla_policy_bitmap_type(pt)					 \
+	((u32)((size_t)(pt)->bitmap_mask & (__alignof__(long) - 1)))
+
+#define nla_policy_bitmap_nbits(pt)	((pt)->len)
+
 /**
  * struct nl_info - netlink source information
  * @nlh: Netlink message header of original request
@@ -1545,6 +1592,63 @@ static inline int nla_put_bitfield32(struct sk_buff *skb, int attrtype,
 	return nla_put(skb, attrtype, sizeof(tmp), &tmp);
 }
 
+/**
+ * __nla_put_bitmap - Add a bitmap netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @bitmap: bitmap to put
+ * @nbits: number of bits in the bitmap
+ * @type: type of the u64-array bitmap to put (%BITMAP_ARR_*64)
+ * @padattr: attribute type for the padding
+ */
+static inline int __nla_put_bitmap(struct sk_buff *skb, int attrtype,
+				   const unsigned long *bitmap,
+				   size_t nbits, u32 type, int padattr)
+{
+	struct nlattr *nla;
+
+	nla = nla_reserve_64bit(skb, attrtype, bitmap_arr64_size(nbits),
+				padattr);
+	if (unlikely(!nla))
+		return -EMSGSIZE;
+
+	bitmap_to_arr64_type(nla_data(nla), bitmap, nbits, type);
+
+	return 0;
+}
+
+static inline int nla_put_bitmap(struct sk_buff *skb, int attrtype,
+				 const unsigned long *bitmap, size_t nbits,
+				 int padattr)
+{
+	return __nla_put_bitmap(skb, attrtype, bitmap, nbits, BITMAP_ARR_U64,
+				padattr);
+}
+
+static inline int nla_put_bitmap_be(struct sk_buff *skb, int attrtype,
+				    const unsigned long *bitmap, size_t nbits,
+				    int padattr)
+{
+	return __nla_put_bitmap(skb, attrtype, bitmap, nbits, BITMAP_ARR_BE64,
+				padattr);
+}
+
+static inline int nla_put_bitmap_le(struct sk_buff *skb, int attrtype,
+				    const unsigned long *bitmap, size_t nbits,
+				    int padattr)
+{
+	return __nla_put_bitmap(skb, attrtype, bitmap, nbits, BITMAP_ARR_LE64,
+				padattr);
+}
+
+static inline int nla_put_bitmap_net(struct sk_buff *skb, int attrtype,
+				     const unsigned long *bitmap, size_t nbits,
+				     int padattr)
+{
+	return nla_put_bitmap_be(skb, attrtype | NLA_F_NET_BYTEORDER, bitmap,
+				 nbits, padattr);
+}
+
 /**
  * nla_get_u32 - return payload of u32 attribute
  * @nla: u32 netlink attribute
@@ -1738,6 +1842,47 @@ static inline struct nla_bitfield32 nla_get_bitfield32(const struct nlattr *nla)
 	return tmp;
 }
 
+/**
+ * __nla_get_bitmap - Return a bitmap from u64-array bitmap Netlink attribute
+ * @nla: %NLA_BITMAP Netlink attribute
+ * @bitmap: target container
+ * @nbits: expected number of bits in the bitmap
+ * @type: expected type of the attribute (%BITMAP_ARR_*64)
+ */
+static inline void __nla_get_bitmap(const struct nlattr *nla,
+				    unsigned long *bitmap,
+				    size_t nbits, u32 type)
+{
+	size_t diff = ALIGN(nbits, BITS_PER_LONG);
+
+	nbits = min_t(typeof(nbits), nbits, nla_len(nla) * BITS_PER_BYTE);
+	bitmap_from_arr64_type(bitmap, nla_data(nla), nbits, type);
+
+	diff -= ALIGN(nbits, BITS_PER_LONG);
+	if (diff)
+		bitmap_clear(bitmap, ALIGN(nbits, BITS_PER_LONG), diff);
+}
+
+static inline void nla_get_bitmap(const struct nlattr *nla,
+				  unsigned long *bitmap, size_t nbits)
+{
+	return __nla_get_bitmap(nla, bitmap, nbits, BITMAP_ARR_U64);
+}
+
+static inline void nla_get_bitmap_be(const struct nlattr *nla,
+				     unsigned long *bitmap, size_t nbits)
+{
+	return __nla_get_bitmap(nla, bitmap, nbits, BITMAP_ARR_BE64);
+}
+
+static inline void nla_get_bitmap_le(const struct nlattr *nla,
+				     unsigned long *bitmap, size_t nbits)
+{
+	return __nla_get_bitmap(nla, bitmap, nbits, BITMAP_ARR_LE64);
+}
+
+#define nla_get_bitmap_net nla_get_bitmap_be
+
 /**
  * nla_memdup - duplicate attribute memory (kmemdup)
  * @src: netlink attribute to duplicate from
@@ -1910,6 +2055,18 @@ static inline int nla_total_size_64bit(int payload)
 		;
 }
 
+/**
+ * nla_total_size_bitmap - get total size of Netlink attr for a number of bits
+ * @nbits: number of bits to store in the attribute
+ *
+ * Returns the size in bytes of a Netlink attribute needed to carry
+ * the specified number of bits.
+ */
+static inline size_t nla_total_size_bitmap(size_t nbits)
+{
+	return nla_total_size_64bit(bitmap_arr64_size(nbits));
+}
+
 /**
  * nla_for_each_attr - iterate over a stream of attributes
  * @pos: loop counter, set to current attribute
diff --git a/include/uapi/linux/netlink.h b/include/uapi/linux/netlink.h
index 855dffb4c1c3..cb55d3ce810b 100644
--- a/include/uapi/linux/netlink.h
+++ b/include/uapi/linux/netlink.h
@@ -284,6 +284,8 @@ struct nla_bitfield32 {
  *	entry has attributes again, the policy for those inner ones
  *	and the corresponding maxtype may be specified.
  * @NL_ATTR_TYPE_BITFIELD32: &struct nla_bitfield32 attribute
+ * @NL_ATTR_TYPE_BITMAP: array of 64-bit unsigned values (__{u,be,le}64)
+ * which form one big bitmap. Validated by an optional bitmask.
  */
 enum netlink_attribute_type {
 	NL_ATTR_TYPE_INVALID,
@@ -308,6 +310,7 @@ enum netlink_attribute_type {
 	NL_ATTR_TYPE_NESTED_ARRAY,
 
 	NL_ATTR_TYPE_BITFIELD32,
+	NL_ATTR_TYPE_BITMAP,
 };
 
 /**
@@ -337,6 +340,7 @@ enum netlink_attribute_type {
  *	bitfield32 type (U32)
  * @NL_POLICY_TYPE_ATTR_MASK: mask of valid bits for unsigned integers (U64)
  * @NL_POLICY_TYPE_ATTR_PAD: pad attribute for 64-bit alignment
+ * @NL_POLICY_TYPE_ATTR_BITMAP_MASK: mask of valid bits for bitmaps
  */
 enum netlink_policy_type_attr {
 	NL_POLICY_TYPE_ATTR_UNSPEC,
@@ -352,6 +356,7 @@ enum netlink_policy_type_attr {
 	NL_POLICY_TYPE_ATTR_BITFIELD32_MASK,
 	NL_POLICY_TYPE_ATTR_PAD,
 	NL_POLICY_TYPE_ATTR_MASK,
+	NL_POLICY_TYPE_ATTR_BITMAP_MASK,
 
 	/* keep last */
 	__NL_POLICY_TYPE_ATTR_MAX,
diff --git a/lib/nlattr.c b/lib/nlattr.c
index 86029ad5ead4..ebff927cfe3a 100644
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -81,6 +81,33 @@ static int validate_nla_bitfield32(const struct nlattr *nla,
 	return 0;
 }
 
+static int nla_validate_bitmap_mask(const struct nla_policy *pt,
+				    const struct nlattr *nla,
+				    struct netlink_ext_ack *extack)
+{
+	unsigned long *bitmap;
+	size_t nbits;
+	bool res;
+
+	nbits = min_t(typeof(nbits), nla_len(nla) * BITS_PER_BYTE,
+		      nla_policy_bitmap_nbits(pt));
+
+	bitmap = bitmap_alloc(nbits, in_task() ? GFP_KERNEL : GFP_ATOMIC);
+	if (!bitmap)
+		return -ENOMEM;
+
+	__nla_get_bitmap(nla, bitmap, nbits, nla_policy_bitmap_type(pt));
+	res = bitmap_andnot(bitmap, bitmap, nla_policy_bitmap_mask(pt), nbits);
+	kfree(bitmap);
+
+	if (res) {
+		NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt, "unexpected bit set");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int nla_validate_array(const struct nlattr *head, int len, int maxtype,
 			      const struct nla_policy *policy,
 			      struct netlink_ext_ack *extack,
@@ -342,6 +369,8 @@ static int nla_validate_mask(const struct nla_policy *pt,
 	case NLA_U64:
 		value = nla_get_u64(nla);
 		break;
+	case NLA_BITMAP:
+		return nla_validate_bitmap_mask(pt, nla, extack);
 	default:
 		return -EINVAL;
 	}
@@ -422,6 +451,15 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
 			goto out_err;
 		break;
 
+	case NLA_BITMAP:
+		err = bitmap_validate_arr64_type(nla_data(nla), nla_len(nla),
+						 nla_policy_bitmap_nbits(pt),
+						 nla_policy_bitmap_type(pt));
+		if (err)
+			goto out_err;
+
+		break;
+
 	case NLA_NUL_STRING:
 		if (pt->len)
 			minlen = min_t(int, attrlen, pt->len + 1);
@@ -649,7 +687,10 @@ nla_policy_len(const struct nla_policy *p, int n)
 	int i, len = 0;
 
 	for (i = 0; i < n; i++, p++) {
-		if (p->len)
+		if (p->type == NLA_BITMAP)
+			len +=
+			    nla_total_size_bitmap(nla_policy_bitmap_nbits(p));
+		else if (p->len)
 			len += nla_total_size(p->len);
 		else if (nla_attr_len[p->type])
 			len += nla_total_size(nla_attr_len[p->type]);
diff --git a/net/netlink/policy.c b/net/netlink/policy.c
index 8d7c900e27f4..8a5a86fb1549 100644
--- a/net/netlink/policy.c
+++ b/net/netlink/policy.c
@@ -224,6 +224,10 @@ int netlink_policy_dump_attr_size_estimate(const struct nla_policy *pt)
 		       2 * (nla_attr_size(0) + nla_attr_size(sizeof(u64)));
 	case NLA_BITFIELD32:
 		return common + nla_attr_size(sizeof(u32));
+	case NLA_BITMAP:
+		/* maximum is common, aligned validation mask as u64 bitmap */
+		return common +
+		       nla_total_size_bitmap(nla_policy_bitmap_nbits(pt));
 	case NLA_STRING:
 	case NLA_NUL_STRING:
 	case NLA_BINARY:
@@ -237,6 +241,40 @@ int netlink_policy_dump_attr_size_estimate(const struct nla_policy *pt)
 	return 0;
 }
 
+static bool
+__netlink_policy_dump_write_attr_bitmap(struct sk_buff *skb,
+					const struct nla_policy *pt)
+{
+	if (pt->validation_type == NLA_VALIDATE_MASK) {
+		if (__nla_put_bitmap(skb, NL_POLICY_TYPE_ATTR_BITMAP_MASK,
+				     nla_policy_bitmap_mask(pt),
+				     nla_policy_bitmap_nbits(pt),
+				     nla_policy_bitmap_type(pt),
+				     NL_POLICY_TYPE_ATTR_PAD))
+			return false;
+	} else {
+		unsigned long *mask;
+		int ret;
+
+		mask = bitmap_zalloc(nla_policy_bitmap_nbits(pt),
+				     in_task() ? GFP_KERNEL : GFP_ATOMIC);
+		if (!mask)
+			return false;
+
+		bitmap_set(mask, 0, nla_policy_bitmap_nbits(pt));
+		ret = __nla_put_bitmap(skb, NL_POLICY_TYPE_ATTR_BITMAP_MASK,
+				       mask, nla_policy_bitmap_nbits(pt),
+				       nla_policy_bitmap_type(pt),
+				       NL_POLICY_TYPE_ATTR_PAD);
+		kfree(mask);
+
+		if (ret)
+			return false;
+	}
+
+	return true;
+}
+
 static int
 __netlink_policy_dump_write_attr(struct netlink_policy_dump_state *state,
 				 struct sk_buff *skb,
@@ -336,6 +374,12 @@ __netlink_policy_dump_write_attr(struct netlink_policy_dump_state *state,
 				pt->bitfield32_valid))
 			goto nla_put_failure;
 		break;
+	case NLA_BITMAP:
+		if (!__netlink_policy_dump_write_attr_bitmap(skb, pt))
+			goto nla_put_failure;
+
+		type = NL_ATTR_TYPE_BITMAP;
+		break;
 	case NLA_STRING:
 	case NLA_NUL_STRING:
 	case NLA_BINARY:
