[PATCH nft] src: initial extended netlink error reporting

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch correlates the in-kernel extended netlink error offset and
the location information.

Assuming 'foo' table does not exists, then error reporting shows:

 # nft delete table foo
 Error: Could not process rule: No such file or directory
 delete table foo
              ^^^

Similarly, if table uniquely identified by handle '1234' does not exist,
then error reporting shows:

 # nft delete table handle 1234
 Error: Could not process rule: No such file or directory
 delete table handle 1234
                     ^^^^

 Assuming 'bar' chain does not exists in the kernel, while 'foo' does:

 # nft delete chain foo bar
 Error: Could not process rule: No such file or directory
 delete chain foo bar
                  ^^^

This is based on ("src: basic support for extended netlink errors") from
Florian Westphal, posted in 2018, with no netlink offset correlation
support.

Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>
---
 include/mnl.h     |  11 ++--
 include/netlink.h |  20 ++++++
 include/rule.h    |   9 +++
 src/libnftables.c |  23 ++++++-
 src/mnl.c         | 180 +++++++++++++++++++++++++++++++++++++++++-------------
 src/monitor.c     |   3 +-
 src/rule.c        |   8 +++
 7 files changed, 202 insertions(+), 52 deletions(-)

diff --git a/include/mnl.h b/include/mnl.h
index eeba7379706f..2df67c2e9718 100644
--- a/include/mnl.h
+++ b/include/mnl.h
@@ -16,6 +16,7 @@ struct mnl_err {
 	struct list_head	head;
 	int			err;
 	uint32_t		seqnum;
+	uint32_t		offset;
 };
 
 void mnl_err_list_free(struct mnl_err *err);
@@ -38,7 +39,7 @@ struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx,
 
 int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd,
 		      unsigned int flags);
-int mnl_nft_chain_del(struct netlink_ctx *ctx, const struct cmd *cmd);
+int mnl_nft_chain_del(struct netlink_ctx *ctx, struct cmd *cmd);
 int mnl_nft_chain_rename(struct netlink_ctx *ctx, const struct cmd *cmd,
 			 const struct chain *chain);
 
@@ -47,14 +48,14 @@ struct nftnl_chain_list *mnl_nft_chain_dump(struct netlink_ctx *ctx,
 
 int mnl_nft_table_add(struct netlink_ctx *ctx, const struct cmd *cmd,
 		      unsigned int flags);
-int mnl_nft_table_del(struct netlink_ctx *ctx, const struct cmd *cmd);
+int mnl_nft_table_del(struct netlink_ctx *ctx, struct cmd *cmd);
 
 struct nftnl_table_list *mnl_nft_table_dump(struct netlink_ctx *ctx,
 					    int family);
 
 int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
 		    unsigned int flags);
-int mnl_nft_set_del(struct netlink_ctx *ctx, const struct cmd *cmd);
+int mnl_nft_set_del(struct netlink_ctx *ctx, struct cmd *cmd);
 
 struct nftnl_set_list *mnl_nft_set_dump(struct netlink_ctx *ctx, int family,
 					const char *table);
@@ -73,14 +74,14 @@ struct nftnl_obj_list *mnl_nft_obj_dump(struct netlink_ctx *ctx, int family,
 					bool dump, bool reset);
 int mnl_nft_obj_add(struct netlink_ctx *ctx, const struct cmd *cmd,
 		    unsigned int flags);
-int mnl_nft_obj_del(struct netlink_ctx *ctx, const struct cmd *cmd, int type);
+int mnl_nft_obj_del(struct netlink_ctx *ctx, struct cmd *cmd, int type);
 
 struct nftnl_flowtable_list *
 mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, const char *table);
 
 int mnl_nft_flowtable_add(struct netlink_ctx *ctx, const struct cmd *cmd,
 			  unsigned int flags);
