Example #1
0
static int chain_cmd(struct mnl_socket *nl, struct nftnl_chain *chain,
		uint16_t cmd, int family, uint16_t type,
		enum callback_return_type cb_type, uint64_t *cb_val)
{
        char buf[MNL_SOCKET_BUFFER_SIZE];
        struct mnl_nlmsg_batch *batch;
        struct nlmsghdr *nlh;
        uint32_t seq = 0;
        int err;

	bzero(buf, sizeof(buf));

        batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
        nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
        mnl_nlmsg_batch_next(batch);

        nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
					cmd, family, type, seq++);
        nftnl_chain_nlmsg_build_payload(nlh, chain);
	nftnl_chain_free(chain);
        mnl_nlmsg_batch_next(batch);

        nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
        mnl_nlmsg_batch_next(batch);

        err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch),
			mnl_nlmsg_batch_size(batch), cb_type, cb_val);

        mnl_nlmsg_batch_stop(batch);
        return err;
}
Example #2
0
static int table_cmd(struct mnl_socket *nl, struct nftnl_table *t,
		uint16_t cmd, uint16_t family, uint16_t type)
{
        char buf[MNL_SOCKET_BUFFER_SIZE];
        struct mnl_nlmsg_batch *batch;
        struct nlmsghdr *nlh;
        uint32_t seq = 0;
        int err;

	bzero(buf, sizeof(buf));

        batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
        nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
        mnl_nlmsg_batch_next(batch);

        nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
				cmd, family, type, seq++);
        nftnl_table_nlmsg_build_payload(nlh, t);
	nftnl_table_free(t);
        mnl_nlmsg_batch_next(batch);

        nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
        mnl_nlmsg_batch_next(batch);

	/* The current table commands do not support any callback returns. */
        err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch),
				mnl_nlmsg_batch_size(batch), 0, NULL);

        mnl_nlmsg_batch_stop(batch);
        return err;
}
Example #3
0
int nftnl_batch_is_supported(void)
{
	struct mnl_socket *nl;
	struct mnl_nlmsg_batch *b;
	char buf[MNL_SOCKET_BUFFER_SIZE];
	uint32_t seq = time(NULL), req_seq;
	int ret;

	nl = mnl_socket_open(NETLINK_NETFILTER);
	if (nl == NULL)
		return -1;

	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
		return -1;

	b = mnl_nlmsg_batch_start(buf, sizeof(buf));

	nftnl_batch_begin(mnl_nlmsg_batch_current(b), seq++);
	mnl_nlmsg_batch_next(b);

	req_seq = seq;
	nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(b),
				NFT_MSG_NEWSET, AF_INET,
				NLM_F_ACK, seq++);
	mnl_nlmsg_batch_next(b);

	nftnl_batch_end(mnl_nlmsg_batch_current(b), seq++);
	mnl_nlmsg_batch_next(b);

	ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(b),
				mnl_nlmsg_batch_size(b));
	if (ret < 0)
		goto err;

	mnl_nlmsg_batch_stop(b);

	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
	while (ret > 0) {
		ret = mnl_cb_run(buf, ret, req_seq, mnl_socket_get_portid(nl),
				 NULL, NULL);
		if (ret <= 0)
			break;

		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
	}
	mnl_socket_close(nl);

	/* 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) ? 1 : 0;
err:
	mnl_nlmsg_batch_stop(b);
	return -1;
}
Example #4
0
static int rule_cmd(struct mnl_socket *nl, struct nftnl_rule *rule,
			uint16_t cmd, uint16_t family, uint16_t type,
			enum callback_return_type callback_type,
			uint64_t *callback_value)
{

        char buf[MNL_SOCKET_BUFFER_SIZE];
        struct mnl_nlmsg_batch *batch;
        struct nlmsghdr *nlh;
        uint32_t seq = 0;
        int err;

	bzero(buf, sizeof(buf));

	debug_netlink_dump_rule(rule);

        batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
        put_batch_headers(mnl_nlmsg_batch_current(batch),
				NFNL_MSG_BATCH_BEGIN, seq++);
        mnl_nlmsg_batch_next(batch);

        nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
					cmd, family, type, seq++);
        nftnl_rule_nlmsg_build_payload(nlh, rule);
        mnl_nlmsg_batch_next(batch);

        put_batch_headers(mnl_nlmsg_batch_current(batch),
				NFNL_MSG_BATCH_END, seq++);
        mnl_nlmsg_batch_next(batch);

        err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch),
				mnl_nlmsg_batch_size(batch),
				callback_type, callback_value);
        mnl_nlmsg_batch_stop(batch);

        return err;
}
Example #5
0
int main(int argc, char *argv[])
{
	struct mnl_socket *nl;
	char buf[MNL_SOCKET_BUFFER_SIZE];
	struct nlmsghdr *nlh;
	struct mnl_nlmsg_batch *batch;
	uint32_t portid, seq;
	struct nft_rule *r = NULL;
	int ret, family;

	if (argc < 4 || argc > 5) {
		fprintf(stderr, "Usage: %s <family> <table> <chain> [<handle>]\n",
			argv[0]);
		exit(EXIT_FAILURE);
	}

	r = nft_rule_alloc();
	if (r == NULL) {
		perror("OOM");
		exit(EXIT_FAILURE);
	}

	if (strcmp(argv[1], "ip") == 0)
		family = NFPROTO_IPV4;
	else if (strcmp(argv[1], "ip6") == 0)
		family = NFPROTO_IPV6;
	else if (strcmp(argv[1], "bridge") == 0)
		family = NFPROTO_BRIDGE;
	else if (strcmp(argv[1], "arp") == 0)
		family = NFPROTO_ARP;
	else {
		fprintf(stderr, "Unknown family: ip, ip6, bridge, arp\n");
		exit(EXIT_FAILURE);
	}

	seq = time(NULL);
	nft_rule_attr_set(r, NFT_RULE_ATTR_TABLE, argv[2]);
	nft_rule_attr_set(r, NFT_RULE_ATTR_CHAIN, argv[3]);

	/* If no handle is specified, delete all rules in the chain */
	if (argc == 5)
		nft_rule_attr_set_u64(r, NFT_RULE_ATTR_HANDLE, atoi(argv[4]));

	batch = mnl_nlmsg_batch_start(buf, sizeof(buf));

	nft_mnl_batch_put(mnl_nlmsg_batch_current(batch),
			  NFNL_MSG_BATCH_BEGIN, seq++);
	mnl_nlmsg_batch_next(batch);

	nlh = nft_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
				NFT_MSG_DELRULE,
				family,
				NLM_F_ACK, seq++);

	nft_rule_nlmsg_build_payload(nlh, r);
	nft_rule_free(r);
	mnl_nlmsg_batch_next(batch);

	nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_END,
			  seq++);
	mnl_nlmsg_batch_next(batch);

	nl = mnl_socket_open(NETLINK_NETFILTER);
	if (nl == NULL) {
		perror("mnl_socket_open");
		exit(EXIT_FAILURE);
	}

	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
		perror("mnl_socket_bind");
		exit(EXIT_FAILURE);
	}
	portid = mnl_socket_get_portid(nl);

	if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch),
			      mnl_nlmsg_batch_size(batch)) < 0) {
		perror("mnl_socket_send");
		exit(EXIT_FAILURE);
	}

	mnl_nlmsg_batch_stop(batch);

	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
	while (ret > 0) {
		ret = mnl_cb_run(buf, ret, 0, portid, NULL, NULL);
		if (ret <= 0)
			break;
		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
	}
	if (ret == -1) {
		perror("error");
		exit(EXIT_FAILURE);
	}
	mnl_socket_close(nl);

	return EXIT_SUCCESS;
}
Example #6
0
int main(int argc, char *argv[])
{
	struct mnl_socket *nl;
	char buf[MNL_SOCKET_BUFFER_SIZE];
	struct nlmsghdr *nlh;
	uint32_t portid, seq, table_seq, family;
	struct nft_table *t;
	struct mnl_nlmsg_batch *batch;
	int ret, batching;

	if (argc != 3) {
		fprintf(stderr, "%s <family> <name>\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	t = table_add_parse(argc, argv);
	if (t == NULL)
		exit(EXIT_FAILURE);

	batching = nft_batch_is_supported();
	if (batching < 0) {
		perror("cannot talk to nfnetlink");
		exit(EXIT_FAILURE);
	}

	seq = time(NULL);
	batch = mnl_nlmsg_batch_start(buf, sizeof(buf));

	if (batching) {
		nft_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
		mnl_nlmsg_batch_next(batch);
	}

	table_seq = seq;
	family = nft_table_attr_get_u32(t, NFT_TABLE_ATTR_FAMILY);
	nlh = nft_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
					NFT_MSG_NEWTABLE, family,
					NLM_F_ACK, seq++);
	nft_table_nlmsg_build_payload(nlh, t);
	nft_table_free(t);
	mnl_nlmsg_batch_next(batch);

	if (batching) {
		nft_batch_end(mnl_nlmsg_batch_current(batch), seq++);
		mnl_nlmsg_batch_next(batch);
	}

	nl = mnl_socket_open(NETLINK_NETFILTER);
	if (nl == NULL) {
		perror("mnl_socket_open");
		exit(EXIT_FAILURE);
	}

	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
		perror("mnl_socket_bind");
		exit(EXIT_FAILURE);
	}
	portid = mnl_socket_get_portid(nl);

	if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch),
			      mnl_nlmsg_batch_size(batch)) < 0) {
		perror("mnl_socket_send");
		exit(EXIT_FAILURE);
	}

	mnl_nlmsg_batch_stop(batch);

	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
	while (ret > 0) {
		ret = mnl_cb_run(buf, ret, table_seq, portid, NULL, NULL);
		if (ret <= 0)
			break;
		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
	}
	if (ret == -1) {
		perror("error");
		exit(EXIT_FAILURE);
	}
	mnl_socket_close(nl);

	return EXIT_SUCCESS;
}
Example #7
0
int main(int argc, char *argv[])
{
	struct mnl_socket *nl;
	char buf[MNL_SOCKET_BUFFER_SIZE];
	struct nlmsghdr *nlh;
	uint32_t portid, seq, set_seq;
	struct nftnl_set *s;
	int ret, batching;
	uint16_t family, format, outformat;
	struct mnl_nlmsg_batch *batch;

	if (argc < 2) {
		printf("Usage: %s {xml|json} <file>\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	if (strcmp(argv[1], "xml") == 0) {
		format = NFTNL_PARSE_XML;
		outformat = NFTNL_OUTPUT_XML;
	} else if (strcmp(argv[1], "json") == 0) {
		format = NFTNL_PARSE_JSON;
		outformat = NFTNL_OUTPUT_JSON;
	} else {
		printf("Unknown format: xml, json\n");
		exit(EXIT_FAILURE);
	}

	s = set_parse_file(argv[2], format);
	if (s == NULL)
		exit(EXIT_FAILURE);

	nftnl_set_fprintf(stdout, s, outformat, 0);
	fprintf(stdout, "\n");

	seq = time(NULL);
	batching = nftnl_batch_is_supported();
	if (batching < 0) {
		perror("cannot talk to nfnetlink");
		exit(EXIT_FAILURE);
	}

	batch = mnl_nlmsg_batch_start(buf, sizeof(buf));

	if (batching) {
		nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
		mnl_nlmsg_batch_next(batch);
	}

	family = nftnl_set_get_u32(s, NFTNL_SET_FAMILY);

	set_seq = seq;
	nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
				      NFT_MSG_NEWSET, family,
				      NLM_F_CREATE|NLM_F_ACK, seq++);
	nftnl_set_nlmsg_build_payload(nlh, s);
	nftnl_set_free(s);
	mnl_nlmsg_batch_next(batch);

	if (batching) {
		nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
		mnl_nlmsg_batch_next(batch);
	}

	nl = mnl_socket_open(NETLINK_NETFILTER);
	if (nl == NULL) {
		perror("mnl_socket_open");
		exit(EXIT_FAILURE);
	}

	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
		perror("mnl_socket_bind");
		exit(EXIT_FAILURE);
	}
	portid = mnl_socket_get_portid(nl);

	if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch),
			      mnl_nlmsg_batch_size(batch)) < 0) {
		perror("mnl_socket_send");
		exit(EXIT_FAILURE);
	}

	mnl_nlmsg_batch_stop(batch);

	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
	while (ret > 0) {
		ret = mnl_cb_run(buf, ret, set_seq, portid, NULL, NULL);
		if (ret <= 0)
			break;
		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
	}
	if (ret == -1) {
		perror("error");
		exit(EXIT_FAILURE);
	}

	mnl_socket_close(nl);

	return EXIT_SUCCESS;
}
Example #8
0
static void
send_batch(struct mnl_socket *nl, struct mnl_nlmsg_batch *b, int portid)
{
	int ret, fd = mnl_socket_get_fd(nl);
	size_t len = mnl_nlmsg_batch_size(b);
	char rcv_buf[MNL_SOCKET_BUFFER_SIZE];

	ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(b), len);
	if (ret == -1) {
		perror("mnl_socket_recvfrom");
		exit(EXIT_FAILURE);
	}

	/* receive and digest all the acknowledgments from the kernel. */
	struct timeval tv = {
		.tv_sec		= 0,
		.tv_usec	= 0
	};
	fd_set readfds;
	FD_ZERO(&readfds);
	FD_SET(fd, &readfds);

	ret = select(fd+1, &readfds, NULL, NULL, &tv);
	if (ret == -1) {
		perror("select");
		exit(EXIT_FAILURE);
	}
	while (ret > 0 && FD_ISSET(fd, &readfds)) {
		ret = mnl_socket_recvfrom(nl, rcv_buf, sizeof(rcv_buf));
		if (ret == -1) {
			perror("mnl_socket_recvfrom");
			exit(EXIT_FAILURE);
		}

		ret = mnl_cb_run2(rcv_buf, ret, 0, portid,
				  NULL, NULL, cb_ctl_array,
				  MNL_ARRAY_SIZE(cb_ctl_array));
		if (ret == -1) {
			perror("mnl_cb_run");
			exit(EXIT_FAILURE);
		}

		ret = select(fd+1, &readfds, NULL, NULL, &tv);
		if (ret == -1) {
			perror("select");
			exit(EXIT_FAILURE);
		}
		FD_ZERO(&readfds);
		FD_SET(fd, &readfds);
	}
}

