diff mbox

[libnfnl] chain: add netdev family support

Message ID 1434468623-4912-1-git-send-email-pablo@netfilter.org
State Accepted
Delegated to: Pablo Neira
Headers show

Commit Message

Pablo Neira Ayuso June 16, 2015, 3:30 p.m. UTC
Add support for the new NFT_CHAIN_ATTR_DEV attribute that indicates that the
basechain is attached to a net_device.

This partially reworks 1dd9ba1ea23c ("table: add netdev family support").

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/libnftnl/chain.h            |    1 +
 include/libnftnl/table.h            |    1 -
 include/linux/netfilter/nf_tables.h |    4 +--
 src/chain.c                         |   47 +++++++++++++++++++++++++++++++++--
 src/table.c                         |   37 ++-------------------------
 tests/nft-chain-test.c              |    4 +++
 tests/nft-table-test.c              |    9 +++----
 7 files changed, 57 insertions(+), 46 deletions(-)
diff mbox

Patch

diff --git a/include/libnftnl/chain.h b/include/libnftnl/chain.h
index c11cb5e..3968e6b 100644
--- a/include/libnftnl/chain.h
+++ b/include/libnftnl/chain.h
@@ -29,6 +29,7 @@  enum {
 	NFT_CHAIN_ATTR_PACKETS	= 8,
 	NFT_CHAIN_ATTR_HANDLE,
 	NFT_CHAIN_ATTR_TYPE,
+	NFT_CHAIN_ATTR_DEV,
 	__NFT_CHAIN_ATTR_MAX
 };
 #define NFT_CHAIN_ATTR_MAX (__NFT_CHAIN_ATTR_MAX - 1)
diff --git a/include/libnftnl/table.h b/include/libnftnl/table.h
index 16df5fa..fac79e7 100644
--- a/include/libnftnl/table.h
+++ b/include/libnftnl/table.h
@@ -22,7 +22,6 @@  enum {
 	NFT_TABLE_ATTR_FAMILY,
 	NFT_TABLE_ATTR_FLAGS,
 	NFT_TABLE_ATTR_USE,
-	NFT_TABLE_ATTR_DEV,
 	__NFT_TABLE_ATTR_MAX
 };
 #define NFT_TABLE_ATTR_MAX (__NFT_TABLE_ATTR_MAX - 1)
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 89a671e..a99e6a9 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -122,11 +122,13 @@  enum nft_list_attributes {
  *
  * @NFTA_HOOK_HOOKNUM: netfilter hook number (NLA_U32)
  * @NFTA_HOOK_PRIORITY: netfilter hook priority (NLA_U32)
+ * @NFTA_HOOK_DEV: netdevice name (NLA_STRING)
  */
 enum nft_hook_attributes {
 	NFTA_HOOK_UNSPEC,
 	NFTA_HOOK_HOOKNUM,
 	NFTA_HOOK_PRIORITY,
+	NFTA_HOOK_DEV,
 	__NFTA_HOOK_MAX
 };
 #define NFTA_HOOK_MAX		(__NFTA_HOOK_MAX - 1)
@@ -146,14 +148,12 @@  enum nft_table_flags {
  * @NFTA_TABLE_NAME: name of the table (NLA_STRING)
  * @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32)
  * @NFTA_TABLE_USE: number of chains in this table (NLA_U32)
- * @NFTA_TABLE_DEV: net device name (NLA_STRING)
  */
 enum nft_table_attributes {
 	NFTA_TABLE_UNSPEC,
 	NFTA_TABLE_NAME,
 	NFTA_TABLE_FLAGS,
 	NFTA_TABLE_USE,
-	NFTA_TABLE_DEV,
 	__NFTA_TABLE_MAX
 };
 #define NFTA_TABLE_MAX		(__NFTA_TABLE_MAX - 1)
diff --git a/src/chain.c b/src/chain.c
index 74e5925..ed9d9e4 100644
--- a/src/chain.c
+++ b/src/chain.c
@@ -35,6 +35,7 @@  struct nft_chain {
 	char		name[NFT_CHAIN_MAXNAMELEN];
 	const char	*type;
 	const char	*table;
+	const char	*dev;
 	uint32_t	family;
 	uint32_t	policy;
 	uint32_t	hooknum;
@@ -98,6 +99,8 @@  void nft_chain_free(struct nft_chain *c)
 		xfree(c->table);
 	if (c->type != NULL)
 		xfree(c->type);
+	if (c->dev != NULL)
+		xfree(c->dev);
 
 	xfree(c);
 }
@@ -138,6 +141,12 @@  void nft_chain_attr_unset(struct nft_chain *c, uint16_t attr)
 	case NFT_CHAIN_ATTR_HANDLE:
 	case NFT_CHAIN_ATTR_FAMILY:
 		break;
+	case NFT_CHAIN_ATTR_DEV:
+		if (c->dev) {
+			xfree(c->dev);
+			c->dev = NULL;
+		}
+		break;
 	default:
 		return;
 	}