-int mnl_nft_flowtable_del(struct netlink_ctx *ctx, const struct cmd *cmd);
+int mnl_nft_flowtable_del(struct netlink_ctx *ctx, struct cmd *cmd);
 
 int mnl_nft_event_listener(struct mnl_socket *nf_sock, unsigned int debug_mask,
 			   struct output_ctx *octx,
diff --git a/include/netlink.h b/include/netlink.h
index d02533ec4430..c2eb89498d72 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -16,6 +16,22 @@
 
 #define MAX_REGS	(1 + NFT_REG32_15 - NFT_REG32_00)
 
+#ifndef NETLINK_EXT_ACK
+#define NETLINK_EXT_ACK                 11
+
+enum nlmsgerr_attrs {
+	NLMSGERR_ATTR_UNUSED,
+	NLMSGERR_ATTR_MSG,
+	NLMSGERR_ATTR_OFFS,
+	NLMSGERR_ATTR_COOKIE,
+
+	__NLMSGERR_ATTR_MAX,
+	NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
+};
+#define NLM_F_CAPPED	0x100	/* request was capped */
+#define NLM_F_ACK_TLVS	0x200	/* extended ACK TVLs were included */
+#endif
+
 struct netlink_parse_ctx {
 	struct list_head	*msgs;
 	struct table		*table;
@@ -176,6 +192,10 @@ struct netlink_mon_handler {
 
 extern int netlink_monitor(struct netlink_mon_handler *monhandler,
 			    struct mnl_socket *nf_sock);
+struct netlink_cb_data {
+	struct netlink_ctx	*nl_ctx;
+	struct list_head	*err_list;
+};
 int netlink_echo_callback(const struct nlmsghdr *nlh, void *data);
 
 struct ruleset_parse {
diff --git a/include/rule.h b/include/rule.h
index c232221e541b..ced63f3ea1b8 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -635,6 +635,8 @@ struct monitor {
 struct monitor *monitor_alloc(uint32_t format, uint32_t type, const char *event);
 void monitor_free(struct monitor *m);
 
+#define NFT_NLATTR_LOC_MAX 8
+
 /**
  * struct cmd - command statement
  *
@@ -666,6 +668,11 @@ struct cmd {
 		struct markup	*markup;
 		struct obj	*object;
 	};
+	struct {
+		uint16_t	offset;
+		struct location	*location;
+	} attr[NFT_NLATTR_LOC_MAX];
+	int			num_attrs;
 	const void		*arg;
 };
 
@@ -678,6 +685,8 @@ extern struct cmd *cmd_alloc_obj_ct(enum cmd_ops op, int type,
 				    const struct location *loc, struct obj *obj);
 extern void cmd_free(struct cmd *cmd);
 
+void cmd_add_loc(struct cmd *cmd, uint16_t offset, struct location *loc);
+
 #include <payload.h>
 #include <expression.h>
 
diff --git a/src/libnftables.c b/src/libnftables.c
index cd2fcf2fd522..eaa4736c397d 100644
--- a/src/libnftables.c
+++ b/src/libnftables.c
@@ -17,6 +17,25 @@
 #include <stdlib.h>
 #include <string.h>
 
+static void nft_error(struct netlink_ctx *ctx, struct cmd *cmd,
+		      struct mnl_err *err)
+{
+	struct location *loc = NULL;
+	int i;
+
+	for (i = 0; i < cmd->num_attrs; i++) {
+		if (!cmd->attr[i].offset)
+			break;
+		if (cmd->attr[i].offset == err->offset)
+			loc = cmd->attr[i].location;
+	}
+	if (!loc)
+		loc = &cmd->location;
+
+	netlink_io_error(ctx, loc, "Could not process rule: %s",
+			 strerror(err->err));
+}
+
 static int nft_netlink(struct nft_ctx *nft,
 		       struct list_head *cmds, struct list_head *msgs,
 		       struct mnl_socket *nf_sock)
@@ -68,9 +87,7 @@ static int nft_netlink(struct nft_ctx *nft,
 		list_for_each_entry(cmd, cmds, list) {
 			if (err->seqnum == cmd->seqnum ||
 			    err->seqnum == batch_seqnum) {
-				netlink_io_error(&ctx, &cmd->location,
-						 "Could not process rule: %s",
-						 strerror(err->err));
+				nft_error(&ctx, cmd, err);
 				errno = err->err;
 				if (err->seqnum == cmd->seqnum) {
 					mnl_err_list_free(err);
diff --git a/src/mnl.c b/src/mnl.c
index 340380ba6fef..d3518688b53b 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -37,6 +37,7 @@
 struct mnl_socket *nft_mnl_socket_open(void)
 {
 	struct mnl_socket *nf_sock;
+	int one = 1;
 
 	nf_sock = mnl_socket_open(NETLINK_NETFILTER);
 	if (!nf_sock)
@@ -45,6 +46,8 @@ struct mnl_socket *nft_mnl_socket_open(void)
 	if (fcntl(mnl_socket_get_fd(nf_sock), F_SETFL, O_NONBLOCK))
 		netlink_init_error();
 
+	mnl_socket_setsockopt(nf_sock, NETLINK_EXT_ACK, &one, sizeof(one));
+
 	return nf_sock;
 }
 
@@ -204,11 +207,13 @@ void mnl_batch_reset(struct nftnl_batch *batch)
 }
 
 static void mnl_err_list_node_add(struct list_head *err_list, int error,
-				  int seqnum)
+				  int seqnum, uint32_t offset,
+				  const char *errmsg)
 {
 	struct mnl_err *err = xmalloc(sizeof(struct mnl_err));
 
 	err->seqnum = seqnum;
+	err->offset = offset;
 	err->err = error;
 	list_add_tail(&err->head, err_list);
 }
@@ -305,6 +310,61 @@ static ssize_t mnl_nft_socket_sendmsg(struct netlink_ctx *ctx,
 	return sendmsg(mnl_socket_get_fd(ctx->nft->nf_sock), msg, 0);
 }
 
+static int err_attr_cb(const struct nlattr *attr, void *data)
+{
+	const struct nlattr **tb = data;
+	uint16_t type;
+
+	if (mnl_attr_type_valid(attr, NLMSGERR_ATTR_MAX) < 0)
+		return MNL_CB_ERROR;
+
+	type = mnl_attr_get_type(attr);
+	switch (type) {
+	case NLMSGERR_ATTR_OFFS:
+		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+			return MNL_CB_ERROR;
+		break;
+	}
+
+	tb[type] = attr;
+	return MNL_CB_OK;
+}
+
+static int mnl_batch_extack_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct netlink_cb_data *cb_data = data;
+	struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
+	const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
+	unsigned int hlen = sizeof(*err);
+	const char *msg = NULL;
+	uint32_t off = 0;
+	int errval;
+
+	if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr)))
+		return MNL_CB_ERROR;
+
+	if (err->error < 0)
+		errval = -err->error;
+	else
+		errval = err->error;
+
+	if (errval == 0)
+		return MNL_CB_STOP;
+
+	if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
+		hlen += mnl_nlmsg_get_payload_len(&err->msg);
+
+	if (mnl_attr_parse(nlh, hlen, err_attr_cb, tb) != MNL_CB_OK)
+		return MNL_CB_ERROR;
+
+	if (tb[NLMSGERR_ATTR_OFFS])
+		off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]);
+
+	mnl_err_list_node_add(cb_data->err_list, errval,
+			      nlh->nlmsg_seq, off, msg);
+	return MNL_CB_ERROR;
+}
+
 #define NFT_MNL_ECHO_RCVBUFF_DEFAULT	(MNL_SOCKET_BUFFER_SIZE * 1024)
 
 int mnl_batch_talk(struct netlink_ctx *ctx, struct list_head *err_list,
@@ -326,6 +386,13 @@ int mnl_batch_talk(struct netlink_ctx *ctx, struct list_head *err_list,
 	unsigned int rcvbufsiz;
 	size_t batch_size;
 	fd_set readfds;
+	static mnl_cb_t cb_ctl_array[NLMSG_MIN_TYPE] = {
+	        [NLMSG_ERROR] = mnl_batch_extack_cb,
+	};
+	struct netlink_cb_data cb_data = {
+		.err_list = err_list,
+		.nl_ctx = ctx,
+	};
 
 	mnl_set_sndbuffer(ctx->nft->nf_sock, ctx->batch);
 
@@ -361,13 +428,10 @@ int mnl_batch_talk(struct netlink_ctx *ctx, struct list_head *err_list,
 		if (ret == -1)
 			return -1;
 
-		ret = mnl_cb_run(rcv_buf, ret, 0, portid, &netlink_echo_callback, ctx);
 		/* Continue on error, make sure we get all acknowledgments */
-		if (ret == -1) {
-			struct nlmsghdr *nlh = (struct nlmsghdr *)rcv_buf;
-
-			mnl_err_list_node_add(err_list, errno, nlh->nlmsg_seq);
-		}
+		ret = mnl_cb_run2(rcv_buf, ret, 0, portid,
+				  netlink_echo_callback, &cb_data,
+				  cb_ctl_array, MNL_ARRAY_SIZE(cb_ctl_array));
 	}
 	return 0;
 }
@@ -624,7 +688,7 @@ int mnl_nft_chain_rename(struct netlink_ctx *ctx, const struct cmd *cmd,
 	return 0;
 }
 
-int mnl_nft_chain_del(struct netlink_ctx *ctx, const struct cmd *cmd)
+int mnl_nft_chain_del(struct netlink_ctx *ctx, struct cmd *cmd)
 {
 	struct nftnl_chain *nlc;
 	struct nlmsghdr *nlh;
@@ -634,18 +698,23 @@ int mnl_nft_chain_del(struct netlink_ctx *ctx, const struct cmd *cmd)
 		memory_allocation_error();
 
 	nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FAMILY, cmd->handle.family);
-	nftnl_chain_set_str(nlc, NFTNL_CHAIN_TABLE, cmd->handle.table.name);
-	if (cmd->handle.chain.name)
-		nftnl_chain_set_str(nlc, NFTNL_CHAIN_NAME,
-				    cmd->handle.chain.name);
-	else if (cmd->handle.handle.id)
-		nftnl_chain_set_u64(nlc, NFTNL_CHAIN_HANDLE,
-				    cmd->handle.handle.id);
 
 	nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
 				    NFT_MSG_DELCHAIN,
 				    cmd->handle.family,
 				    0, ctx->seqnum);
+
+	cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+	mnl_attr_put_strz(nlh, NFTA_CHAIN_TABLE, cmd->handle.table.name);
+	if (cmd->handle.chain.name) {
+		cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.chain.location);
+		mnl_attr_put_strz(nlh, NFTA_CHAIN_NAME, cmd->handle.chain.name);
+	} else if (cmd->handle.handle.id) {
+		cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+		mnl_attr_put_u64(nlh, NFTA_CHAIN_HANDLE,
+				 htobe64(cmd->handle.handle.id));
+	}
+
 	nftnl_chain_nlmsg_build_payload(nlh, nlc);
 	nftnl_chain_free(nlc);
 
@@ -734,7 +803,7 @@ int mnl_nft_table_add(struct netlink_ctx *ctx, const struct cmd *cmd,
 	return 0;
 }
 
-int mnl_nft_table_del(struct netlink_ctx *ctx, const struct cmd *cmd)
+int mnl_nft_table_del(struct netlink_ctx *ctx, struct cmd *cmd)
 {
 	struct nftnl_table *nlt;
 	struct nlmsghdr *nlh;
@@ -744,17 +813,20 @@ int mnl_nft_table_del(struct netlink_ctx *ctx, const struct cmd *cmd)
 		memory_allocation_error();
 
 	nftnl_table_set_u32(nlt, NFTNL_TABLE_FAMILY, cmd->handle.family);
-	if (cmd->handle.table.name)
-		nftnl_table_set_str(nlt, NFTNL_TABLE_NAME,
-				    cmd->handle.table.name);
-	else if (cmd->handle.handle.id)
-		nftnl_table_set_u64(nlt, NFTNL_TABLE_HANDLE,
-				    cmd->handle.handle.id);
 
 	nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
 				    NFT_MSG_DELTABLE,
 				    cmd->handle.family,
 				    0, ctx->seqnum);
+
+	if (cmd->handle.table.name) {
+		cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+		mnl_attr_put_strz(nlh, NFTA_TABLE_NAME, cmd->handle.table.name);
+	} else if (cmd->handle.handle.id) {
+		cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+		mnl_attr_put_u64(nlh, NFTA_TABLE_NAME,
+				 htobe64(cmd->handle.handle.id));
+	}
 	nftnl_table_nlmsg_build_payload(nlh, nlt);
 	nftnl_table_free(nlt);
 
@@ -930,7 +1002,7 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
 	return 0;
 }
 
