sd-netlink: allow configuration of flags parameter when creating message object

We soon want to add for sock_diag(7) netlink sockets. Those reuse the
same message type codes for request and response but with different
message formats. Hence we need to look at NLM_F_REQUEST to determine
which message policy to apply. Hence it is essential to know the flags
parameters right away when creating a message, since we cannot do early
validation otherwise.

This only adds support for setting the flags value right at the moment
of creation of the message object, it does not otherwise add
sock_diag(7) support, that is added in a later message.

This also corrects the flag for synthetic NLMSG_ERROR messages which
should not have the NLM_F_REQUEST flag set (since they are responses,
not requests).
This commit is contained in:
Lennart Poettering
2025-05-13 14:42:33 +02:00
parent a2ab433a60
commit 6e196011ca
8 changed files with 59 additions and 49 deletions
+1 -1
View File
@@ -244,7 +244,7 @@ static int genl_message_new(
if (!policy_set)
return -EOPNOTSUPP;
r = message_new_full(nl, family->id, policy_set,
r = message_new_full(nl, family->id, NLM_F_REQUEST | NLM_F_ACK, policy_set,
sizeof(struct genlmsghdr) + family->additional_header_size, &m);
if (r < 0)
return r;
+2 -1
View File
@@ -131,10 +131,11 @@ int message_new_empty(sd_netlink *nl, sd_netlink_message **ret);
int message_new_full(
sd_netlink *nl,
uint16_t nlmsg_type,
uint16_t nlmsg_flags,
const NLAPolicySet *policy_set,
size_t header_size,
sd_netlink_message **ret);
int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t type);
int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t type, uint16_t flags);
int message_new_synthetic_error(sd_netlink *nl, int error, uint32_t serial, sd_netlink_message **ret);
static inline uint32_t message_get_serial(sd_netlink_message *m) {
@@ -34,7 +34,7 @@ int sd_nfnl_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int nfproto,
assert_return(nfproto_is_valid(nfproto), -EINVAL);
assert_return(NFNL_MSG_TYPE(msg_type) == msg_type, -EINVAL);
r = message_new(nfnl, &m, subsys << 8 | msg_type);
r = message_new(nfnl, &m, subsys << 8 | msg_type, NLM_F_REQUEST | NLM_F_ACK);
if (r < 0)
return r;
@@ -244,13 +244,13 @@ int sd_rtnl_message_new_route(
IN_SET(family, AF_INET, AF_INET6), -EINVAL);
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
r = message_new(rtnl,
ret,
nlmsg_type,
NLM_F_REQUEST|NLM_F_ACK|(nlmsg_type == RTM_NEWROUTE ? NLM_F_CREATE | NLM_F_APPEND : 0));
if (r < 0)
return r;
if (nlmsg_type == RTM_NEWROUTE)
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
rtm = NLMSG_DATA((*ret)->hdr);
rtm->rtm_family = family;
@@ -281,13 +281,13 @@ int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret,
}
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
r = message_new(rtnl,
ret,
nlmsg_type,
NLM_F_REQUEST | NLM_F_ACK | (nlmsg_type == RTM_NEWNEXTHOP ? NLM_F_CREATE | NLM_F_REPLACE : 0));
if (r < 0)
return r;
if (nlmsg_type == RTM_NEWNEXTHOP)
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
nhm = NLMSG_DATA((*ret)->hdr);
nhm->nh_family = family;
@@ -311,17 +311,18 @@ int sd_rtnl_message_new_neigh(
assert_return(IN_SET(family, AF_UNSPEC, AF_INET, AF_INET6, AF_BRIDGE), -EINVAL);
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
if (r < 0)
return r;
uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
if (nlmsg_type == RTM_NEWNEIGH) {
if (family == AF_BRIDGE)
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
flags |= NLM_F_CREATE | NLM_F_APPEND;
else
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
flags |= NLM_F_CREATE | NLM_F_REPLACE;
}
r = message_new(rtnl, ret, nlmsg_type, flags);
if (r < 0)
return r;
ndm = NLMSG_DATA((*ret)->hdr);
ndm->ndm_family = family;
@@ -337,15 +338,16 @@ int sd_rtnl_message_new_link(sd_netlink *rtnl, sd_netlink_message **ret, uint16_
assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
if (nlmsg_type == RTM_NEWLINK && ifindex == 0)
flags |= NLM_F_CREATE | NLM_F_EXCL;
else if (nlmsg_type == RTM_NEWLINKPROP)
flags |= NLM_F_CREATE | NLM_F_EXCL | NLM_F_APPEND;
r = message_new(rtnl, ret, nlmsg_type, flags);
if (r < 0)
return r;
if (nlmsg_type == RTM_NEWLINK && ifindex == 0)
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
else if (nlmsg_type == RTM_NEWLINKPROP)
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL | NLM_F_APPEND;
ifi = NLMSG_DATA((*ret)->hdr);
ifi->ifi_family = AF_UNSPEC;
@@ -371,7 +373,7 @@ int sd_rtnl_message_new_addr(
IN_SET(family, AF_INET, AF_INET6), -EINVAL);
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
r = message_new(rtnl, ret, nlmsg_type, NLM_F_REQUEST | NLM_F_ACK);
if (r < 0)
return r;
@@ -439,13 +441,13 @@ int sd_rtnl_message_new_addrlabel(
assert_return(rtnl_message_type_is_addrlabel(nlmsg_type), -EINVAL);
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
r = message_new(rtnl,
ret,
nlmsg_type,
NLM_F_REQUEST | NLM_F_ACK | (nlmsg_type == RTM_NEWADDRLABEL ? NLM_F_CREATE | NLM_F_REPLACE : 0));
if (r < 0)
return r;
if (nlmsg_type == RTM_NEWADDRLABEL)
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
addrlabel = NLMSG_DATA((*ret)->hdr);
addrlabel->ifal_family = family;
@@ -466,13 +468,13 @@ int sd_rtnl_message_new_routing_policy_rule(
assert_return(rtnl_message_type_is_routing_policy_rule(nlmsg_type), -EINVAL);
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
r = message_new(rtnl,
ret,
nlmsg_type,
NLM_F_REQUEST | NLM_F_ACK | (nlmsg_type == RTM_NEWRULE ? NLM_F_CREATE | NLM_F_EXCL : 0));
if (r < 0)
return r;
if (nlmsg_type == RTM_NEWRULE)
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
frh = NLMSG_DATA((*ret)->hdr);
frh->family = family;
@@ -493,13 +495,13 @@ int sd_rtnl_message_new_traffic_control(
assert_return(rtnl_message_type_is_traffic_control(nlmsg_type), -EINVAL);
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
r = message_new(rtnl,
ret,
nlmsg_type,
NLM_F_REQUEST | NLM_F_ACK | (IN_SET(nlmsg_type, RTM_NEWQDISC, RTM_NEWTCLASS) ? NLM_F_CREATE | NLM_F_REPLACE : 0));
if (r < 0)
return r;
if (IN_SET(nlmsg_type, RTM_NEWQDISC, RTM_NEWTCLASS))
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
tcm = NLMSG_DATA((*ret)->hdr);
tcm->tcm_ifindex = ifindex;
tcm->tcm_handle = handle;
@@ -520,13 +522,13 @@ int sd_rtnl_message_new_mdb(
assert_return(rtnl_message_type_is_mdb(nlmsg_type), -EINVAL);
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
r = message_new(rtnl,
ret,
nlmsg_type,
NLM_F_REQUEST | NLM_F_ACK | (nlmsg_type == RTM_NEWMDB ? NLM_F_CREATE | NLM_F_REPLACE : 0));
if (r < 0)
return r;
if (nlmsg_type == RTM_NEWMDB)
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
bpm = NLMSG_DATA((*ret)->hdr);
bpm->family = AF_BRIDGE;
bpm->ifindex = ifindex;
@@ -545,7 +547,7 @@ int sd_rtnl_message_new_nsid(
assert_return(rtnl_message_type_is_nsid(nlmsg_type), -EINVAL);
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
r = message_new(rtnl, ret, nlmsg_type, NLM_F_REQUEST | NLM_F_ACK);
if (r < 0)
return r;
+12 -7
View File
@@ -44,6 +44,7 @@ int message_new_empty(sd_netlink *nl, sd_netlink_message **ret) {
int message_new_full(
sd_netlink *nl,
uint16_t nlmsg_type,
uint16_t nlmsg_flags,
const NLAPolicySet *policy_set,
size_t header_size,
sd_netlink_message **ret) {
@@ -69,7 +70,7 @@ int message_new_full(
if (!m->hdr)
return -ENOMEM;
m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
m->hdr->nlmsg_flags = nlmsg_flags;
m->hdr->nlmsg_len = size;
m->hdr->nlmsg_type = nlmsg_type;
@@ -77,7 +78,7 @@ int message_new_full(
return 0;
}
int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t nlmsg_type) {
int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t nlmsg_type, uint16_t nlmsg_flags) {
const NLAPolicySet *policy_set;
size_t size;
int r;
@@ -85,11 +86,11 @@ int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t nlmsg_type) {
assert_return(nl, -EINVAL);
assert_return(ret, -EINVAL);
r = netlink_get_policy_set_and_header_size(nl, nlmsg_type, &policy_set, &size);
r = netlink_get_policy_set_and_header_size(nl, nlmsg_type, nlmsg_flags, &policy_set, &size);
if (r < 0)
return r;
return message_new_full(nl, nlmsg_type, policy_set, size, ret);
return message_new_full(nl, nlmsg_type, nlmsg_flags, policy_set, size, ret);
}
int message_new_synthetic_error(sd_netlink *nl, int error, uint32_t serial, sd_netlink_message **ret) {
@@ -98,7 +99,7 @@ int message_new_synthetic_error(sd_netlink *nl, int error, uint32_t serial, sd_n
assert(error <= 0);
r = message_new(nl, ret, NLMSG_ERROR);
r = message_new(nl, ret, NLMSG_ERROR, 0);
if (r < 0)
return r;
@@ -1328,8 +1329,12 @@ int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *nl) {
assert(m->hdr);
r = netlink_get_policy_set_and_header_size(nl, m->hdr->nlmsg_type,
&m->containers[0].policy_set, &size);
r = netlink_get_policy_set_and_header_size(
nl,
m->hdr->nlmsg_type,
m->hdr->nlmsg_flags,
&m->containers[0].policy_set,
&size);
if (r < 0)
return r;
+1 -1
View File
@@ -307,7 +307,7 @@ static int parse_message_one(sd_netlink *nl, uint32_t group, const struct nlmsgh
goto finalize;
/* check that we support this message type */
r = netlink_get_policy_set_and_header_size(nl, hdr->nlmsg_type, NULL, &size);
r = netlink_get_policy_set_and_header_size(nl, hdr->nlmsg_type, hdr->nlmsg_flags, NULL, &size);
if (r == -EOPNOTSUPP) {
log_debug("sd-netlink: ignored message with unknown type: %i", hdr->nlmsg_type);
goto finalize;
@@ -51,6 +51,7 @@ const NLAPolicySetUnion *policy_get_policy_set_union(const NLAPolicy *policy) {
int netlink_get_policy_set_and_header_size(
sd_netlink *nl,
uint16_t type,
uint16_t flags,
const NLAPolicySet **ret_policy_set,
size_t *ret_header_size) {
@@ -52,6 +52,7 @@ const NLAPolicySetUnion *policy_get_policy_set_union(const NLAPolicy *policy);
int netlink_get_policy_set_and_header_size(
sd_netlink *nl,
uint16_t type,
uint16_t flags,
const NLAPolicySet **ret_policy_set,
size_t *ret_header_size);