int main(void)
{
	struct mnl_socket *nl;
	char snd_buf[MNL_SOCKET_BUFFER_SIZE*2];
	struct mnl_nlmsg_batch *b;
	int j;
	unsigned int seq, portid;
	uint16_t i;

	nl = mnl_socket_open(NETLINK_NETFILTER);
	if (nl == NULL) {
		perror("mnl_socket_open");
		exit(EXIT_FAILURE);
	}
	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
		perror("mnl_socket_bind");
		exit(EXIT_FAILURE);
	}
	portid = mnl_socket_get_portid(nl);

	/* The buffer that we use to batch messages is MNL_SOCKET_BUFFER_SIZE
	 * multiplied by 2 bytes long, but we limit the batch to half of it
	 * since the last message that does not fit the batch goes over the
	 * upper boundary, if you break this rule, expect memory corruptions. */
	b = mnl_nlmsg_batch_start(snd_buf, MNL_SOCKET_BUFFER_SIZE);
	if (b == NULL) {
		perror("mnl_nlmsg_batch_start");
		exit(EXIT_FAILURE);
	}

	seq = time(NULL);
	for (i=1024, j=0; i<65535; i++, j++) {
		put_msg(mnl_nlmsg_batch_current(b), i, seq+j);

		/* is there room for more messages in this batch?
		 * if so, continue. */
		if (mnl_nlmsg_batch_next(b))
			continue;

		send_batch(nl, b, portid);

		/* this moves the last message that did not fit into the
		 * batch to the head of it. */
		mnl_nlmsg_batch_reset(b);
	}

	/* check if there is any message in the batch not sent yet. */
	if (!mnl_nlmsg_batch_is_empty(b))
		send_batch(nl, b, portid);

	mnl_nlmsg_batch_stop(b);
	mnl_socket_close(nl);

	return 0;
}
Example #9
0
int main(int argc, char *argv[])
{
	struct mnl_socket *nl;
	struct nftnl_rule *r;
	struct nlmsghdr *nlh;
	struct mnl_nlmsg_batch *batch;
	uint8_t family;
	char buf[MNL_SOCKET_BUFFER_SIZE];
	uint32_t seq = time(NULL);
	int ret;

	if (argc < 4 || argc > 5) {
		fprintf(stderr, "Usage: %s <family> <table> <chain>\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	if (strcmp(argv[1], "ip") == 0)
		family = NFPROTO_IPV4;
	else if (strcmp(argv[1], "ip6") == 0)
		family = NFPROTO_IPV6;
	else {
		fprintf(stderr, "Unknown family: ip, ip6\n");
		exit(EXIT_FAILURE);
	}

	if (argc != 5)
		r = setup_rule(family, argv[2], argv[3], NULL);
	else
		r = setup_rule(family, argv[2], argv[3], argv[4]);

	nl = mnl_socket_open(NETLINK_NETFILTER);
	if (nl == NULL) {
		perror("mnl_socket_open");
		exit(EXIT_FAILURE);
	}

	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
		perror("mnl_socket_bind");
		exit(EXIT_FAILURE);
	}

	batch = mnl_nlmsg_batch_start(buf, sizeof(buf));

	nftnl_mnl_batch_put(mnl_nlmsg_batch_current(batch),
			  NFNL_MSG_BATCH_BEGIN, seq++);
	mnl_nlmsg_batch_next(batch);

	nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
			NFT_MSG_NEWRULE,
			nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY),
			NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK, seq++);

	nftnl_rule_nlmsg_build_payload(nlh, r);
	nftnl_rule_free(r);
	mnl_nlmsg_batch_next(batch);

	nftnl_mnl_batch_put(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_END,
			 seq++);
	mnl_nlmsg_batch_next(batch);

	ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch),
				mnl_nlmsg_batch_size(batch));
	if (ret == -1) {
		perror("mnl_socket_sendto");
		exit(EXIT_FAILURE);
	}

	mnl_nlmsg_batch_stop(batch);

	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
	if (ret == -1) {
		perror("mnl_socket_recvfrom");
		exit(EXIT_FAILURE);
	}

	ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(nl), NULL, NULL);
	if (ret < 0) {
		perror("mnl_cb_run");
		exit(EXIT_FAILURE);
	}

	mnl_socket_close(nl);

	return EXIT_SUCCESS;
}
Example #10
0
int main(int argc, char *argv[])
{
	struct mnl_socket *nl;
	struct mnl_nlmsg_batch *batch;
	char buf[MNL_SOCKET_BUFFER_SIZE];
	struct nlmsghdr *nlh;
	uint32_t portid, seq, chain_seq;
	struct nft_chain *t;
	int ret, family, batching;

	if (argc != 4) {
		fprintf(stderr, "Usage: %s <family> <table> <chain>\n",
			argv[0]);
		exit(EXIT_FAILURE);
	}

	if (strcmp(argv[1], "ip") == 0)
		family = NFPROTO_IPV4;
	else if (strcmp(argv[1], "ip6") == 0)
		family = NFPROTO_IPV6;
	else if (strcmp(argv[1], "bridge") == 0)
		family = NFPROTO_BRIDGE;
	else if (strcmp(argv[1], "arp") == 0)
		family = NFPROTO_ARP;
	else {
		fprintf(stderr, "Unknown family: ip, ip6, bridge, arp\n");
		exit(EXIT_FAILURE);
	}

	t = chain_del_parse(argc, argv);
	if (t == NULL)
		exit(EXIT_FAILURE);

	batching = nft_batch_is_supported();
	if (batching < 0) {
		perror("cannot talk to nfnetlink");
		exit(EXIT_FAILURE);
	}

	seq = time(NULL);
	batch = mnl_nlmsg_batch_start(buf, sizeof(buf));

	if (batching) {
		nft_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
		mnl_nlmsg_batch_next(batch);
	}

	chain_seq = seq;
	nlh = nft_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
					NFT_MSG_DELCHAIN, family,
					NLM_F_ACK, seq++);
	nft_chain_nlmsg_build_payload(nlh, t);
	nft_chain_free(t);
	mnl_nlmsg_batch_next(batch);

	if (batching) {
		nft_batch_end(mnl_nlmsg_batch_current(batch), seq++);
		mnl_nlmsg_batch_next(batch);
	}

	nl = mnl_socket_open(NETLINK_NETFILTER);
	if (nl == NULL) {
		perror("mnl_socket_open");
		exit(EXIT_FAILURE);
	}

	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
		perror("mnl_socket_bind");
		exit(EXIT_FAILURE);
	}
	portid = mnl_socket_get_portid(nl);

	if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch),
			      mnl_nlmsg_batch_size(batch)) < 0) {
		perror("mnl_socket_send");
		exit(EXIT_FAILURE);
	}

	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
	while (ret > 0) {
		ret = mnl_cb_run(buf, ret, chain_seq, portid, NULL, NULL);
		if (ret <= 0)
			break;
		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
	}
	if (ret == -1) {
		perror("error");
		exit(EXIT_FAILURE);
	}
	mnl_socket_close(nl);

	return EXIT_SUCCESS;
}