-int mnl_nft_set_del(struct netlink_ctx *ctx, const struct cmd *cmd)
+int mnl_nft_set_del(struct netlink_ctx *ctx, struct cmd *cmd)
 {
 	const struct handle *h = &cmd->handle;
 	struct nftnl_set *nls;
@@ -941,16 +1013,23 @@ int mnl_nft_set_del(struct netlink_ctx *ctx, const struct cmd *cmd)
 		memory_allocation_error();
 
 	nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family);
-	nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name);
-	if (h->set.name)
-		nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name);
-	else if (h->handle.id)
-		nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id);
 
 	nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
 				    NFT_MSG_DELSET,
 				    h->family,
 				    0, ctx->seqnum);
+
+	cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+	mnl_attr_put_strz(nlh, NFTA_SET_TABLE, cmd->handle.table.name);
+	if (h->set.name) {
+		cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.set.location);
+		mnl_attr_put_strz(nlh, NFTA_SET_NAME, cmd->handle.set.name);
+	} else if (h->handle.id) {
+		cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+		mnl_attr_put_u64(nlh, NFTA_SET_HANDLE,
+				 htobe64(cmd->handle.handle.id));
+	}
+
 	nftnl_set_nlmsg_build_payload(nlh, nls);
 	nftnl_set_free(nls);
 