@@ -204,6 +213,12 @@  void nft_chain_attr_set_data(struct nft_chain *c, uint16_t attr,
 
 		c->type = strdup(data);
 		break;
+	case NFT_CHAIN_ATTR_DEV:
+		if (c->dev)
+			xfree(c->dev);
+
+		c->dev = strdup(data);
+		break;
 	}
 	c->flags |= (1 << attr);
 }
@@ -283,6 +298,8 @@  const void *nft_chain_attr_get_data(struct nft_chain *c, uint16_t attr,
 	case NFT_CHAIN_ATTR_TYPE:
 		*data_len = sizeof(uint32_t);
 		return c->type;
+	case NFT_CHAIN_ATTR_DEV:
+		return c->dev;
 	}
 	return NULL;
 }
@@ -358,6 +375,8 @@  void nft_chain_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nft_chain
 		nest = mnl_attr_nest_start(nlh, NFTA_CHAIN_HOOK);
 		mnl_attr_put_u32(nlh, NFTA_HOOK_HOOKNUM, htonl(c->hooknum));
 		mnl_attr_put_u32(nlh, NFTA_HOOK_PRIORITY, htonl(c->prio));
+		if (c->flags & (1 << NFT_CHAIN_ATTR_DEV))
+			mnl_attr_put_strz(nlh, NFTA_HOOK_DEV, c->dev);
 		mnl_attr_nest_end(nlh, nest);
 	}
 	if (c->flags & (1 << NFT_CHAIN_ATTR_POLICY))
@@ -467,6 +486,10 @@  static int nft_chain_parse_hook_cb(const struct nlattr *attr, void *data)
 		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
 			abi_breakage();
 		break;
+	case NFTA_HOOK_DEV:
+		if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
+			abi_breakage();
+		break;
 	}
 
 	tb[type] = attr;
@@ -488,6 +511,10 @@  static int nft_chain_parse_hook(struct nlattr *attr, struct nft_chain *c)
 		c->prio = ntohl(mnl_attr_get_u32(tb[NFTA_HOOK_PRIORITY]));
 		c->flags |= (1 << NFT_CHAIN_ATTR_PRIO);
 	}
+	if (tb[NFTA_HOOK_DEV]) {
+		c->dev = strdup(mnl_attr_get_str(tb[NFTA_HOOK_DEV]));
+		c->flags |= (1 << NFT_CHAIN_ATTR_DEV);
+	}
 
 	return 0;
 }
@@ -563,7 +590,7 @@  int nft_jansson_parse_chain(struct nft_chain *c, json_t *tree,
 	uint64_t handle, bytes, packets;
 	int policy_num;
 	int32_t family, prio, hooknum, use;
-	const char *name, *table, *type, *hooknum_str, *policy;
+	const char *name, *table, *type, *hooknum_str, *policy, *dev;
 
 	root = nft_jansson_get_node(tree, "chain", err);
 	if (root == NULL)
@@ -626,6 +653,10 @@  int nft_jansson_parse_chain(struct nft_chain *c, json_t *tree,
 			nft_chain_attr_set_u32(c, NFT_CHAIN_ATTR_POLICY,
 					       policy_num);
 		}
+
+		dev = nft_jansson_parse_str(root, "device", err);
+		if (dev != NULL)
+			nft_chain_attr_set_str(c, NFT_CHAIN_ATTR_DEV, dev);
 	}
 
 	return 0;
