STRUCT NLA_POLICY(9)

πŸ“¦ version 7.3.1, in nixpkgs unstable

πŸ’… struct nla_policy β€” attribute validation policy

okay bestie, welcome to the Kernel API Manual, section 9. This is the page for struct nla_policy, aka the glow-up your netlink attributes need before anyone's allowed to touch them ✨


🌸 NAME 🌸

struct nla_policy β€” attribute validation policy πŸŽ€


✨ SYNOPSIS ✨

struct nla_policy {
    u8 type;
    u8 validation_type;
    u16 len;
    union {
      u16 strict_start_type;
    };
 };

πŸ¦‹ Members πŸ¦‹

  • type β€” the type of the attribute, or NLA_UNSPEC. that's it, that's the field πŸ’…
  • validation_type β€” the type of attribute validation that gets done in addition to the type-specific validation (think range checks, function calls, all that extra credit work). peep enum nla_policy_validation for the deets.
  • len β€” the type specific length of the payload πŸ“
  • {unnamed_union} β€” anonymous. it's giving mysterious, it's giving "no name needed" πŸ™ˆ
  • strict_start_type β€” the first attribute to validate strictly πŸ”₯
okay so this entry is special β€” it's used for the attribute at index 0 only, and it carries special data about the policy itself. namely, it specifies the "boundary type" where strict length validation starts for any attribute types >= this value. also, strict nesting validation starts right here too. periodt.
additionally (yes there's more, stay with me), it means that NLA_UNSPEC is actually NLA_REJECT for any types >= this. so you need to use NLA_POLICY_MIN_LEN to get the previous pure { .len = xyz } behaviour back. the advantage? types that aren't specified in the policy get rejected. lowkey iconic 🫢
for completely new families it should be set to 1 so the validation is enforced for all attributes. for existing ones, it should be set at least when new attributes get added to the enum used by the policy, and be set to the new value that was added, so strict validation is enforced from thereon πŸ‘‘

πŸ’œ Description πŸ’œ

Policies are defined as arrays of this struct, and the array must be accessible by attribute type up to the highest identifier you expect to see. no cap, plan your indices.

πŸ“ Meaning of len field

  • NLA_STRING β€” maximum length of string
  • NLA_NUL_STRING β€” maximum length of string (excluding NUL)
  • NLA_FLAG β€” unused
  • NLA_BINARY β€” maximum length of attribute payload (but see also below, with the validation type)
  • NLA_NESTED, NLA_NESTED_ARRAY β€” length verification is done by checking len of the nested header (or empty); the 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, NLA_S32, NLA_S64, NLA_BE16, NLA_BE32, NLA_MSECS β€” leaving the length field zero will verify the given type fits; using it verifies minimum length just like "All other"
  • NLA_BITFIELD32 β€” unused
  • 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_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 πŸ’€
  • NLA_NESTED β€” nested_policy points to a nested policy to validate, and you must also set len to the max attribute number. use the provided NLA_POLICY_NESTED macro. note that nla_parse will validate β€” but of course not parse β€” the nested sub-policies.
  • NLA_NESTED_ARRAY β€” nested_policy points to a nested policy to validate, and you must also set len to the max attribute number. use the provided NLA_POLICY_NESTED_ARRAY macro. the difference from NLA_NESTED is the structure: NLA_NESTED has the nested attributes directly inside, 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, NLA_S64 β€” the min and max fields get used depending on the validation_type field. if that's min/max/range then the min, max, or both are used (respectively) to check the value of the integer attribute. ⚠️ note that in the interest of code simplicity and struct size, both limits are s16, so you cannot enforce a range that doesn't fall within the range of s16 β€” do that using the NLA_POLICY_FULL_RANGE 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, NLA_U64 β€” if the validation_type field instead is set to NLA_VALIDATE_RANGE_PTR, then range must be a pointer 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, NLA_S64 β€” if the validation_type field instead is set to NLA_VALIDATE_RANGE_PTR, then range_signed must be a pointer to a struct netlink_range_validation_signed that indicates the min/max values. use NLA_POLICY_FULL_RANGE_SIGNED.
  • NLA_BINARY β€” if the validation type is like the ones for integers above, then the min/max length (not value like for integers, bestie, length) of the attribute is enforced.
  • All other β€” unused. but note that it's a union πŸ’…

🧚 Meaning of validate field β€” use via NLA_POLICY_VALIDATE_FN

  • NLA_U8, NLA_U16, NLA_U32, NLA_U64, NLA_S8, NLA_S16, NLA_S32, NLA_S64, NLA_MSECS, NLA_BINARY β€” validation function called for the attribute πŸ”₯
  • All other β€” unused β€” but note that it's a union πŸ™ˆ

πŸ‘‘ Example πŸ‘‘

static const u32 myvalidflags = 0xff231023;

static const struct nla_policy my_policy[ATTR_MAX+1] = {
    [ATTR_FOO] = { .type = NLA_U16 },
    [ATTR_BAR] = { .type = NLA_STRING, .len = BARSIZ },
    [ATTR_BAZ] = NLA_POLICY_EXACT_LEN(sizeof(struct mystruct)),
    [ATTR_GOO] = NLA_POLICY_BITFIELD32(myvalidflags),
};

⭐ SEE ALSO ⭐

Kernel file ./include/net/netlink.h β€” plus, like, the entire extended netlink family reunion, no cap: struct nl_info(9), enum netlink_validation(9), nlmsg_msg_size(9), nlmsg_total_size(9), nlmsg_padlen(9), nlmsg_data(9), nlmsg_len(9), nlmsg_payload(9), nlmsg_attrdata(9), nlmsg_attrlen(9), nlmsg_ok(9), nlmsg_next(9), nla_parse(9), nla_parse_deprecated(9), nla_parse_deprecated_strict(9), __nlmsg_parse(9), nlmsg_parse(9), nlmsg_parse_deprecated(9), nlmsg_parse_deprecated_strict(9), nlmsg_find_attr(9), nla_validate_deprecated(9), nla_validate(9), nlmsg_validate_deprecated(9), nlmsg_report(9), nlmsg_seq(9), nlmsg_for_each_attr(9), nlmsg_for_each_attr_type(9), nlmsg_put(9), nlmsg_append(9), nlmsg_put_answer(9), nlmsg_new(9), nlmsg_new_large(9), nlmsg_end(9), nlmsg_get_pos(9), nlmsg_trim(9), nlmsg_cancel(9), nlmsg_free(9), nlmsg_consume(9), nlmsg_multicast_filtered(9), nlmsg_multicast(9), nlmsg_unicast(9), nlmsg_for_each_msg(9), nl_dump_check_consistent(9), nla_attr_size(9), nla_total_size(9), nla_padlen(9), nla_type(9), nla_data(9), nla_len(9), nla_ok(9), nla_next(9), nla_find_nested(9), nla_parse_nested(9), nla_parse_nested_deprecated(9), nla_put_u8(9), nla_put_u16(9), nla_put_be16(9), nla_put_net16(9), nla_put_le16(9), nla_put_u32(9), nla_put_uint(9), nla_put_be32(9), nla_put_net32(9), nla_put_le32(9), nla_put_u64_64bit(9), nla_put_be64(9), nla_put_net64(9), nla_put_le64(9), nla_put_s8(9), nla_put_s16(9), nla_put_s32(9), nla_put_s64(9), nla_put_sint(9), nla_put_string(9), nla_put_flag(9), nla_put_msecs(9), nla_put_in_addr(9), nla_put_in6_addr(9), nla_put_bitfield32(9), nla_get_u32(9), nla_get_u32_default(9), nla_get_be32(9), nla_get_be32_default(9), nla_get_le32(9), nla_get_le32_default(9), nla_get_u16(9), nla_get_u16_default(9), nla_get_be16(9), nla_get_be16_default(9), nla_get_le16(9), nla_get_le16_default(9), nla_get_u8(9), nla_get_u8_default(9), nla_get_u64(9), nla_get_u64_default(9), nla_get_uint(9), nla_get_uint_default(9), nla_get_be64(9), nla_get_be64_default(9), nla_get_le64(9), nla_get_le64_default(9), nla_get_s32(9), nla_get_s32_default(9), nla_get_s16(9), nla_get_s16_default(9), nla_get_s8(9), nla_get_s8_default(9), nla_get_s64(9), nla_get_s64_default(9), nla_get_sint(9), nla_get_sint_default(9), nla_get_flag(9), nla_get_msecs(9), nla_get_msecs_default(9), nla_get_in_addr(9), nla_get_in_addr_default(9), nla_get_in6_addr(9), nla_get_bitfield32(9), nla_memdup(9), nla_nest_start_noflag(9), nla_nest_start(9), nla_nest_end(9), nla_nest_end_safe(9), nla_nest_cancel(9), nla_put_empty_nest(9), __nla_validate_nested(9), nla_need_padding_for_64bit(9), nla_align_64bit(9), nla_total_size_64bit(9), nla_for_each_attr(9), nla_for_each_attr_type(9), nla_for_each_nested(9), nla_for_each_nested_type(9), nla_is_last(9)


and that's the whole page, bestie 🫢 this one shipped out from ./include/net β€” kernel source version dated October 2026, struct nla_policy(9) era. go forth and validate, you absolute icon 🌟

πŸ“¦ where this page comes from