@@ -1115,7 +1194,7 @@ int mnl_nft_obj_add(struct netlink_ctx *ctx, const struct cmd *cmd,
 	return 0;
 }
 
-int mnl_nft_obj_del(struct netlink_ctx *ctx, const struct cmd *cmd, int type)
+int mnl_nft_obj_del(struct netlink_ctx *ctx, struct cmd *cmd, int type)
 {
 	struct nftnl_obj *nlo;
 	struct nlmsghdr *nlh;
@@ -1125,16 +1204,24 @@ int mnl_nft_obj_del(struct netlink_ctx *ctx, const struct cmd *cmd, int type)
 		memory_allocation_error();
 
 	nftnl_obj_set_u32(nlo, NFTNL_OBJ_FAMILY, cmd->handle.family);
-	nftnl_obj_set_str(nlo, NFTNL_OBJ_TABLE, cmd->handle.table.name);
 	nftnl_obj_set_u32(nlo, NFTNL_OBJ_TYPE, type);
-	if (cmd->handle.obj.name)
-		nftnl_obj_set_str(nlo, NFTNL_OBJ_NAME, cmd->handle.obj.name);
-	else if (cmd->handle.handle.id)
-		nftnl_obj_set_u64(nlo, NFTNL_OBJ_HANDLE, cmd->handle.handle.id);
 
 	nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
 				    NFT_MSG_DELOBJ, cmd->handle.family,
 				    0, ctx->seqnum);