@@ -660,7 +691,7 @@  static int nft_chain_json_parse(struct nft_chain *c, const void *json,
 int nft_mxml_chain_parse(mxml_node_t *tree, struct nft_chain *c,
 			 struct nft_parse_err *err)
 {
-	const char *table, *name, *hooknum_str, *policy_str, *type;
+	const char *table, *name, *hooknum_str, *policy_str, *type, *dev;
 	int family, hooknum, policy;
 	uint64_t handle, bytes, packets, prio, use;
 
@@ -729,6 +760,11 @@  int nft_mxml_chain_parse(mxml_node_t *tree, struct nft_chain *c,
 			nft_chain_attr_set_u32(c, NFT_CHAIN_ATTR_POLICY,
 					       policy);
 		}
+		dev = nft_mxml_str_parse(tree, "device", MXML_DESCEND_FIRST,
+					 NFT_XML_MAND, err);
+
+		if (table != NULL)
+			nft_chain_attr_set_str(c, NFT_CHAIN_ATTR_DEV, dev);
 	}
 
 	return 0;
@@ -824,6 +860,8 @@  static int nft_chain_export(char *buf, size_t size, struct nft_chain *c,
 			nft_buf_s32(&b, type, c->prio, PRIO);
 		if (c->flags & (1 << NFT_CHAIN_ATTR_POLICY))
 			nft_buf_str(&b, type, nft_verdict2str(c->policy), POLICY);
+		if (c->flags & (1 << NFT_CHAIN_ATTR_DEV))
+			nft_buf_str(&b, type, c->dev, DEVICE);
 	}
 
 	nft_buf_close(&b, type, CHAIN);
@@ -848,6 +886,11 @@  static int nft_chain_snprintf_default(char *buf, size_t size,
 			       c->prio, nft_verdict2str(c->policy),
 			       c->packets, c->bytes);
 		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+		if (c->flags & (1 << NFT_CHAIN_ATTR_DEV)) {
+			ret = snprintf(buf+offset, len, " dev %s ", c->dev);
+			SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+		}
 	}
 
 	return offset;
diff --git a/src/table.c b/src/table.c
index f748d6d..ab0a8ea 100644
--- a/src/table.c
+++ b/src/table.c
@@ -32,7 +32,6 @@  struct nft_table {
 	const char	*name;
 	uint32_t	family;
 	uint32_t	table_flags;
-	const char	*dev;
 	uint32_t	use;
 	uint32_t	flags;
 };
@@ -75,12 +74,6 @@  void nft_table_attr_unset(struct nft_table *t, uint16_t attr)
 		break;
 	case NFT_TABLE_ATTR_USE:
 		break;
-	case NFT_TABLE_ATTR_DEV:
-		if (t->dev) {
-			xfree(t->dev);
-			t->dev = NULL;
-		}
-		break;
 	}
 	t->flags &= ~(1 << attr);
 }
@@ -115,12 +108,6 @@  void nft_table_attr_set_data(struct nft_table *t, uint16_t attr,
 	case NFT_TABLE_ATTR_USE:
 		t->use = *((uint32_t *)data);
 		break;
-	case NFT_TABLE_ATTR_DEV:
-		if (t->dev)
-			xfree(t->dev);
-
-		t->dev = strdup(data);
-		break;
 	}
 	t->flags |= (1 << attr);
 }
