netlink: introduce type-checking attribute iteration for nlmsg

Add the nlmsg_for_each_attr_type() macro to simplify iteration over
attributes of a specific type in a Netlink message.

Convert existing users in vxlan and nfsd to use the new macro.

Suggested-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Carolina Jubran <cjubran@nvidia.com>
Signed-off-by: Mark Bloch <mbloch@nvidia.com>
Link: https://patch.msgid.link/20250629142138.361537-2-mbloch@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Carolina Jubran 2025-06-29 17:21:31 +03:00 committed by Jakub Kicinski
parent 97b2409f28
commit 42401c4238
3 changed files with 32 additions and 31 deletions

View File

@ -971,15 +971,10 @@ static int vxlan_vnifilter_process(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!(vxlan->cfg.flags & VXLAN_F_VNIFILTER))
return -EOPNOTSUPP;
nlmsg_for_each_attr(attr, nlh, sizeof(*tmsg), rem) {
switch (nla_type(attr)) {
case VXLAN_VNIFILTER_ENTRY:
err = vxlan_process_vni_filter(vxlan, attr,
nlh->nlmsg_type, extack);
break;
default:
continue;
}
nlmsg_for_each_attr_type(attr, VXLAN_VNIFILTER_ENTRY, nlh,
sizeof(*tmsg), rem) {
err = vxlan_process_vni_filter(vxlan, attr, nlh->nlmsg_type,
extack);
vnis++;
if (err)
break;

View File

@ -1621,10 +1621,9 @@ int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
/* count number of SERVER_THREADS values */
nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
if (nla_type(attr) == NFSD_A_SERVER_THREADS)
nrpools++;
}
nlmsg_for_each_attr_type(attr, NFSD_A_SERVER_THREADS, info->nlhdr,
GENL_HDRLEN, rem)
nrpools++;
mutex_lock(&nfsd_mutex);
@ -1635,12 +1634,11 @@ int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
}
i = 0;
nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
if (nla_type(attr) == NFSD_A_SERVER_THREADS) {
nthreads[i++] = nla_get_u32(attr);
if (i >= nrpools)
break;
}
nlmsg_for_each_attr_type(attr, NFSD_A_SERVER_THREADS, info->nlhdr,
GENL_HDRLEN, rem) {
nthreads[i++] = nla_get_u32(attr);
if (i >= nrpools)
break;
}
if (info->attrs[NFSD_A_SERVER_GRACETIME] ||
@ -1781,14 +1779,12 @@ int nfsd_nl_version_set_doit(struct sk_buff *skb, struct genl_info *info)
for (i = 0; i <= NFSD_SUPPORTED_MINOR_VERSION; i++)
nfsd_minorversion(nn, i, NFSD_CLEAR);
nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
nlmsg_for_each_attr_type(attr, NFSD_A_SERVER_PROTO_VERSION, info->nlhdr,
GENL_HDRLEN, rem) {
struct nlattr *tb[NFSD_A_VERSION_MAX + 1];
u32 major, minor = 0;
bool enabled;
if (nla_type(attr) != NFSD_A_SERVER_PROTO_VERSION)
continue;
if (nla_parse_nested(tb, NFSD_A_VERSION_MAX, attr,
nfsd_version_nl_policy, info->extack) < 0)
continue;
@ -1939,14 +1935,12 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
* Walk the list of server_socks from userland and move any that match
* back to sv_permsocks
*/
nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
nlmsg_for_each_attr_type(attr, NFSD_A_SERVER_SOCK_ADDR, info->nlhdr,
GENL_HDRLEN, rem) {
struct nlattr *tb[NFSD_A_SOCK_MAX + 1];
const char *xcl_name;
struct sockaddr *sa;
if (nla_type(attr) != NFSD_A_SERVER_SOCK_ADDR)
continue;
if (nla_parse_nested(tb, NFSD_A_SOCK_MAX, attr,
nfsd_sock_nl_policy, info->extack) < 0)
continue;
@ -2001,15 +1995,13 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
svc_xprt_destroy_all(serv, net);
/* walk list of addrs again, open any that still don't exist */
nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
nlmsg_for_each_attr_type(attr, NFSD_A_SERVER_SOCK_ADDR, info->nlhdr,
GENL_HDRLEN, rem) {
struct nlattr *tb[NFSD_A_SOCK_MAX + 1];
const char *xcl_name;
struct sockaddr *sa;
int ret;
if (nla_type(attr) != NFSD_A_SERVER_SOCK_ADDR)
continue;
if (nla_parse_nested(tb, NFSD_A_SOCK_MAX, attr,
nfsd_sock_nl_policy, info->extack) < 0)
continue;

View File

@ -68,6 +68,8 @@
* nlmsg_for_each_msg() loop over all messages
* nlmsg_validate() validate netlink message incl. attrs
* nlmsg_for_each_attr() loop over all attributes
* nlmsg_for_each_attr_type() loop over all attributes with the
* given type
*
* Misc:
* nlmsg_report() report back to application?
@ -966,6 +968,18 @@ static inline u32 nlmsg_seq(const struct nlmsghdr *nlh)
nla_for_each_attr(pos, nlmsg_attrdata(nlh, hdrlen), \
nlmsg_attrlen(nlh, hdrlen), rem)
/**
* nlmsg_for_each_attr_type - iterate over a stream of attributes
* @pos: loop counter, set to the current attribute
* @type: required attribute type for @pos
* @nlh: netlink message header
* @hdrlen: length of the family specific header
* @rem: initialized to len, holds bytes currently remaining in stream
*/
#define nlmsg_for_each_attr_type(pos, type, nlh, hdrlen, rem) \
nlmsg_for_each_attr(pos, nlh, hdrlen, rem) \
if (nla_type(pos) == type)
/**
* nlmsg_put - Add a new netlink message to an skb
* @skb: socket buffer to store message in