+
+	cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+	mnl_attr_put_strz(nlh, NFTA_OBJ_TABLE, cmd->handle.table.name);
+
+	if (cmd->handle.obj.name) {
+		cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.obj.location);
+		mnl_attr_put_strz(nlh, NFTA_OBJ_NAME, cmd->handle.obj.name);
+	} else if (cmd->handle.handle.id) {
+		cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+		mnl_attr_put_u64(nlh, NFTA_OBJ_HANDLE,
+				 htobe64(cmd->handle.handle.id));
+	}
+
 	nftnl_obj_nlmsg_build_payload(nlh, nlo);
 	nftnl_obj_free(nlo);
 
@@ -1493,7 +1580,7 @@ int mnl_nft_flowtable_add(struct netlink_ctx *ctx, const struct cmd *cmd,
 	return 0;
 }
 
-int mnl_nft_flowtable_del(struct netlink_ctx *ctx, const struct cmd *cmd)
+int mnl_nft_flowtable_del(struct netlink_ctx *ctx, struct cmd *cmd)
 {
 	struct nftnl_flowtable *flo;
 	struct nlmsghdr *nlh;
@@ -1504,18 +1591,25 @@ int mnl_nft_flowtable_del(struct netlink_ctx *ctx, const struct cmd *cmd)
 
 	nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FAMILY,
 				cmd->handle.family);