@@ -168,8 +155,6 @@  const void *nft_table_attr_get_data(struct nft_table *t, uint16_t attr,
 	case NFT_TABLE_ATTR_USE:
 		*data_len = sizeof(uint32_t);
 		return &t->use;
-	case NFT_TABLE_ATTR_DEV:
-		return t->dev;
 	}
 	return NULL;
 }
@@ -208,8 +193,6 @@  void nft_table_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nft_table
 		mnl_attr_put_strz(nlh, NFTA_TABLE_NAME, t->name);
 	if (t->flags & (1 << NFT_TABLE_ATTR_FLAGS))
 		mnl_attr_put_u32(nlh, NFTA_TABLE_FLAGS, htonl(t->table_flags));
-	if (t->flags & (1 << NFT_TABLE_ATTR_DEV))
-		mnl_attr_put_str(nlh, NFTA_TABLE_DEV, t->dev);
 }
 EXPORT_SYMBOL(nft_table_nlmsg_build_payload);
 
@@ -223,7 +206,6 @@  static int nft_table_parse_attr_cb(const struct nlattr *attr, void *data)
 
 	switch(type) {
 	case NFTA_TABLE_NAME:
-	case NFTA_TABLE_DEV:
 		if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
 			abi_breakage();
 		break;
@@ -258,10 +240,6 @@  int nft_table_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_table *t)
 		t->use = ntohl(mnl_attr_get_u32(tb[NFTA_TABLE_USE]));
 		t->flags |= (1 << NFT_TABLE_ATTR_USE);
 	}
-	if (tb[NFTA_TABLE_DEV]) {
-		t->dev = strdup(mnl_attr_get_str(tb[NFTA_TABLE_DEV]));
-		t->flags |= (1 << NFT_TABLE_ATTR_DEV);
-	}
 
 	t->family = nfg->nfgen_family;
 	t->flags |= (1 << NFT_TABLE_ATTR_FAMILY);
@@ -274,7 +252,7 @@  EXPORT_SYMBOL(nft_table_nlmsg_parse);
 int nft_mxml_table_parse(mxml_node_t *tree, struct nft_table *t,
 			 struct nft_parse_err *err)
 {
-	const char *name, *dev;
+	const char *name;
 	int family;
 	uint32_t flags, use;
 
@@ -292,11 +270,6 @@  int nft_mxml_table_parse(mxml_node_t *tree, struct nft_table *t,
 			       &flags, NFT_TYPE_U32, NFT_XML_MAND, err) == 0)
 		nft_table_attr_set_u32(t, NFT_TABLE_ATTR_FLAGS, flags);
 
-	dev = nft_mxml_str_parse(tree, "device", MXML_DESCEND_FIRST,
-				 NFT_XML_MAND, err);
-	if (dev != NULL)
-		nft_table_attr_set_str(t, NFT_TABLE_ATTR_DEV, dev);
-
 	if (nft_mxml_num_parse(tree, "use", MXML_DESCEND, BASE_DEC,
 			       &use, NFT_TYPE_U32, NFT_XML_MAND, err) == 0)
 		nft_table_attr_set_u32(t, NFT_TABLE_ATTR_USE, use);
