summaryrefslogtreecommitdiffstats
path: root/src/mnl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mnl.c')
-rw-r--r--src/mnl.c129
1 files changed, 129 insertions, 0 deletions
diff --git a/src/mnl.c b/src/mnl.c
index 4d60d64b..873d442c 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -630,6 +630,38 @@ int mnl_nft_set_delete(struct mnl_socket *nf_sock, struct nft_set *nls,
return nft_mnl_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL);
}
+int mnl_nft_set_batch_add(struct mnl_socket *nf_sock, struct nft_set *nls,
+ unsigned int flags, uint32_t seqnum)
+{
+ struct nlmsghdr *nlh;
+
+ nlh = nft_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
+ NFT_MSG_NEWSET,
+ nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY),
+ NLM_F_CREATE | flags, seqnum);
+ nft_set_nlmsg_build_payload(nlh, nls);
+ if (!mnl_nlmsg_batch_next(batch))
+ mnl_batch_page_add();
+
+ return 0;
+}
+
+int mnl_nft_set_batch_del(struct mnl_socket *nf_sock, struct nft_set *nls,
+ unsigned int flags, uint32_t seqnum)
+{
+ struct nlmsghdr *nlh;
+
+ nlh = nft_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
+ NFT_MSG_DELSET,
+ nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY),
+ flags, seqnum);
+ nft_set_nlmsg_build_payload(nlh, nls);
+ if (!mnl_nlmsg_batch_next(batch))
+ mnl_batch_page_add();
+
+ return 0;
+}
+
static int set_cb(const struct nlmsghdr *nlh, void *data)
{
struct nft_set_list *nls_list = data;
@@ -742,6 +774,38 @@ static int set_elem_cb(const struct nlmsghdr *nlh, void *data)
return MNL_CB_OK;
}
+int mnl_nft_setelem_batch_add(struct mnl_socket *nf_sock, struct nft_set *nls,
+ unsigned int flags, uint32_t seqnum)
+{
+ struct nlmsghdr *nlh;
+
+ nlh = nft_set_elem_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
+ NFT_MSG_NEWSETELEM,
+ nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY),
+ NLM_F_CREATE | flags, seqnum);
+ nft_set_elems_nlmsg_build_payload(nlh, nls);
+ if (!mnl_nlmsg_batch_next(batch))
+ mnl_batch_page_add();
+
+ return 0;
+}
+
+int mnl_nft_setelem_batch_del(struct mnl_socket *nf_sock, struct nft_set *nls,
+ unsigned int flags, uint32_t seqnum)
+{
+ struct nlmsghdr *nlh;
+
+ nlh = nft_set_elem_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
+ NFT_MSG_DELSETELEM,
+ nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY),
+ 0, seqnum);
+ nft_set_elems_nlmsg_build_payload(nlh, nls);
+ if (!mnl_nlmsg_batch_next(batch))
+ mnl_batch_page_add();
+
+ return 0;
+}
+
int mnl_nft_setelem_get(struct mnl_socket *nf_sock, struct nft_set *nls)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
@@ -823,3 +887,68 @@ int mnl_nft_event_listener(struct mnl_socket *nf_sock,
{
return nft_mnl_recv(nf_sock, 0, 0, cb, cb_data);
}
+
+static void nft_mnl_batch_put(char *buf, uint16_t type, uint32_t seq)
+{
+ struct nlmsghdr *nlh;
+ struct nfgenmsg *nfg;
+
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = type;
+ nlh->nlmsg_flags = NLM_F_REQUEST;
+ nlh->nlmsg_seq = seq;
+
+ nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+ nfg->nfgen_family = AF_INET;
+ nfg->version = NFNETLINK_V0;
+ nfg->res_id = NFNL_SUBSYS_NFTABLES;
+}
+
+bool mnl_batch_supported(struct mnl_socket *nf_sock)
+{
+ struct mnl_nlmsg_batch *b;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ int ret;
+
+ b = mnl_nlmsg_batch_start(buf, sizeof(buf));
+
+ nft_mnl_batch_put(mnl_nlmsg_batch_current(b), NFNL_MSG_BATCH_BEGIN,
+ seq++);
+ mnl_nlmsg_batch_next(b);
+
+ nft_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(b),
+ NFT_MSG_NEWSET, AF_INET,
+ NLM_F_ACK, seq++);
+ mnl_nlmsg_batch_next(b);
+
+ nft_mnl_batch_put(mnl_nlmsg_batch_current(b), NFNL_MSG_BATCH_END,
+ seq++);
+ mnl_nlmsg_batch_next(b);
+
+ ret = mnl_socket_sendto(nf_sock, mnl_nlmsg_batch_head(b),
+ mnl_nlmsg_batch_size(b));
+ if (ret < 0)
+ goto err;
+
+ mnl_nlmsg_batch_stop(b);
+
+ ret = mnl_socket_recvfrom(nf_sock, buf, sizeof(buf));
+ while (ret > 0) {
+ ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(nf_sock),
+ NULL, NULL);
+ if (ret <= 0)
+ break;
+
+ ret = mnl_socket_recvfrom(nf_sock, buf, sizeof(buf));
+ }
+
+ /* We're sending an incomplete message to see if the kernel supports
+ * set messages in batches. EINVAL means that we sent an incomplete
+ * message with missing attributes. The kernel just ignores messages
+ * that we cannot include in the batch.
+ */
+ return (ret == -1 && errno == EINVAL) ? true : false;
+err:
+ mnl_nlmsg_batch_stop(b);
+ return ret;
+}