#include "sd-netlink.h"
#include "alloc-util.h"
-#include "errno-util.h"
#include "iovec-util.h"
#include "netlink-internal.h"
#include "netlink-util.h"
return -ENOMEM;
if (ret_serials) {
- serials = new(uint32_t, n_messages);
+ serials = new(uint32_t, n_messages + 2);
if (!serials)
return -ENOMEM;
}
return r;
netlink_seal_message(nfnl, batch_begin);
+ if (serials)
+ serials[c] = message_get_serial(batch_begin);
+
iovs[c++] = IOVEC_MAKE(batch_begin->hdr, batch_begin->hdr->nlmsg_len);
for (size_t i = 0; i < n_messages; i++) {
netlink_seal_message(nfnl, messages[i]);
if (serials)
- serials[i] = message_get_serial(messages[i]);
+ serials[c] = message_get_serial(messages[i]);
/* It seems that the kernel accepts an arbitrary number. Let's set the lower 16 bits of the
* serial of the first message. */
return r;
netlink_seal_message(nfnl, batch_end);
+ if (serials)
+ serials[c] = message_get_serial(batch_end);
+
iovs[c++] = IOVEC_MAKE(batch_end->hdr, batch_end->hdr->nlmsg_len);
assert(c == n_messages + 2);
if (r < 0)
return r;
- for (size_t i = 0; i < n_messages; i++)
- RET_GATHER(r, sd_netlink_read(nfnl, serials[i], usec, /* ret= */ NULL));
- if (r < 0)
- return r;
+ for (size_t i = 1; i <= n_messages; i++) {
+ /* If we have received an error, kernel may not send replies for later messages. Let's ignore
+ * remaining replies. */
+ if (r < 0) {
+ (void) sd_netlink_ignore_serial(nfnl, serials[i], usec);
+ continue;
+ }
+
+ r = sd_netlink_read(nfnl, serials[i], usec, /* ret= */ NULL);
+ if (r != -ETIMEDOUT)
+ continue;
+
+ /* The kernel returns some errors, e.g. unprivileged, to the BATCH_BEGIN. Hence, if we have
+ * not received any replies for the batch body, try to read an error in the reply for the
+ * batch begin. Note, since v6.10 (bf2ac490d28c21a349e9eef81edc45320fca4a3c), we can expect
+ * that the kernel always replies the batch begin and end. When we bump the kernel baseline,
+ * we can read the reply for the batch begin at first. */
+ int k = sd_netlink_read(nfnl, serials[0], usec, /* ret= */ NULL);
+ if (k < 0)
+ r = k;
+
+ serials[0] = 0; /* indicates that we have read the reply. */
+ }
- return 0;
+ /* Ignore replies for batch begin and end if we have not read them. */
+ if (serials[0] != 0)
+ (void) sd_netlink_ignore_serial(nfnl, serials[0], usec);
+ (void) sd_netlink_ignore_serial(nfnl, serials[n_messages + 1], usec);
+
+ return r;
}
int sd_nfnl_nft_message_new_basechain(