@@ -330,7 +303,7 @@  int nft_jansson_parse_table(struct nft_table *t, json_t *tree,
 {
 	json_t *root;
 	uint32_t flags, use;
-	const char *str, *dev;
+	const char *str;
 	int family;
 
 	root = nft_jansson_get_node(tree, "table", err);
@@ -348,10 +321,6 @@  int nft_jansson_parse_table(struct nft_table *t, json_t *tree,
 				  err) == 0)
 		nft_table_attr_set_u32(t, NFT_TABLE_ATTR_FLAGS, flags);
 
-	dev = nft_jansson_parse_str(root, "device", err);
-	if (dev != NULL)
-		nft_table_attr_set_str(t, NFT_TABLE_ATTR_DEV, dev);
-
 	if (nft_jansson_parse_val(root, "use", NFT_TYPE_U32, &use, err) == 0)
 		nft_table_attr_set_u32(t, NFT_TABLE_ATTR_USE, use);
 
@@ -435,8 +404,6 @@  static int nft_table_export(char *buf, size_t size, struct nft_table *t,
 		nft_buf_str(&b, type, nft_family2str(t->family), FAMILY);
 	if (t->flags & (1 << NFT_TABLE_ATTR_FLAGS))
 		nft_buf_u32(&b, type, t->table_flags, FLAGS);
-	if (t->flags & (1 << NFT_TABLE_ATTR_DEV))
-		nft_buf_str(&b, type, t->dev, DEVICE);
 	if (t->flags & (1 << NFT_TABLE_ATTR_USE))
 		nft_buf_u32(&b, type, t->use, USE);
 
diff --git a/tests/nft-chain-test.c b/tests/nft-chain-test.c
index 1ff8334..ff8afed 100644
--- a/tests/nft-chain-test.c
+++ b/tests/nft-chain-test.c
@@ -59,6 +59,9 @@  static void cmp_nft_chain(struct nft_chain *a, struct nft_chain *b)
 	if (strcmp(nft_chain_attr_get_str(a, NFT_CHAIN_ATTR_TYPE),
 		   nft_chain_attr_get_str(b, NFT_CHAIN_ATTR_TYPE)) != 0)
 		print_err("Chain type mismatches");
+	if (strcmp(nft_chain_attr_get_str(a, NFT_CHAIN_ATTR_DEV),
+		   nft_chain_attr_get_str(b, NFT_CHAIN_ATTR_DEV)) != 0)
+		print_err("Chain device mismatches");
 }
 
 int main(int argc, char *argv[])
@@ -83,6 +86,7 @@  int main(int argc, char *argv[])
 	nft_chain_attr_set_u64(a, NFT_CHAIN_ATTR_BYTES, 0x1234567812345678);
 	nft_chain_attr_set_u64(a, NFT_CHAIN_ATTR_HANDLE, 0x1234567812345678);
 	nft_chain_attr_set_str(a, NFT_CHAIN_ATTR_TYPE, "Prueba");
+	nft_chain_attr_set_str(a, NFT_CHAIN_ATTR_DEV, "eth0");
 
 	/* cmd extracted from include/linux/netfilter/nf_tables.h */
 	nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, AF_INET,
diff --git a/tests/nft-table-test.c b/tests/nft-table-test.c
index 4714131..2096ea5 100644
--- a/tests/nft-table-test.c
+++ b/tests/nft-table-test.c
@@ -35,27 +35,24 @@  static void cmp_nft_table(struct nft_table *a, struct nft_table *b)
 	if (nft_table_attr_get_u32(a, NFT_TABLE_ATTR_FAMILY) !=
 	    nft_table_attr_get_u32(b, NFT_TABLE_ATTR_FAMILY))
 		print_err("tabke family mismatches");
-	if (strcmp(nft_table_attr_get_str(a, NFT_TABLE_ATTR_DEV),
-		   nft_table_attr_get_str(b, NFT_TABLE_ATTR_DEV)) != 0)
-		print_err("table name mismatches");
 }
 
 int main(int argc, char *argv[])
 {
 	char buf[4096];
 	struct nlmsghdr *nlh;
-	struct nft_table *a;
-	struct nft_table *b;
 
+	struct nft_table *a = NULL;
+	struct nft_table *b = NULL;
 	a = nft_table_alloc();
 	b = nft_table_alloc();
+
 	if (a == NULL || b == NULL)
 		print_err("OOM");
 
 	nft_table_attr_set_str(a, NFT_TABLE_ATTR_NAME, "test");
 	nft_table_attr_set_u32(a, NFT_TABLE_ATTR_FAMILY, AF_INET);
 	nft_table_attr_set_u32(a, NFT_TABLE_ATTR_FLAGS, 0);
-	nft_table_attr_set_str(a, NFT_TABLE_ATTR_DEV, "test");
 
 	/* cmd extracted from include/linux/netfilter/nf_tables.h */
 	nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_NEWTABLE, AF_INET, 0,