-	nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_TABLE,
-				cmd->handle.table.name);
-	if (cmd->handle.flowtable.name)
-		nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_NAME,
-					cmd->handle.flowtable.name);
-	else if (cmd->handle.handle.id)
-		nftnl_flowtable_set_u64(flo, NFTNL_FLOWTABLE_HANDLE,
-				        cmd->handle.handle.id);
 
 	nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
 				    NFT_MSG_DELFLOWTABLE, cmd->handle.family,
 				    0, ctx->seqnum);
+
+	cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+	mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_TABLE, cmd->handle.table.name);
+
+	if (cmd->handle.flowtable.name) {
+		cmd_add_loc(cmd, nlh->nlmsg_len,
+			    &cmd->handle.flowtable.location);
+		mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_NAME,
+				  cmd->handle.flowtable.name);
+	} else if (cmd->handle.handle.id) {
+		cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+		mnl_attr_put_u64(nlh, NFTA_FLOWTABLE_HANDLE,
+				 htobe64(cmd->handle.handle.id));
+	}
+
 	nftnl_flowtable_nlmsg_build_payload(nlh, flo);
 	nftnl_flowtable_free(flo);
 
diff --git a/src/monitor.c b/src/monitor.c
index 142cc929664f..bb269c02950c 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -906,7 +906,8 @@ static int netlink_events_cb(const struct nlmsghdr *nlh, void *data)
 
 int netlink_echo_callback(const struct nlmsghdr *nlh, void *data)
 {
-	struct netlink_ctx *ctx = data;
+	struct netlink_cb_data *nl_cb_data = data;
+	struct netlink_ctx *ctx = nl_cb_data->nl_ctx;
 	struct netlink_mon_handler echo_monh = {
 		.format = NFTNL_OUTPUT_DEFAULT,
 		.ctx = ctx,
diff --git a/src/rule.c b/src/rule.c
index 337a66bbd5fa..9307dad54b6f 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -1377,6 +1377,14 @@ struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj,
 	return cmd;
 }
 
+void cmd_add_loc(struct cmd *cmd, uint16_t offset, struct location *loc)
+{
+	assert(cmd->num_attrs < NFT_NLATTR_LOC_MAX);
+	cmd->attr[cmd->num_attrs].offset = offset;
+	cmd->attr[cmd->num_attrs].location = loc;
+	cmd->num_attrs++;
+}
+
 void nft_cmd_expand(struct cmd *cmd)
 {
 	struct list_head new_cmds;
-- 
2.11.0




[Index of Archives]     [Netfitler Users]     [Berkeley Packet Filter]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux