sd-netlink: add sd_netlink_sendv

nftables uses a transaction-based netlink model: one netlink write
comes with multiple messages.

A 'BEGIN' message to tell nf_tables/kernel that a new transaction starts.

Then, one more messages to add/delete tables/chains/rules etc.

Lastly, an END message that commits all changes.

This function will be used to send all the individual messages that should
make up a single transaction as a single write.
This commit is contained in:
Florian Westphal 2020-06-19 14:58:41 +02:00
parent 347ea16797
commit 99c41c0de4
4 changed files with 62 additions and 0 deletions

View File

@ -139,6 +139,7 @@ int socket_bind(sd_netlink *nl);
int socket_broadcast_group_ref(sd_netlink *nl, unsigned group);
int socket_broadcast_group_unref(sd_netlink *nl, unsigned group);
int socket_write_message(sd_netlink *nl, sd_netlink_message *m);
int socket_writev_message(sd_netlink *nl, sd_netlink_message *m[], size_t msgcount);
int socket_read_message(sd_netlink *nl);
int rtnl_rqueue_make_room(sd_netlink *rtnl);

View File

@ -238,6 +238,31 @@ int socket_write_message(sd_netlink *nl, sd_netlink_message *m) {
return k;
}
int socket_writev_message(sd_netlink *nl, sd_netlink_message *m[], size_t msgcount) {
_cleanup_free_ struct iovec *iovs = NULL;
ssize_t k;
size_t i;
assert(nl);
assert(msgcount);
iovs = new0(struct iovec, msgcount);
if (!iovs)
return -ENOMEM;
for (i = 0; i < msgcount; i++) {
assert(m[i]->hdr != NULL);
assert(m[i]->hdr->nlmsg_len > 0);
iovs[i] = IOVEC_MAKE(m[i]->hdr, m[i]->hdr->nlmsg_len);
}
k = writev(nl->fd, iovs, msgcount);
if (k < 0)
return -errno;
return k;
}
static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_group, bool peek) {
union sockaddr_union sender;
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct nl_pktinfo))) control;

View File

@ -226,6 +226,41 @@ int sd_netlink_send(sd_netlink *nl,
return 1;
}
int sd_netlink_sendv(sd_netlink *nl,
sd_netlink_message *messages[],
size_t msgcount,
uint32_t **ret_serial) {
_cleanup_free_ uint32_t *serials = NULL;
unsigned i;
int r;
assert_return(nl, -EINVAL);
assert_return(!rtnl_pid_changed(nl), -ECHILD);
assert_return(messages, -EINVAL);
if (ret_serial) {
serials = new0(uint32_t, msgcount);
if (!serials)
return -ENOMEM;
}
for (i = 0; i < msgcount; i++) {
assert_return(!messages[i]->sealed, -EPERM);
rtnl_seal_message(nl, messages[i]);
if (serials)
serials[i] = rtnl_message_get_serial(messages[i]);
}
r = socket_writev_message(nl, messages, msgcount);
if (r < 0)
return r;
if (ret_serial)
*ret_serial = TAKE_PTR(serials);
return r;
}
int rtnl_rqueue_make_room(sd_netlink *rtnl) {
assert(rtnl);

View File

@ -60,6 +60,7 @@ sd_netlink *sd_netlink_ref(sd_netlink *nl);
sd_netlink *sd_netlink_unref(sd_netlink *nl);
int sd_netlink_send(sd_netlink *nl, sd_netlink_message *message, uint32_t *serial);
int sd_netlink_sendv(sd_netlink *nl, sd_netlink_message *messages[], size_t msgcnt, uint32_t **ret_serial);
int sd_netlink_call_async(sd_netlink *nl, sd_netlink_slot **ret_slot, sd_netlink_message *message,
sd_netlink_message_handler_t callback, sd_netlink_destroy_t destoy_callback,
void *userdata, uint64_t usec, const char *description);