Skip to contentSkip to conversation

add insert after to nf_tables

RFC PATCH In review Eric Leblond 4 participants 40 messages Jun 19, 2013 – Jul 19, 2013

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover add insert after to nf_tables

Hello,

The patch
netfilter: nf_tables: add insert operation
adds support for inserting a rule after a handle.

It is followed by the patch
examples: add insert rule example
which is the libnftables example.

I choose to reuse the CREATE operation in the kernel code to avoid to add a new message to netlink. This way we have a sort of 'create after' syntax. This is almost natural IMHO.

BR,
--
Eric

#1 lore raw

PATCH 1/1 netfilter: nf_tables: add insert operation

By providing a create command and specifying an handle, the rule is inserted after the rule with the provided handle.

---
 net/netfilter/nf_tables_api.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)
net/netfilter/nf_tables_api.c +10 -3
index cfe0c58..4f3e112 100644
@@ -1563,7 +1563,10 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 			return -EEXIST;
 		if (nlh->nlmsg_flags & NLM_F_REPLACE)
 			old_rule = rule;
-		else
+		else if (nlh->nlmsg_flags & NLM_F_CREATE) {
+			old_rule = rule;
+			handle = nf_tables_alloc_handle(table);
+		} else
 			return -EOPNOTSUPP;
 	} else {
 		if (!create || nlh->nlmsg_flags & NLM_F_REPLACE)
@@ -1626,8 +1629,12 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 		}
 	} else if (nlh->nlmsg_flags & NLM_F_APPEND)
 		list_add_tail_rcu(&rule->list, &chain->rules);
-	else
-		list_add_rcu(&rule->list, &chain->rules);
+	else {
+		if (old_rule)
+			list_add_rcu(&rule->list, &old_rule->list);
+		else
+			list_add_rcu(&rule->list, &chain->rules);
+	}
 
 	if (flags & NFT_RULE_F_COMMIT)
 		list_add(&rule->dirty_list, &chain->dirty_rules);
Signature · 1 line
1.8.3.1
#2 lore raw

PATCH 1/1 examples: add insert rule example

In reply to Eric Leblond

This program can insert a rule after a rule given by its handle.

---
 examples/Makefile.am       |   4 +
 examples/nft-rule-insert.c | 203 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 207 insertions(+)
 create mode 100644 examples/nft-rule-insert.c
examples/Makefile.am +4 -0
index dcf798a..1d6b98f 100644
@@ -10,6 +10,7 @@ check_PROGRAMS = nft-table-add		\
 		 nft-chain-del		\
 		 nft-chain-get		\
 		 nft-rule-add		\
+		 nft-rule-insert	\
 		 nft-rule-xml-add	\
 		 nft-rule-del		\
 		 nft-rule-get		\
@@ -52,6 +53,9 @@ nft_chain_get_LDADD = ../src/libnftables.la ${LIBMNL_LIBS} ${LIBXML_LIBS}
 nft_rule_add_SOURCES = nft-rule-add.c
 nft_rule_add_LDADD = ../src/libnftables.la ${LIBMNL_LIBS} ${LIBXML_LIBS}
 
+nft_rule_insert_SOURCES = nft-rule-insert.c
+nft_rule_insert_LDADD = ../src/libnftables.la ${LIBMNL_LIBS} ${LIBXML_LIBS}
+
 nft_rule_xml_add_SOURCES = nft-rule-xml-add.c
 nft_rule_xml_add_LDADD = ../src/libnftables.la ${LIBMNL_LIBS} ${LIBXML_LIBS}
 
examples/nft-rule-insert.c new file +203 -0

203 lines not on this page · raw message

Signature · 1 line
1.8.3.1
#3 lore raw
In reply to Eric Leblond

Hi Eric,

Quoted 11 lines

The patch
netfilter: nf_tables: add insert operation
adds support for inserting a rule after a handle.

It is followed by the patch
examples: add insert rule example
which is the libnftables example.

I choose to reuse the CREATE operation in the kernel code to avoid to add a new message to netlink. This way we have a sort of 'create after' syntax. This is almost natural IMHO.

There is an issue however: notification.
I don't see how other clients are going to know where to put the rule when updating there own list when they get notified.

They will be notified that a rule as been added successfully, but they will get it as an appended rule.

Here it's a one shot usage: only on creating you need this info, so it would be also provided on notification. Not on the dump obviously. I don't see a direct solution here, since adding an attribute (or a new flag to NFTA_RULE_FLAGS) would be going against current API design.

We have to sort this out.

Tomasz

#4 lore raw
Quoted 14 lines · Tomasz Bursztyka

Hi Eric,

Quoted 11 lines

The patch
netfilter: nf_tables: add insert operation
adds support for inserting a rule after a handle.

It is followed by the patch
examples: add insert rule example
which is the libnftables example.

I choose to reuse the CREATE operation in the kernel code to avoid to add a new message to netlink. This way we have a sort of 'create after' syntax. This is almost natural IMHO.

Quoted 6 lines

There is an issue however: notification.
I don't see how other clients are going to know where to put the rule when updating there own list when they get notified.

They will be notified that a rule as been added successfully, but they will get it as an appended rule.

This can be implemented in user-space.

The user-space daemon can keep a cache of the ordered rule-set. Thus, it can guess the position of the rule-set from the handle.

#5 lore raw

Hi Pablo,

Quoted 2 lines

The user-space daemon can keep a cache of the ordered rule-set. Thus, it can guess the position of the rule-set from the handle.

Hum, how?
The handle it will get from the notification is the handle of the newly created rule, not the one used to identify the rule for insertion.

Tomasz

#6 lore raw
Quoted 9 lines · Tomasz Bursztyka

Hi Pablo,

Quoted 2 lines

The user-space daemon can keep a cache of the ordered rule-set. Thus, it can guess the position of the rule-set from the handle.

Hum, how?
The handle it will get from the notification is the handle of the newly created rule, not the one used to identify the rule for insertion.

That's right. I don't come with any other way to make it rather than adding a new attribute.

Eric, would you rework the patch to do so?

#7 lore raw

Hi Pablo,

Quoted 6 lines
Quoted 4 lines

Hum, how?
The handle it will get from the notification is the handle of the newly created rule, not the one used to identify the rule for insertion.

That's right. I don't come with any other way to make it rather than adding a new attribute.

Yes, though it breaks the design logic of the current API, somehow.

I mean, attributes are currently reflecting the rule as it is, and are used symmetrically in queries/replies.

Here what we need is a temporary extra attribute, or some sort, only used for the notification.

Either via:

we don't add an element to enum nft_rule_attributes {}, instead we create another enum for attributes only used on notification. like enum nft_rule_extras_notifications_attributes {}

Or via (maybe better for nla policy way of working?):

Adding a nft_rule_attributes as NFTA_RULE_EXTRAS_NOTIFICATIONS as a nested attribute and then enum nft_rule_extras_notifications_attributes {} again, etc etc...

It's just a quick proposal, but my point here is to keep the API semantically sane. So it won't require extra guesses to understand how it's supposed to work
(as it is right now: it's a sane API, besides the lonely NFT_RULE_F_COMMIT in its anonymous enum)

Maybe there is a better way, probably. But you get my point.

Tomasz

#8 lore raw
Quoted 31 lines · Tomasz Bursztyka

Hi Pablo,

Quoted 6 lines
Quoted 4 lines

Hum, how?
The handle it will get from the notification is the handle of the newly created rule, not the one used to identify the rule for insertion.

That's right. I don't come with any other way to make it rather than adding a new attribute.

Yes, though it breaks the design logic of the current API, somehow.

I mean, attributes are currently reflecting the rule as it is, and are used symmetrically in queries/replies.

Here what we need is a temporary extra attribute, or some sort, only used for the notification.

Either via:

we don't add an element to enum nft_rule_attributes {}, instead we create another enum for attributes only used on notification. like enum nft_rule_extras_notifications_attributes {}

Or via (maybe better for nla policy way of working?):

Adding a nft_rule_attributes as NFTA_RULE_EXTRAS_NOTIFICATIONS as a nested attribute
and then enum nft_rule_extras_notifications_attributes {} again, etc etc...

Quoted 7 lines

It's just a quick proposal, but my point here is to keep the API semantically sane.
So it won't require extra guesses to understand how it's supposed to work (as it is right now: it's a sane API, besides the lonely NFT_RULE_F_COMMIT in its anonymous enum)

Maybe there is a better way, probably. But you get my point.

We could instead of using NLA_RULE_HANDLE for the position add a new attribute NLA_RULE_POSITION and use that both for creating rules and for notifications. It would always be set and contain the handle of the rule preceeding the new rule (for NLM_F_APPEND) or the one following it (for !NLM_F_APPEND).

#9 lore raw

Hi Patrick,

Quoted 6 lines
Quoted 1 line
Quoted 1 line

Maybe there is a better way, probably. But you get my point.

We could instead of using NLA_RULE_HANDLE for the position add a new attribute NLA_RULE_POSITION and use that both for creating rules and for notifications. It would always be set and contain the handle of the rule preceeding the new rule (for NLM_F_APPEND) or the one following it (for !NLM_F_APPEND).

I like that, it follows the current API design logic and it's simpler to implement in both sides. It's much simpler indeed!

Tomasz

#10 lore raw
In reply to Patrick McHardy

Hi,

Quoted 7 lines · Patrick McHardy
Quoted 6 lines · Tomasz Bursztyka

Hi Pablo,

Quoted 4 lines
Quoted 4 lines

Hum, how?
The handle it will get from the notification is the handle of the newly created rule, not the one used to identify the rule for insertion.

...

Quoted 7 lines

LE_F_COMMIT in its anonymous enum)

Quoted 2 lines

Maybe there is a better way, probably. But you get my point.

We could instead of using NLA_RULE_HANDLE for the position add a new attribute NLA_RULE_POSITION and use that both for creating rules and for notifications.

I like that. Reusing NLA_RULE_HANDLE was making feel somehow uncomfortable.

Quoted 3 lines

It would always be set and contain the handle of
the rule preceeding the new rule (for NLM_F_APPEND) or the one following it (for !NLM_F_APPEND).

Nice, reworking my patches in that direction.

BR,
--
Eric

#11 lore raw

RFC PATCH v2 1/1 netfilter: nf_tables: add insert operation

This patch adds a new rule attribute NFTA_RULE_POSITION which is used to store the position of a rule relatively to the others. By providing a create command and specifying a position, the rule is inserted after the rule with the handle equal to the provided position.
Regarding notification, the position attribute is added to specify the handle of the previous rule in append mode and the handle of the next rule in the other case.

---
 include/uapi/linux/netfilter/nf_tables.h |  1 +
 net/netfilter/nf_tables_api.c            | 32 +++++++++++++++++++++++++++++---
 2 files changed, 30 insertions(+), 3 deletions(-)
include/uapi/linux/netfilter/nf_tables.h +1 -0
index d40a7f9..d9bf8ea 100644
@@ -143,6 +143,7 @@ enum nft_rule_attributes {
 	NFTA_RULE_EXPRESSIONS,
 	NFTA_RULE_FLAGS,
 	NFTA_RULE_COMPAT,
+	NFTA_RULE_POSITION,
 	__NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX		(__NFTA_RULE_MAX - 1)
net/netfilter/nf_tables_api.c +29 -3
index b00aca8..a03aa9f 100644
@@ -1267,6 +1267,7 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
 	[NFTA_RULE_EXPRESSIONS]	= { .type = NLA_NESTED },
 	[NFTA_RULE_FLAGS]	= { .type = NLA_U32 },
 	[NFTA_RULE_COMPAT]	= { .type = NLA_NESTED },
+	[NFTA_RULE_POSITION]	= { .type = NLA_U64 },
 };
 
 static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
@@ -1298,6 +1299,17 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
 		goto nla_put_failure;
 
+	if (event & NLM_F_APPEND && rule->list.prev) {
+		if (nla_put_be64(skb, NFTA_RULE_POSITION,
+				 cpu_to_be64(((struct nft_rule *)rule->list.prev)->handle)))
+			goto nla_put_failure;
+	} else if (rule->list.next) {
+		if (nla_put_be64(skb, NFTA_RULE_POSITION,
+				 cpu_to_be64(((struct nft_rule *)rule->list.next)->handle)))
+			goto nla_put_failure;
+	} else
+		goto nla_put_failure;
+
 	list = nla_nest_start(skb, NFTA_RULE_EXPRESSIONS);
 	if (list == NULL)
 		goto nla_put_failure;
@@ -1537,7 +1549,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 	int err, rem;
 	bool create;
 	u32 flags = 0;
-	u64 handle;
+	u64 handle, pos_handle;
 
 	create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
 
@@ -1571,6 +1583,16 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 		handle = nf_tables_alloc_handle(table);
 	}
 
+	if (nla[NFTA_RULE_POSITION]) {
+		pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
+		old_rule = __nf_tables_rule_lookup(chain, pos_handle);
+		if (IS_ERR(old_rule))
+			return PTR_ERR(old_rule);
+
+		if (! (nlh->nlmsg_flags & NLM_F_CREATE))
+			return -EOPNOTSUPP;
+	}
+
 	nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
 
 	n = 0;
@@ -1626,8 +1648,12 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 		}
 	} else if (nlh->nlmsg_flags & NLM_F_APPEND)
 		list_add_tail_rcu(&rule->list, &chain->rules);
-	else
-		list_add_rcu(&rule->list, &chain->rules);
+	else {
+		if (old_rule)
+			list_add_rcu(&rule->list, &old_rule->list);
+		else
+			list_add_rcu(&rule->list, &chain->rules);
+	}
 
 	if (flags & NFT_RULE_F_COMMIT)
 		list_add(&rule->dirty_list, &chain->dirty_rules);
Signature · 1 line
1.8.3.1
#12 lore raw

Re: [RFC PATCHv2] netfilter: nf_tables: add insert operation

Hi Eric,

Quoted 40 lines · Eric Leblond

This patch adds a new rule attribute NFTA_RULE_POSITION which is used to store the position of a rule relatively to the others. By providing a create command and specifying a position, the rule is inserted after the rule with the handle equal to the provided position.
Regarding notification, the position attribute is added to specify the handle of the previous rule in append mode and the handle of the next rule in the other case.

---
 include/uapi/linux/netfilter/nf_tables.h |  1 +
 net/netfilter/nf_tables_api.c            | 32 +++++++++++++++++++++++++++++---
 2 files changed, 30 insertions(+), 3 deletions(-)
include/uapi/linux/netfilter/nf_tables.h +1 -0
index d40a7f9..d9bf8ea 100644
@@ -143,6 +143,7 @@ enum nft_rule_attributes {
 	NFTA_RULE_EXPRESSIONS,
 	NFTA_RULE_FLAGS,
 	NFTA_RULE_COMPAT,
+	NFTA_RULE_POSITION,
 	__NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX		(__NFTA_RULE_MAX - 1)
net/netfilter/nf_tables_api.c +1 -0
index b00aca8..a03aa9f 100644
@@ -1267,6 +1267,7 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
 	[NFTA_RULE_EXPRESSIONS]	= { .type = NLA_NESTED },
 	[NFTA_RULE_FLAGS]	= { .type = NLA_U32 },
 	[NFTA_RULE_COMPAT]	= { .type = NLA_NESTED },
+	[NFTA_RULE_POSITION]	= { .type = NLA_U64 },
 };
 
 static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,

net/netfilter/nf_tables_api.c static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq, · line 1302

Quoted 4 lines
net/netfilter/nf_tables_api.c +1 -0
@@ -1298,6 +1299,17 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
 		goto nla_put_failure;
 
+	if (event & NLM_F_APPEND && rule->list.prev) {

.prev is always != NULL.

It points to the list head in the first element case. It is set to LIST_POISON2 in case that rule has been deleted.

Quoted 61 lines
net/netfilter/nf_tables_api.c +27 -3
+		if (nla_put_be64(skb, NFTA_RULE_POSITION,
+				 cpu_to_be64(((struct nft_rule *)rule->list.prev)->handle)))
+			goto nla_put_failure;
+	} else if (rule->list.next) {
+		if (nla_put_be64(skb, NFTA_RULE_POSITION,
+				 cpu_to_be64(((struct nft_rule *)rule->list.next)->handle)))
+			goto nla_put_failure;
+	} else
+		goto nla_put_failure;
+
 	list = nla_nest_start(skb, NFTA_RULE_EXPRESSIONS);
 	if (list == NULL)
 		goto nla_put_failure;
@@ -1537,7 +1549,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 	int err, rem;
 	bool create;
 	u32 flags = 0;
-	u64 handle;
+	u64 handle, pos_handle;
 
 	create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
 
@@ -1571,6 +1583,16 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 		handle = nf_tables_alloc_handle(table);
 	}
 
+	if (nla[NFTA_RULE_POSITION]) {
+		pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
+		old_rule = __nf_tables_rule_lookup(chain, pos_handle);
+		if (IS_ERR(old_rule))
+			return PTR_ERR(old_rule);
+
+		if (! (nlh->nlmsg_flags & NLM_F_CREATE))
+			return -EOPNOTSUPP;
+	}
+
 	nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
 
 	n = 0;
@@ -1626,8 +1648,12 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 		}
 	} else if (nlh->nlmsg_flags & NLM_F_APPEND)
 		list_add_tail_rcu(&rule->list, &chain->rules);
-	else
-		list_add_rcu(&rule->list, &chain->rules);
+	else {
+		if (old_rule)
+			list_add_rcu(&rule->list, &old_rule->list);
+		else
+			list_add_rcu(&rule->list, &chain->rules);
+	}
 
 	if (flags & NFT_RULE_F_COMMIT)
 		list_add(&rule->dirty_list, &chain->dirty_rules);
Signature · 6 lines
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#13 lore raw

PATCH v3 1/1 [PATCHv3 nftables insert operation]

Hello,

Here's a rework of previous patch. Kernel patch, libnftables and nftables patches are to follow.

libnftables patchset statistics:

 examples/Makefile.am                |   4 +
 examples/nft-rule-insert.c          | 204 ++++++++++++++++++++++++++++++++++++
 include/libnftables/rule.h          |   3 +-
 include/linux/netfilter/nf_tables.h |   1 +
 src/rule.c                          |  29 ++++-
 5 files changed, 237 insertions(+), 4 deletions(-)

nftables patchset statistics:

 include/rule.h            |  2 ++
 src/netlink.c             |  2 ++
 src/netlink_delinearize.c |  2 ++
 src/parser.y              | 22 ++++++++++++++++++++--
 src/rule.c                |  2 ++
 src/scanner.l             |  3 +++
 6 files changed, 31 insertions(+), 2 deletions(-)

BR,
--
Eric

#14 lore raw

PATCH 1/1 netfilter: nf_tables: add insert operation

This patch adds a new rule attribute NFTA_RULE_POSITION which is used to store the position of a rule relatively to the others. By providing a create command and specifying a position, the rule is inserted after the rule with the handle equal to the provided position.
Regarding notification, the position attribute is added to specify the handle of the previous rule in append mode and the handle of the next rule in the other case.

---
 include/uapi/linux/netfilter/nf_tables.h |  1 +
 net/netfilter/nf_tables_api.c            | 47 +++++++++++++++++++++++++++++---
 2 files changed, 44 insertions(+), 4 deletions(-)
include/uapi/linux/netfilter/nf_tables.h +1 -0
index d40a7f9..d9bf8ea 100644
@@ -143,6 +143,7 @@ enum nft_rule_attributes {
 	NFTA_RULE_EXPRESSIONS,
 	NFTA_RULE_FLAGS,
 	NFTA_RULE_COMPAT,
+	NFTA_RULE_POSITION,
 	__NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX		(__NFTA_RULE_MAX - 1)
net/netfilter/nf_tables_api.c +43 -4

83 lines not on this page · raw message

Signature · 1 line
1.8.3.2
#15 lore raw

Re: [PATCH] netfilter: nf_tables: add insert operation

Hi Eric,

Thanks for this new round, some comments below:

Quoted 48 lines · Eric Leblond

This patch adds a new rule attribute NFTA_RULE_POSITION which is used to store the position of a rule relatively to the others. By providing a create command and specifying a position, the rule is inserted after the rule with the handle equal to the provided position.
Regarding notification, the position attribute is added to specify the handle of the previous rule in append mode and the handle of the next rule in the other case.

---
 include/uapi/linux/netfilter/nf_tables.h |  1 +
 net/netfilter/nf_tables_api.c            | 47 +++++++++++++++++++++++++++++---
 2 files changed, 44 insertions(+), 4 deletions(-)
include/uapi/linux/netfilter/nf_tables.h +1 -0
index d40a7f9..d9bf8ea 100644
@@ -143,6 +143,7 @@ enum nft_rule_attributes {
 	NFTA_RULE_EXPRESSIONS,
 	NFTA_RULE_FLAGS,
 	NFTA_RULE_COMPAT,
+	NFTA_RULE_POSITION,
 	__NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX		(__NFTA_RULE_MAX - 1)
net/netfilter/nf_tables_api.c +2 -0
index b00aca8..ce8a4f0 100644
@@ -1267,6 +1267,7 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
 	[NFTA_RULE_EXPRESSIONS]	= { .type = NLA_NESTED },
 	[NFTA_RULE_FLAGS]	= { .type = NLA_U32 },
 	[NFTA_RULE_COMPAT]	= { .type = NLA_NESTED },
+	[NFTA_RULE_POSITION]	= { .type = NLA_U64 },
 };
 
 static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
@@ -1279,6 +1280,7 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	struct nfgenmsg *nfmsg;
 	const struct nft_expr *expr, *next;
 	struct nlattr *list;
+	const struct nft_rule *prule;
 
 	event |= NFNL_SUBSYS_NFTABLES << 8;
 	nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),

net/netfilter/nf_tables_api.c static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq, · line 1303

Quoted 4 lines
net/netfilter/nf_tables_api.c +1 -0
@@ -1298,6 +1300,26 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
 		goto nla_put_failure;
 
+	if (event & NLM_F_APPEND) {

This should be if (flags & NLM_F_APPEND)

net/netfilter/nf_tables_api.c static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq, · line 1304

Quoted 1 line
net/netfilter/nf_tables_api.c +1 -0
+		if ((rule->list.prev != LIST_POISON2) &&

You can use event instead to catch the deletion case:

if (event != NFT_MSG_DELRULE)

net/netfilter/nf_tables_api.c static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq, · line 1314

Quoted 10 lines
net/netfilter/nf_tables_api.c +10 -0
+		    (rule->list.prev != &chain->rules)) {
+			prule = list_entry(rule->list.prev,
+					   struct nft_rule, list);
+			if (nla_put_be64(skb, NFTA_RULE_POSITION,
+					 cpu_to_be64(prule->handle)))
+				goto nla_put_failure;
+		}
+	} else {
+		if ((rule->list.next != LIST_POISON1) &&
+		    (rule->list.next != &chain->rules)) {

You can use list_is_last instead of rule->list.next != &chain->rules.

Unfortunately, there is no list_is_first, but we could ask for mainstream inclusion later on.

Quoted 22 lines
net/netfilter/nf_tables_api.c +9 -1
+			prule = list_entry(rule->list.next,
+					   struct nft_rule, list);
+			if (nla_put_be64(skb, NFTA_RULE_POSITION,
+					 cpu_to_be64(prule->handle)))
+				goto nla_put_failure;
+		}
+	}
+
 	list = nla_nest_start(skb, NFTA_RULE_EXPRESSIONS);
 	if (list == NULL)
 		goto nla_put_failure;
@@ -1537,7 +1559,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 	int err, rem;
 	bool create;
 	u32 flags = 0;
-	u64 handle;
+	u64 handle, pos_handle;
 
 	create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
 
@@ -1571,6 +1593,16 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 		handle = nf_tables_alloc_handle(table);

net/netfilter/nf_tables_api.c static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, · line 1603

Quoted 10 lines
net/netfilter/nf_tables_api.c +8 -0
 	}
 
+	if (nla[NFTA_RULE_POSITION]) {
+		pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
+		old_rule = __nf_tables_rule_lookup(chain, pos_handle);
+		if (IS_ERR(old_rule))
+			return PTR_ERR(old_rule);
+
+		if (! (nlh->nlmsg_flags & NLM_F_CREATE))
+			return -EOPNOTSUPP;

Better this checking before the rule lookup.

Quoted 28 lines
net/netfilter/nf_tables_api.c +12 -3
+	}
+
 	nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
 
 	n = 0;
@@ -1625,9 +1657,16 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 			nf_tables_rule_destroy(old_rule);
 		}
 	} else if (nlh->nlmsg_flags & NLM_F_APPEND)
-		list_add_tail_rcu(&rule->list, &chain->rules);
-	else
-		list_add_rcu(&rule->list, &chain->rules);
+		if (old_rule)
+			list_add_rcu(&rule->list, &old_rule->list);
+		else
+			list_add_tail_rcu(&rule->list, &chain->rules);
+	else {
+		if (old_rule)
+			list_add_tail_rcu(&rule->list, &old_rule->list);
+		else
+			list_add_rcu(&rule->list, &chain->rules);
+	}
 
 	if (flags & NFT_RULE_F_COMMIT)
 		list_add(&rule->dirty_list, &chain->dirty_rules);
Signature · 1 line
1.8.3.2
#16 lore raw

v4 cover [PATCHv4 nftables insert operation 0/1]

Hello Pablo,

Thanks for the review, here's an update version of the kernel patch. A nftables patch on top of the one I've already provide is also mandatory to have the insert operation working correctly.

BR,
--
Eric

#17 lore raw

PATCH v4 1/1 netfilter: nf_tables: add insert operation

This patch adds a new rule attribute NFTA_RULE_POSITION which is used to store the position of a rule relatively to the others. By providing a create command and specifying a position, the rule is inserted after the rule with the handle equal to the provided position.
Regarding notification, the position attribute is added to specify the handle of the previous rule in append mode and the handle of the next rule in the other case.

---
 include/uapi/linux/netfilter/nf_tables.h |  1 +
 net/netfilter/nf_tables_api.c            | 46 +++++++++++++++++++++++++++++---
 2 files changed, 43 insertions(+), 4 deletions(-)
include/uapi/linux/netfilter/nf_tables.h +1 -0
index d40a7f9..d9bf8ea 100644
@@ -143,6 +143,7 @@ enum nft_rule_attributes {
 	NFTA_RULE_EXPRESSIONS,
 	NFTA_RULE_FLAGS,
 	NFTA_RULE_COMPAT,
+	NFTA_RULE_POSITION,
 	__NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX		(__NFTA_RULE_MAX - 1)
net/netfilter/nf_tables_api.c +42 -4

82 lines not on this page · raw message

Signature · 1 line
1.8.3.2
#18 lore raw

Re: [PATCHv4] netfilter: nf_tables: add insert operation

Hi Eric,

Quoted 50 lines · Eric Leblond

This patch adds a new rule attribute NFTA_RULE_POSITION which is used to store the position of a rule relatively to the others. By providing a create command and specifying a position, the rule is inserted after the rule with the handle equal to the provided position.
Regarding notification, the position attribute is added to specify the handle of the previous rule in append mode and the handle of the next rule in the other case.

---
 include/uapi/linux/netfilter/nf_tables.h |  1 +
 net/netfilter/nf_tables_api.c            | 46 +++++++++++++++++++++++++++++---
 2 files changed, 43 insertions(+), 4 deletions(-)
include/uapi/linux/netfilter/nf_tables.h +1 -0
index d40a7f9..d9bf8ea 100644
@@ -143,6 +143,7 @@ enum nft_rule_attributes {
 	NFTA_RULE_EXPRESSIONS,
 	NFTA_RULE_FLAGS,
 	NFTA_RULE_COMPAT,
+	NFTA_RULE_POSITION,
 	__NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX		(__NFTA_RULE_MAX - 1)
net/netfilter/nf_tables_api.c +2 -0
index b00aca8..012eb1f 100644
@@ -1267,6 +1267,7 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
 	[NFTA_RULE_EXPRESSIONS]	= { .type = NLA_NESTED },
 	[NFTA_RULE_FLAGS]	= { .type = NLA_U32 },
 	[NFTA_RULE_COMPAT]	= { .type = NLA_NESTED },
+	[NFTA_RULE_POSITION]	= { .type = NLA_U64 },
 };
 
 static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
@@ -1279,6 +1280,7 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	struct nfgenmsg *nfmsg;
 	const struct nft_expr *expr, *next;
 	struct nlattr *list;
+	const struct nft_rule *prule;
 
 	event |= NFNL_SUBSYS_NFTABLES << 8;
 	nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
@@ -1298,6 +1300,26 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
 		goto nla_put_failure;

net/netfilter/nf_tables_api.c static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq, · line 1311

Quoted 10 lines
net/netfilter/nf_tables_api.c +9 -0
 
+	if (flags & NLM_F_APPEND) {
+		if ((event != NFT_MSG_DELRULE) &&
+		    (rule->list.prev != &chain->rules)) {
+			prule = list_entry(rule->list.prev,
+					   struct nft_rule, list);
+			if (nla_put_be64(skb, NFTA_RULE_POSITION,
+					 cpu_to_be64(prule->handle)))
+				goto nla_put_failure;
+		}

This looks good but I think we can simplify this to always use .prev.

1) Append: we use .prev. If it's the first rule in the list, skip position attribute.

2) Insert: never dump position attribute as it is always the first rule in the list.

3) At position X: use .prev. If it's the first rule in the list, skip.

That should allows us to remove the else branch below and it should simplify the semantics of NFTA_RULE_POSITION as well.

Quoted 62 lines
net/netfilter/nf_tables_api.c +31 -4
+	} else {
+		if ((event != NFT_MSG_DELRULE) &&
+		    list_is_last(&rule->list, &chain->rules)) {
+			prule = list_entry(rule->list.next,
+					   struct nft_rule, list);
+			if (nla_put_be64(skb, NFTA_RULE_POSITION,
+					 cpu_to_be64(prule->handle)))
+				goto nla_put_failure;
+		}
+	}
+
 	list = nla_nest_start(skb, NFTA_RULE_EXPRESSIONS);
 	if (list == NULL)
 		goto nla_put_failure;
@@ -1537,7 +1559,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 	int err, rem;
 	bool create;
 	u32 flags = 0;
-	u64 handle;
+	u64 handle, pos_handle;
 
 	create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
 
@@ -1571,6 +1593,15 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 		handle = nf_tables_alloc_handle(table);
 	}
 
+	if (nla[NFTA_RULE_POSITION]) {
+		if (!(nlh->nlmsg_flags & NLM_F_CREATE))
+			return -EOPNOTSUPP;
+		pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
+		old_rule = __nf_tables_rule_lookup(chain, pos_handle);
+		if (IS_ERR(old_rule))
+			return PTR_ERR(old_rule);
+	}
+
 	nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
 
 	n = 0;
@@ -1625,9 +1656,16 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 			nf_tables_rule_destroy(old_rule);
 		}
 	} else if (nlh->nlmsg_flags & NLM_F_APPEND)
-		list_add_tail_rcu(&rule->list, &chain->rules);
-	else
-		list_add_rcu(&rule->list, &chain->rules);
+		if (old_rule)
+			list_add_rcu(&rule->list, &old_rule->list);
+		else
+			list_add_tail_rcu(&rule->list, &chain->rules);
+	else {
+		if (old_rule)
+			list_add_tail_rcu(&rule->list, &old_rule->list);
+		else
+			list_add_rcu(&rule->list, &chain->rules);
+	}
 
 	if (flags & NFT_RULE_F_COMMIT)
 		list_add(&rule->dirty_list, &chain->dirty_rules);
Signature · 1 line
1.8.3.2
#19 lore raw

Re: [PATCHv4] netfilter: nf_tables: add insert operation

Hi,

Quoted 69 lines · Pablo Neira Ayuso

Hi Eric,

Quoted 50 lines · Eric Leblond

This patch adds a new rule attribute NFTA_RULE_POSITION which is used to store the position of a rule relatively to the others. By providing a create command and specifying a position, the rule is inserted after the rule with the handle equal to the provided position.
Regarding notification, the position attribute is added to specify the handle of the previous rule in append mode and the handle of the next rule in the other case.

---
 include/uapi/linux/netfilter/nf_tables.h |  1 +
 net/netfilter/nf_tables_api.c            | 46 +++++++++++++++++++++++++++++---
 2 files changed, 43 insertions(+), 4 deletions(-)
include/uapi/linux/netfilter/nf_tables.h +1 -0
index d40a7f9..d9bf8ea 100644
@@ -143,6 +143,7 @@ enum nft_rule_attributes {
 	NFTA_RULE_EXPRESSIONS,
 	NFTA_RULE_FLAGS,
 	NFTA_RULE_COMPAT,
+	NFTA_RULE_POSITION,
 	__NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX		(__NFTA_RULE_MAX - 1)
net/netfilter/nf_tables_api.c +2 -0
index b00aca8..012eb1f 100644
@@ -1267,6 +1267,7 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
 	[NFTA_RULE_EXPRESSIONS]	= { .type = NLA_NESTED },
 	[NFTA_RULE_FLAGS]	= { .type = NLA_U32 },
 	[NFTA_RULE_COMPAT]	= { .type = NLA_NESTED },
+	[NFTA_RULE_POSITION]	= { .type = NLA_U64 },
 };
 
 static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
@@ -1279,6 +1280,7 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	struct nfgenmsg *nfmsg;
 	const struct nft_expr *expr, *next;
 	struct nlattr *list;
+	const struct nft_rule *prule;
 
 	event |= NFNL_SUBSYS_NFTABLES << 8;
 	nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
@@ -1298,6 +1300,26 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
 		goto nla_put_failure;

net/netfilter/nf_tables_api.c static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq, · line 1311

Quoted 10 lines
net/netfilter/nf_tables_api.c +9 -0
 
+	if (flags & NLM_F_APPEND) {
+		if ((event != NFT_MSG_DELRULE) &&
+		    (rule->list.prev != &chain->rules)) {
+			prule = list_entry(rule->list.prev,
+					   struct nft_rule, list);
+			if (nla_put_be64(skb, NFTA_RULE_POSITION,
+					 cpu_to_be64(prule->handle)))
+				goto nla_put_failure;
+		}

This looks good but I think we can simplify this to always use .prev.

1) Append: we use .prev. If it's the first rule in the list, skip position attribute.

Quoted 7 lines

2) Insert: never dump position attribute as it is always the first rule in the list.

3) At position X: use .prev. If it's the first rule in the list, skip.

That should allows us to remove the else branch below and it should simplify the semantics of NFTA_RULE_POSITION as well.

This code is not pretty and I understand your point but we have two type of operations:
* Insert before
* Append after
In both cases, the presence of the NFTA_RULE_POSITION attribute is triggering the switch to this mode. And I think this is a convenient way to update the API.

Furthermore, inside nf_tables_fill_rule_info() we don't have any information to decide that we are in "position X". Only solution to switch to the method you describe would be to introduce a new operation and it seems that was is wanted (it was said in initial discussion).

BR,

Quoted 67 lines
Quoted 63 lines
net/netfilter/nf_tables_api.c +31 -4
+	} else {
+		if ((event != NFT_MSG_DELRULE) &&
+		    list_is_last(&rule->list, &chain->rules)) {
+			prule = list_entry(rule->list.next,
+					   struct nft_rule, list);
+			if (nla_put_be64(skb, NFTA_RULE_POSITION,
+					 cpu_to_be64(prule->handle)))
+				goto nla_put_failure;
+		}
+	}
+
 	list = nla_nest_start(skb, NFTA_RULE_EXPRESSIONS);
 	if (list == NULL)
 		goto nla_put_failure;
@@ -1537,7 +1559,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 	int err, rem;
 	bool create;
 	u32 flags = 0;
-	u64 handle;
+	u64 handle, pos_handle;
 
 	create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
 
@@ -1571,6 +1593,15 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 		handle = nf_tables_alloc_handle(table);
 	}
 
+	if (nla[NFTA_RULE_POSITION]) {
+		if (!(nlh->nlmsg_flags & NLM_F_CREATE))
+			return -EOPNOTSUPP;
+		pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
+		old_rule = __nf_tables_rule_lookup(chain, pos_handle);
+		if (IS_ERR(old_rule))
+			return PTR_ERR(old_rule);
+	}
+
 	nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
 
 	n = 0;
@@ -1625,9 +1656,16 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 			nf_tables_rule_destroy(old_rule);
 		}
 	} else if (nlh->nlmsg_flags & NLM_F_APPEND)
-		list_add_tail_rcu(&rule->list, &chain->rules);
-	else
-		list_add_rcu(&rule->list, &chain->rules);
+		if (old_rule)
+			list_add_rcu(&rule->list, &old_rule->list);
+		else
+			list_add_tail_rcu(&rule->list, &chain->rules);
+	else {
+		if (old_rule)
+			list_add_tail_rcu(&rule->list, &old_rule->list);
+		else
+			list_add_rcu(&rule->list, &chain->rules);
+	}
 
 	if (flags & NFT_RULE_F_COMMIT)
 		list_add(&rule->dirty_list, &chain->dirty_rules);
Signature · 1 line
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#20 lore raw

Re: [PATCHv4] netfilter: nf_tables: add insert operation

Hi Eric,

Quoted 80 lines · Eric Leblond

Hi,

Quoted 69 lines · Pablo Neira Ayuso

Hi Eric,

Quoted 50 lines · Eric Leblond

This patch adds a new rule attribute NFTA_RULE_POSITION which is used to store the position of a rule relatively to the others. By providing a create command and specifying a position, the rule is inserted after the rule with the handle equal to the provided position.
Regarding notification, the position attribute is added to specify the handle of the previous rule in append mode and the handle of the next rule in the other case.

---
 include/uapi/linux/netfilter/nf_tables.h |  1 +
 net/netfilter/nf_tables_api.c            | 46 +++++++++++++++++++++++++++++---
 2 files changed, 43 insertions(+), 4 deletions(-)
include/uapi/linux/netfilter/nf_tables.h +1 -0
index d40a7f9..d9bf8ea 100644
@@ -143,6 +143,7 @@ enum nft_rule_attributes {
 	NFTA_RULE_EXPRESSIONS,
 	NFTA_RULE_FLAGS,
 	NFTA_RULE_COMPAT,
+	NFTA_RULE_POSITION,
 	__NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX		(__NFTA_RULE_MAX - 1)
net/netfilter/nf_tables_api.c +2 -0
index b00aca8..012eb1f 100644
@@ -1267,6 +1267,7 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
 	[NFTA_RULE_EXPRESSIONS]	= { .type = NLA_NESTED },
 	[NFTA_RULE_FLAGS]	= { .type = NLA_U32 },
 	[NFTA_RULE_COMPAT]	= { .type = NLA_NESTED },
+	[NFTA_RULE_POSITION]	= { .type = NLA_U64 },
 };
 
 static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
@@ -1279,6 +1280,7 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	struct nfgenmsg *nfmsg;
 	const struct nft_expr *expr, *next;
 	struct nlattr *list;
+	const struct nft_rule *prule;
 
 	event |= NFNL_SUBSYS_NFTABLES << 8;
 	nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
@@ -1298,6 +1300,26 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
 		goto nla_put_failure;

net/netfilter/nf_tables_api.c static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq, · line 1311

Quoted 10 lines
net/netfilter/nf_tables_api.c +9 -0
 
+	if (flags & NLM_F_APPEND) {
+		if ((event != NFT_MSG_DELRULE) &&
+		    (rule->list.prev != &chain->rules)) {
+			prule = list_entry(rule->list.prev,
+					   struct nft_rule, list);
+			if (nla_put_be64(skb, NFTA_RULE_POSITION,
+					 cpu_to_be64(prule->handle)))
+				goto nla_put_failure;
+		}

This looks good but I think we can simplify this to always use .prev.

1) Append: we use .prev. If it's the first rule in the list, skip position attribute.

Quoted 7 lines

2) Insert: never dump position attribute as it is always the first rule in the list.

3) At position X: use .prev. If it's the first rule in the list, skip.

That should allows us to remove the else branch below and it should simplify the semantics of NFTA_RULE_POSITION as well.

Quoted 7 lines

This code is not pretty and I understand your point but we have two type of operations:
* Insert before
* Append after
In both cases, the presence of the NFTA_RULE_POSITION attribute is triggering the switch to this mode. And I think this is a convenient way to update the API.

I see. Then we need to save the append flag to report events correctly in the commit path for the "insert after" case, according to this approach (that's should be easy to resolve though with a follow up patch).

Quoted 2 lines

Furthermore, inside nf_tables_fill_rule_info() we don't have any information to decide that we are in "position X".

But we know the handle of our .prev node for that new rule we added, that can be used to report back our relative location to it, ie. always return the previous node.

This however results in reporting back a different handle via the event notification in the "insert after" case (instead of the original handle passed via the rule_position attribute).

Quoted 3 lines

Only solution to switch to the method you describe would be to introduce a new operation and it seems that was is wanted (it was said in initial discussion).

Sure, I just wanted to discuss the nf_tables_fill_rule_info path, not questioning the entire patch.

Regards.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#21 lore raw

Re: [PATCHv4] netfilter: nf_tables: add insert operation

Hello Pablo,

Quoted 91 lines · Pablo Neira Ayuso

Hi Eric,

Quoted 80 lines · Eric Leblond

Hi,

Quoted 69 lines · Pablo Neira Ayuso

Hi Eric,

Quoted 50 lines · Eric Leblond

This patch adds a new rule attribute NFTA_RULE_POSITION which is used to store the position of a rule relatively to the others. By providing a create command and specifying a position, the rule is inserted after the rule with the handle equal to the provided position.
Regarding notification, the position attribute is added to specify the handle of the previous rule in append mode and the handle of the next rule in the other case.

---
 include/uapi/linux/netfilter/nf_tables.h |  1 +
 net/netfilter/nf_tables_api.c            | 46 +++++++++++++++++++++++++++++---
 2 files changed, 43 insertions(+), 4 deletions(-)
include/uapi/linux/netfilter/nf_tables.h +1 -0
index d40a7f9..d9bf8ea 100644
@@ -143,6 +143,7 @@ enum nft_rule_attributes {
 	NFTA_RULE_EXPRESSIONS,
 	NFTA_RULE_FLAGS,
 	NFTA_RULE_COMPAT,
+	NFTA_RULE_POSITION,
 	__NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX		(__NFTA_RULE_MAX - 1)
net/netfilter/nf_tables_api.c +2 -0
index b00aca8..012eb1f 100644
@@ -1267,6 +1267,7 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
 	[NFTA_RULE_EXPRESSIONS]	= { .type = NLA_NESTED },
 	[NFTA_RULE_FLAGS]	= { .type = NLA_U32 },
 	[NFTA_RULE_COMPAT]	= { .type = NLA_NESTED },
+	[NFTA_RULE_POSITION]	= { .type = NLA_U64 },
 };
 
 static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
@@ -1279,6 +1280,7 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	struct nfgenmsg *nfmsg;
 	const struct nft_expr *expr, *next;
 	struct nlattr *list;
+	const struct nft_rule *prule;
 
 	event |= NFNL_SUBSYS_NFTABLES << 8;
 	nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
@@ -1298,6 +1300,26 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
 		goto nla_put_failure;

net/netfilter/nf_tables_api.c static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq, · line 1311

Quoted 10 lines
net/netfilter/nf_tables_api.c +9 -0
 
+	if (flags & NLM_F_APPEND) {
+		if ((event != NFT_MSG_DELRULE) &&
+		    (rule->list.prev != &chain->rules)) {
+			prule = list_entry(rule->list.prev,
+					   struct nft_rule, list);
+			if (nla_put_be64(skb, NFTA_RULE_POSITION,
+					 cpu_to_be64(prule->handle)))
+				goto nla_put_failure;
+		}

This looks good but I think we can simplify this to always use .prev.

1) Append: we use .prev. If it's the first rule in the list, skip position attribute.

Quoted 7 lines

2) Insert: never dump position attribute as it is always the first rule in the list.

3) At position X: use .prev. If it's the first rule in the list, skip.

That should allows us to remove the else branch below and it should simplify the semantics of NFTA_RULE_POSITION as well.

Quoted 7 lines

This code is not pretty and I understand your point but we have two type of operations:
* Insert before
* Append after
In both cases, the presence of the NFTA_RULE_POSITION attribute is triggering the switch to this mode. And I think this is a convenient way to update the API.

Quoted 4 lines

I see. Then we need to save the append flag to report events correctly in the commit path for the "insert after" case, according to this approach (that's should be easy to resolve though with a follow up patch).

IMHO, it is already there. At start of nf_tables_fill_rule_info, we are doing:

	nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
			flags);

So flags is used as flag inside nlh. And we can get the information during event by checking (nlh->nlmsg_flags & NLM_F_APPEND). I've done some tests with the attached patch and it seems to work well.

So events get insert/append information as well as position. This should be enough for event listeners to follow ruleset evolution.

Quoted 10 lines
Quoted 2 lines

Furthermore, inside nf_tables_fill_rule_info() we don't have any information to decide that we are in "position X".

But we know the handle of our .prev node for that new rule we added, that can be used to report back our relative location to it, ie. always return the previous node.

This however results in reporting back a different handle via the event notification in the "insert after" case (instead of the original handle passed via the rule_position attribute).

Yes, getting insert/append information and position is better.

Quoted 6 lines
Quoted 3 lines

Only solution to switch to the method you describe would be to introduce a new operation and it seems that was is wanted (it was said in initial discussion).

Sure, I just wanted to discuss the nf_tables_fill_rule_info path, not questioning the entire patch.

Cool :)

BR,
--
Eric

From 86e6e09ebbe2b770547034c2cb6a2239f79f1ce4 Mon Sep 17 00:00:00 2001
From: Eric Leblond <[email protected]>
Date: Tue, 16 Jul 2013 09:12:19 +0200
Subject: [PATCH] after before

---
 examples/nft-events.c | 4 ++++
 1 file changed, 4 insertions(+)
examples/nft-events.c +4 -0
index 5550c70..5bbdce4 100644
@@ -63,6 +63,10 @@ static int rule_cb(const struct nlmsghdr *nlh, int type)
 		goto err_free;
 	}
 
+	if (nlh->nlmsg_flags & NLM_F_APPEND)
+		printf("AFTER ");
+	else
+		printf("BEFORE ");
 	nft_rule_snprintf(buf, sizeof(buf), t, NFT_RULE_O_DEFAULT, 0);
 	printf("[%s]\t%s\n", type == NFT_MSG_NEWRULE ? "NEW" : "DEL", buf);
 
Signature · 1 line
1.8.3.2
#22 lore raw

Re: [PATCHv4] netfilter: nf_tables: add insert operation

Quoted 103 lines · Eric Leblond

Hello Pablo,

Quoted 91 lines · Pablo Neira Ayuso

Hi Eric,

Quoted 80 lines · Eric Leblond

Hi,

Quoted 69 lines · Pablo Neira Ayuso

Hi Eric,

Quoted 50 lines · Eric Leblond

This patch adds a new rule attribute NFTA_RULE_POSITION which is used to store the position of a rule relatively to the others. By providing a create command and specifying a position, the rule is inserted after the rule with the handle equal to the provided position.
Regarding notification, the position attribute is added to specify the handle of the previous rule in append mode and the handle of the next rule in the other case.

---
 include/uapi/linux/netfilter/nf_tables.h |  1 +
 net/netfilter/nf_tables_api.c            | 46 +++++++++++++++++++++++++++++---
 2 files changed, 43 insertions(+), 4 deletions(-)
include/uapi/linux/netfilter/nf_tables.h +1 -0
index d40a7f9..d9bf8ea 100644
@@ -143,6 +143,7 @@ enum nft_rule_attributes {
 	NFTA_RULE_EXPRESSIONS,
 	NFTA_RULE_FLAGS,
 	NFTA_RULE_COMPAT,
+	NFTA_RULE_POSITION,
 	__NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX		(__NFTA_RULE_MAX - 1)
net/netfilter/nf_tables_api.c +2 -0
index b00aca8..012eb1f 100644
@@ -1267,6 +1267,7 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
 	[NFTA_RULE_EXPRESSIONS]	= { .type = NLA_NESTED },
 	[NFTA_RULE_FLAGS]	= { .type = NLA_U32 },
 	[NFTA_RULE_COMPAT]	= { .type = NLA_NESTED },
+	[NFTA_RULE_POSITION]	= { .type = NLA_U64 },
 };
 
 static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
@@ -1279,6 +1280,7 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	struct nfgenmsg *nfmsg;
 	const struct nft_expr *expr, *next;
 	struct nlattr *list;
+	const struct nft_rule *prule;
 
 	event |= NFNL_SUBSYS_NFTABLES << 8;
 	nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
@@ -1298,6 +1300,26 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
 		goto nla_put_failure;

net/netfilter/nf_tables_api.c static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq, · line 1311

Quoted 10 lines
net/netfilter/nf_tables_api.c +9 -0
 
+	if (flags & NLM_F_APPEND) {
+		if ((event != NFT_MSG_DELRULE) &&
+		    (rule->list.prev != &chain->rules)) {
+			prule = list_entry(rule->list.prev,
+					   struct nft_rule, list);
+			if (nla_put_be64(skb, NFTA_RULE_POSITION,
+					 cpu_to_be64(prule->handle)))
+				goto nla_put_failure;
+		}

This looks good but I think we can simplify this to always use .prev.

1) Append: we use .prev. If it's the first rule in the list, skip position attribute.

Quoted 7 lines

2) Insert: never dump position attribute as it is always the first rule in the list.

3) At position X: use .prev. If it's the first rule in the list, skip.

That should allows us to remove the else branch below and it should simplify the semantics of NFTA_RULE_POSITION as well.

Quoted 7 lines

This code is not pretty and I understand your point but we have two type of operations:
* Insert before
* Append after
In both cases, the presence of the NFTA_RULE_POSITION attribute is triggering the switch to this mode. And I think this is a convenient way to update the API.

Quoted 4 lines

I see. Then we need to save the append flag to report events correctly in the commit path for the "insert after" case, according to this approach (that's should be easy to resolve though with a follow up patch).

IMHO, it is already there. At start of nf_tables_fill_rule_info, we are doing:

Quoted 6 lines
	nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
			flags);

So flags is used as flag inside nlh. And we can get the information during event by checking (nlh->nlmsg_flags & NLM_F_APPEND). I've done some tests with the attached patch and it seems to work well.

Please, see nf_tables_commit. In that path nf_tables_rule_notify does not get those flags at this moment, so it's returning its position in the insert fashion, ie. pointing to .next.

The problem with pointing to the .next node in the commit path is we are sure that .prev points to an existing rule. However, .next may point to stale rule. So I think we have to notify the position always relative to the .prev pointer to get this working in the commit path.

Regards.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#23 lore raw

Re: [PATCHv4] netfilter: nf_tables: add insert operation

Hi,

Quoted 111 lines · Pablo Neira Ayuso
Quoted 103 lines · Eric Leblond

Hello Pablo,

Quoted 91 lines · Pablo Neira Ayuso

Hi Eric,

Quoted 80 lines · Eric Leblond

Hi,

Quoted 69 lines · Pablo Neira Ayuso

Hi Eric,

Quoted 50 lines · Eric Leblond

This patch adds a new rule attribute NFTA_RULE_POSITION which is used to store the position of a rule relatively to the others. By providing a create command and specifying a position, the rule is inserted after the rule with the handle equal to the provided position.
Regarding notification, the position attribute is added to specify the handle of the previous rule in append mode and the handle of the next rule in the other case.

---
 include/uapi/linux/netfilter/nf_tables.h |  1 +
 net/netfilter/nf_tables_api.c            | 46 +++++++++++++++++++++++++++++---
 2 files changed, 43 insertions(+), 4 deletions(-)
include/uapi/linux/netfilter/nf_tables.h +1 -0
index d40a7f9..d9bf8ea 100644
@@ -143,6 +143,7 @@ enum nft_rule_attributes {
 	NFTA_RULE_EXPRESSIONS,
 	NFTA_RULE_FLAGS,
 	NFTA_RULE_COMPAT,
+	NFTA_RULE_POSITION,
 	__NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX		(__NFTA_RULE_MAX - 1)
net/netfilter/nf_tables_api.c +2 -0
index b00aca8..012eb1f 100644
@@ -1267,6 +1267,7 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
 	[NFTA_RULE_EXPRESSIONS]	= { .type = NLA_NESTED },
 	[NFTA_RULE_FLAGS]	= { .type = NLA_U32 },
 	[NFTA_RULE_COMPAT]	= { .type = NLA_NESTED },
+	[NFTA_RULE_POSITION]	= { .type = NLA_U64 },
 };
 
 static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
@@ -1279,6 +1280,7 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	struct nfgenmsg *nfmsg;
 	const struct nft_expr *expr, *next;
 	struct nlattr *list;
+	const struct nft_rule *prule;
 
 	event |= NFNL_SUBSYS_NFTABLES << 8;
 	nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
@@ -1298,6 +1300,26 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
 		goto nla_put_failure;

net/netfilter/nf_tables_api.c static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq, · line 1311

Quoted 10 lines
net/netfilter/nf_tables_api.c +9 -0
 
+	if (flags & NLM_F_APPEND) {
+		if ((event != NFT_MSG_DELRULE) &&
+		    (rule->list.prev != &chain->rules)) {
+			prule = list_entry(rule->list.prev,
+					   struct nft_rule, list);
+			if (nla_put_be64(skb, NFTA_RULE_POSITION,
+					 cpu_to_be64(prule->handle)))
+				goto nla_put_failure;
+		}

This looks good but I think we can simplify this to always use .prev.

1) Append: we use .prev. If it's the first rule in the list, skip position attribute.

Quoted 7 lines

2) Insert: never dump position attribute as it is always the first rule in the list.

3) At position X: use .prev. If it's the first rule in the list, skip.

That should allows us to remove the else branch below and it should simplify the semantics of NFTA_RULE_POSITION as well.

Quoted 7 lines

This code is not pretty and I understand your point but we have two type of operations:
* Insert before
* Append after
In both cases, the presence of the NFTA_RULE_POSITION attribute is triggering the switch to this mode. And I think this is a convenient way to update the API.

Quoted 4 lines

I see. Then we need to save the append flag to report events correctly in the commit path for the "insert after" case, according to this approach (that's should be easy to resolve though with a follow up patch).

IMHO, it is already there. At start of nf_tables_fill_rule_info, we are doing:

Quoted 6 lines
	nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
			flags);

So flags is used as flag inside nlh. And we can get the information during event by checking (nlh->nlmsg_flags & NLM_F_APPEND). I've done some tests with the attached patch and it seems to work well.

Quoted 8 lines

Please, see nf_tables_commit. In that path nf_tables_rule_notify does not get those flags at this moment, so it's returning its position in the insert fashion, ie. pointing to .next.

The problem with pointing to the .next node in the commit path is we are sure that .prev points to an existing rule. However, .next may point to stale rule. So I think we have to notify the position always relative to the .prev pointer to get this working in the commit path.

Thanks a lot for the clarification. I'll update the patch.

BR,
--
Eric

#24 lore raw

PATCH v5 1/1 netfilter: nf_tables: add insert operation

This patch adds a new rule attribute NFTA_RULE_POSITION which is used to store the position of a rule relatively to the others. By providing a create command and specifying a position, the rule is inserted after the rule with the handle equal to the provided position.
Regarding notification, the position attribute is added to specify the handle of the previous rule.

---
 include/uapi/linux/netfilter/nf_tables.h |  1 +
 net/netfilter/nf_tables_api.c            | 33 ++++++++++++++++++++++++++++----
 2 files changed, 30 insertions(+), 4 deletions(-)
include/uapi/linux/netfilter/nf_tables.h +1 -0
index d40a7f9..d9bf8ea 100644
@@ -143,6 +143,7 @@ enum nft_rule_attributes {
 	NFTA_RULE_EXPRESSIONS,
 	NFTA_RULE_FLAGS,
 	NFTA_RULE_COMPAT,
+	NFTA_RULE_POSITION,
 	__NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX		(__NFTA_RULE_MAX - 1)
net/netfilter/nf_tables_api.c +29 -4
index b00aca8..469818f 100644
@@ -1267,6 +1267,7 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
 	[NFTA_RULE_EXPRESSIONS]	= { .type = NLA_NESTED },
 	[NFTA_RULE_FLAGS]	= { .type = NLA_U32 },
 	[NFTA_RULE_COMPAT]	= { .type = NLA_NESTED },
+	[NFTA_RULE_POSITION]	= { .type = NLA_U64 },
 };
 
 static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
@@ -1279,6 +1280,7 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	struct nfgenmsg *nfmsg;
 	const struct nft_expr *expr, *next;
 	struct nlattr *list;
+	const struct nft_rule *prule;
 
 	event |= NFNL_SUBSYS_NFTABLES << 8;
 	nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
@@ -1298,6 +1300,13 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
 	if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
 		goto nla_put_failure;
 
+	if ((event != NFT_MSG_DELRULE) && (rule->list.prev != &chain->rules)) {
+		prule = list_entry(rule->list.prev, struct nft_rule, list);
+		if (nla_put_be64(skb, NFTA_RULE_POSITION,
+				 cpu_to_be64(prule->handle)))
+			goto nla_put_failure;
+	}
+
 	list = nla_nest_start(skb, NFTA_RULE_EXPRESSIONS);
 	if (list == NULL)
 		goto nla_put_failure;
@@ -1537,7 +1546,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 	int err, rem;
 	bool create;
 	u32 flags = 0;
-	u64 handle;
+	u64 handle, pos_handle;
 
 	create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
 
@@ -1571,6 +1580,15 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 		handle = nf_tables_alloc_handle(table);
 	}
 
+	if (nla[NFTA_RULE_POSITION]) {
+		if (!(nlh->nlmsg_flags & NLM_F_CREATE))
+			return -EOPNOTSUPP;
+		pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
+		old_rule = __nf_tables_rule_lookup(chain, pos_handle);
+		if (IS_ERR(old_rule))
+			return PTR_ERR(old_rule);
+	}
+
 	nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
 
 	n = 0;
@@ -1625,9 +1643,16 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 			nf_tables_rule_destroy(old_rule);
 		}
 	} else if (nlh->nlmsg_flags & NLM_F_APPEND)
-		list_add_tail_rcu(&rule->list, &chain->rules);
-	else
-		list_add_rcu(&rule->list, &chain->rules);
+		if (old_rule)
+			list_add_rcu(&rule->list, &old_rule->list);
+		else
+			list_add_tail_rcu(&rule->list, &chain->rules);
+	else {
+		if (old_rule)
+			list_add_tail_rcu(&rule->list, &old_rule->list);
+		else
+			list_add_rcu(&rule->list, &chain->rules);
+	}
 
 	if (flags & NFT_RULE_F_COMMIT)
 		list_add(&rule->dirty_list, &chain->dirty_rules);
Signature · 1 line
1.8.3.2
maintainer Applied
#25 lore raw

Re: [PATCHv5] netfilter: nf_tables: add insert operation

Quoted 7 lines · Eric Leblond

This patch adds a new rule attribute NFTA_RULE_POSITION which is used to store the position of a rule relatively to the others. By providing a create command and specifying a position, the rule is inserted after the rule with the handle equal to the provided position.
Regarding notification, the position attribute is added to specify the handle of the previous rule.

Applied, thanks a lot Eric!

#26 lore raw

PATCH 1/1 rule: honor flag argument during rule creation

In reply to Eric Leblond
---
 src/mnl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
src/mnl.c +1 -1
index ea9637c..71fe73b 100644
@@ -61,7 +61,7 @@ int mnl_nft_rule_add(struct mnl_socket *nf_sock, struct nft_rule *nlr,
 
 	nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_NEWRULE,
 			nft_rule_attr_get_u32(nlr, NFT_RULE_ATTR_FAMILY),
-			NLM_F_APPEND|NLM_F_ACK|NLM_F_CREATE, seq);
+			flags|NLM_F_ACK|NLM_F_CREATE, seq);
 	nft_rule_nlmsg_build_payload(nlh, nlr);
 
 	return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL);
Signature · 1 line
1.8.3.2
#27 lore raw

PATCH 1/4 rule: add support for position attribute

In reply to Eric Leblond

This patch adds support for position attribute which can be used to insert a rule at a given position.

---
 include/libnftables/rule.h          |  1 +
 include/linux/netfilter/nf_tables.h |  1 +
 src/rule.c                          | 23 +++++++++++++++++++++++
 3 files changed, 25 insertions(+)
include/libnftables/rule.h +1 -0
index 186c82c..ab61eb8 100644
@@ -22,6 +22,7 @@ enum {
 	NFT_RULE_ATTR_FLAGS,
 	NFT_RULE_ATTR_COMPAT_PROTO,
 	NFT_RULE_ATTR_COMPAT_FLAGS,
+	NFT_RULE_ATTR_POSITION,
 };
 
 void nft_rule_attr_unset(struct nft_rule *r, uint16_t attr);
include/linux/netfilter/nf_tables.h +1 -0
index c2dae4e..4fe91ef 100644
@@ -99,6 +99,7 @@ enum nft_rule_attributes {
 	NFTA_RULE_EXPRESSIONS,
 	NFTA_RULE_FLAGS,
 	NFTA_RULE_COMPAT,
+	NFTA_RULE_POSITION,
 	__NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX		(__NFTA_RULE_MAX - 1)
src/rule.c +23 -0
index 5a4ae91..a56df34 100644
@@ -39,6 +39,7 @@ struct nft_rule {
 	uint8_t		family;
 	uint32_t	rule_flags;
 	uint64_t	handle;
+	uint64_t	position;
 	struct {
 			uint32_t	flags;
 			uint32_t	proto;
@@ -99,6 +100,7 @@ void nft_rule_attr_unset(struct nft_rule *r, uint16_t attr)
 	case NFT_RULE_ATTR_FLAGS:
 	case NFT_RULE_ATTR_COMPAT_PROTO:
 	case NFT_RULE_ATTR_COMPAT_FLAGS:
+	case NFT_RULE_ATTR_POSITION:
 	case NFT_RULE_ATTR_FAMILY:
 		break;
 	default:
@@ -127,6 +129,9 @@ void nft_rule_attr_set(struct nft_rule *r, uint16_t attr, const void *data)
 	case NFT_RULE_ATTR_HANDLE:
 		r->handle = *((uint64_t *)data);
 		break;
+	case NFT_RULE_ATTR_POSITION:
+		r->position = *((uint64_t *)data);
+		break;
 	case NFT_RULE_ATTR_FLAGS:
 		r->rule_flags = *((uint32_t *)data);
 		break;
@@ -208,6 +213,12 @@ const void *nft_rule_attr_get(const struct nft_rule *r, uint16_t attr)
 		else
 			return NULL;
 		break;
+	case NFT_RULE_ATTR_POSITION:
+		if (r->flags & (1 << NFT_RULE_ATTR_POSITION))
+			return &r->position;
+		else
+			return NULL;
+		break;
 	default:
 		return NULL;
 	}
@@ -273,6 +284,8 @@ void nft_rule_nlmsg_build_payload(struct nlmsghdr *nlh, struct nft_rule *r)
 		mnl_attr_put_strz(nlh, NFTA_RULE_CHAIN, r->chain);
 	if (r->flags & (1 << NFT_RULE_ATTR_HANDLE))
 		mnl_attr_put_u64(nlh, NFTA_RULE_HANDLE, htobe64(r->handle));
+	if (r->flags & (1 << NFT_RULE_ATTR_POSITION))
+		mnl_attr_put_u64(nlh, NFTA_RULE_POSITION, htobe64(r->position));
 	if (r->flags & (1 << NFT_RULE_ATTR_FLAGS))
 		mnl_attr_put_u32(nlh, NFTA_RULE_FLAGS, htonl(r->rule_flags));
 
@@ -335,6 +348,12 @@ static int nft_rule_parse_attr_cb(const struct nlattr *attr, void *data)
 			return MNL_CB_ERROR;
 		}
 		break;
+	case NFTA_RULE_POSITION:
+		if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) {
+			perror("mnl_attr_validate");
+			return MNL_CB_ERROR;
+		}
+		break;
 	}
 
 	tb[type] = attr;
@@ -469,6 +488,10 @@ int nft_rule_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_rule *r)
 		ret = nft_rule_parse_expr(tb[NFTA_RULE_EXPRESSIONS], r);
 	if (tb[NFTA_RULE_COMPAT])
 		ret = nft_rule_parse_compat(tb[NFTA_RULE_COMPAT], r);
+	if (tb[NFTA_RULE_POSITION]) {
+		r->position = be64toh(mnl_attr_get_u64(tb[NFTA_RULE_POSITION]));
+		r->flags |= (1 << NFT_RULE_ATTR_POSITION);
+	}
 
 	r->family = nfg->nfgen_family;
 	r->flags |= (1 << NFT_RULE_ATTR_FAMILY);
Signature · 1 line
1.8.3.2
#28 lore raw

PATCH 2/4 examples: add insert rule example

This program can insert a rule after a rule given by its handle.

---
 examples/Makefile.am       |   4 +
 examples/nft-rule-insert.c | 204 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 208 insertions(+)
 create mode 100644 examples/nft-rule-insert.c
examples/Makefile.am +4 -0
index dcf798a..1d6b98f 100644
@@ -10,6 +10,7 @@ check_PROGRAMS = nft-table-add		\
 		 nft-chain-del		\
 		 nft-chain-get		\
 		 nft-rule-add		\
+		 nft-rule-insert	\
 		 nft-rule-xml-add	\
 		 nft-rule-del		\
 		 nft-rule-get		\
@@ -52,6 +53,9 @@ nft_chain_get_LDADD = ../src/libnftables.la ${LIBMNL_LIBS} ${LIBXML_LIBS}
 nft_rule_add_SOURCES = nft-rule-add.c
 nft_rule_add_LDADD = ../src/libnftables.la ${LIBMNL_LIBS} ${LIBXML_LIBS}
 
+nft_rule_insert_SOURCES = nft-rule-insert.c
+nft_rule_insert_LDADD = ../src/libnftables.la ${LIBMNL_LIBS} ${LIBXML_LIBS}
+
 nft_rule_xml_add_SOURCES = nft-rule-xml-add.c
 nft_rule_xml_add_LDADD = ../src/libnftables.la ${LIBMNL_LIBS} ${LIBXML_LIBS}
 
examples/nft-rule-insert.c new file +204 -0

204 lines not on this page · raw message

Signature · 1 line
1.8.3.2
maintainer Applied
#29 lore raw

Re: [libnftables PATCH 2/4] examples: add insert rule example

Quoted 2 lines · Eric Leblond

This program can insert a rule after a rule given by its handle.

Applied, thanks Eric.

#30 lore raw

PATCH 3/4 rule: display position in default printf

In reply to Eric Leblond
---
 src/rule.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
src/rule.c +2 -2
index a56df34..9dc82b8 100644
@@ -769,9 +769,9 @@ static int nft_rule_snprintf_default(char *buf, size_t size, struct nft_rule *r,
 	struct nft_rule_expr *expr;
 	int ret, len = size, offset = 0;
 
-	ret = snprintf(buf, size, "%s %s %s %"PRIu64"\n",
+	ret = snprintf(buf, size, "%s %s %s %"PRIu64" %"PRIu64"\n",
 			nft_family2str(r->family), r->table, r->chain,
-			r->handle);
+			r->handle, r->position);
 	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
 	list_for_each_entry(expr, &r->expr_list, head) {
Signature · 1 line
1.8.3.2
#31 lore raw

Re: [libnftables PATCH 3/4] rule: display position in default printf

Also applied, thanks.

#32 lore raw

PATCH 4/4 rule: change type of function to use const

In reply to Eric Leblond

The function nft_rule_attr_is_set() is doing no modification so it is possible to type it to const.

---
 include/libnftables/rule.h | 2 +-
 src/rule.c                 | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
include/libnftables/rule.h +1 -1
index ab61eb8..5496561 100644
@@ -26,7 +26,7 @@ enum {
 };
 
 void nft_rule_attr_unset(struct nft_rule *r, uint16_t attr);
-bool nft_rule_attr_is_set(struct nft_rule *r, uint16_t attr);
+bool nft_rule_attr_is_set(const struct nft_rule *r, uint16_t attr);
 void nft_rule_attr_set(struct nft_rule *r, uint16_t attr, const void *data);
 void nft_rule_attr_set_u32(struct nft_rule *r, uint16_t attr, uint32_t val);
 void nft_rule_attr_set_u64(struct nft_rule *r, uint16_t attr, uint64_t val);
src/rule.c +1 -1
index 9dc82b8..dc98a8f 100644
@@ -73,7 +73,7 @@ void nft_rule_free(struct nft_rule *r)
 }
 EXPORT_SYMBOL(nft_rule_free);
 
-bool nft_rule_attr_is_set(struct nft_rule *r, uint16_t attr)
+bool nft_rule_attr_is_set(const struct nft_rule *r, uint16_t attr)
 {
 	return r->flags & (1 << attr);
 }
Signature · 1 line
1.8.3.2
#33 lore raw

Re: [libnftables PATCH 4/4] rule: change type of function to use const

Quoted 2 lines · Eric Leblond

The function nft_rule_attr_is_set() is doing no modification so it is possible to type it to const.

I have mangled this patch to adapt all other nft_*_attr_is_set as well. This patch is master now, thanks.

maintainer Applied
#34 lore raw

Re: [libnftables PATCH 1/4] rule: add support for position attribute

In reply to Eric Leblond
Quoted 2 lines · Eric Leblond

This patch adds support for position attribute which can be used to insert a rule at a given position.

Applied, thanks.

#35 lore raw

PATCH 1/1 Add support for insertion inside rule list

In reply to Eric Leblond

This patch adds support for "insert before" and "add after" rule operation.
The rule handle syntax has an new optional after/before field which take a handle as argument.
Here is two examples:
nft add rule filter output after 5 ip daddr 1.2.3.1 drop nft insert rule filter output before 5 ip daddr 1.2.3.1 drop

---
 include/rule.h            |  2 ++
 src/netlink.c             |  2 ++
 src/netlink_delinearize.c |  2 ++
 src/parser.y              | 22 ++++++++++++++++++++--
 src/rule.c                |  2 ++
 src/scanner.l             |  3 +++
 6 files changed, 31 insertions(+), 2 deletions(-)
include/rule.h +2 -0
index e0debe3..2577cff 100644
@@ -13,6 +13,7 @@
  * @chain:	chain name (chains and rules only)
  * @set:	set name (sets only)
  * @handle:	rule handle (rules only)
+ * @position:	rule position (rules only)
  */
 struct handle {
 	uint32_t		family;
@@ -20,6 +21,7 @@ struct handle {
 	const char		*chain;
 	const char		*set;
 	uint64_t		handle;
+	uint64_t		position;
 };
 
 extern void handle_merge(struct handle *dst, const struct handle *src);
src/netlink.c +2 -0
index 2a7bdb5..5129cac 100644
@@ -105,6 +105,8 @@ struct nft_rule *alloc_nft_rule(const struct handle *h)
 		nft_rule_attr_set_str(nlr, NFT_RULE_ATTR_CHAIN, h->chain);
 	if (h->handle)
 		nft_rule_attr_set_u64(nlr, NFT_RULE_ATTR_HANDLE, h->handle);
+	if (h->position)
+		nft_rule_attr_set_u64(nlr, NFT_RULE_ATTR_POSITION, h->position);
 	return nlr;
 }
 
src/netlink_delinearize.c +2 -0
index 9348913..f92e83f 100644
@@ -796,6 +796,8 @@ struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
 	h.table  = xstrdup(nft_rule_attr_get_str(nlr, NFT_RULE_ATTR_TABLE));
 	h.chain  = xstrdup(nft_rule_attr_get_str(nlr, NFT_RULE_ATTR_CHAIN));
 	h.handle = nft_rule_attr_get_u64(nlr, NFT_RULE_ATTR_HANDLE);
+	if (nft_rule_attr_is_set(nlr, NFT_RULE_ATTR_POSITION))
+		h.position = nft_rule_attr_get_u64(nlr, NFT_RULE_ATTR_POSITION);
 
 	pctx->rule = rule_alloc(&internal_location, &h);
 	pctx->table = table_lookup(&h);
src/parser.y +20 -2
index 2923b59..d52bd97 100644
@@ -326,6 +326,9 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %token SNAT			"snat"
 %token DNAT			"dnat"
 
+%token BEFORE			"before"
+%token AFTER			"after"
+
 %type <string>			identifier string
 %destructor { xfree($$); }	identifier string
 
@@ -339,7 +342,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %destructor { handle_free(&$$); } table_spec tables_spec chain_spec chain_identifier ruleid_spec
 %type <handle>			set_spec set_identifier
 %destructor { handle_free(&$$); } set_spec set_identifier
-%type <val>			handle_spec family_spec
+%type <val>			handle_spec family_spec position_spec
 
 %type <table>			table_block_alloc table_block
 %destructor { table_free($$); }	table_block_alloc
@@ -842,10 +845,25 @@ handle_spec		:	/* empty */
 			}
 			;
 
-ruleid_spec		:	chain_spec	handle_spec
+position_spec		:	/* empty */
+			{
+				$$ = 0;
+			}
+			|	BEFORE		NUM
+			{
+				$$ = $2;
+			}
+			|	AFTER		NUM
+			{
+				$$ = $2;
+			}
+			;
+
+ruleid_spec		:	chain_spec	handle_spec	position_spec
 			{
 				$$		= $1;
 				$$.handle	= $2;
+				$$.position	= $3;
 			}
 			;
 
src/rule.c +2 -0
index 5a894cc..8368624 100644
@@ -41,6 +41,8 @@ void handle_merge(struct handle *dst, const struct handle *src)
 		dst->set = xstrdup(src->set);
 	if (dst->handle == 0)
 		dst->handle = src->handle;
+	if (dst->position == 0)
+		dst->position = src->position;
 }
 
 struct set *set_alloc(const struct location *loc)
src/scanner.l +3 -0
index fe7b86c..519e1fc 100644
@@ -249,6 +249,9 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 "flush"			{ return FLUSH; }
 "rename"		{ return RENAME; }
 
+"before"		{ return BEFORE; }
+"after"			{ return AFTER; }
+
 "counter"		{ return COUNTER; }
 "packets"		{ return PACKETS; }
 "bytes"			{ return BYTES; }
Signature · 1 line
1.8.3.2
#36 lore raw

Re: [nftables PATCH] Add support for insertion inside rule list

Hi Eric,

Quoted 7 lines · Eric Leblond

This patch adds support for "insert before" and "add after" rule operation.
The rule handle syntax has an new optional after/before field which take a handle as argument.
Here is two examples:
nft add rule filter output after 5 ip daddr 1.2.3.1 drop nft insert rule filter output before 5 ip daddr 1.2.3.1 drop

While testing this new feature, I noticed that the parser was accepting this:

nft add rule filter output after 5 ip daddr 1.2.3.1 drop nft insert rule filter output after 5 ip daddr 1.2.3.1 drop

Note that 'add' and 'insert' become semantically equivalent, which seems inconsistent to me.

While fixing it using the 'before' and 'after', I noticed that 'add' and 'insert' already tell us where to put the new rule, so 'after' and 'before' were repeating again what we want to do. I have reworked this patch to change this initial syntax:

nft add rule filter output position 5 ip daddr 1.2.3.1 drop nft insert rule filter output position 5 ip daddr 1.2.3.1 drop

We can support the after and before, but that would imply some extra evaluation after the parsing that would make the patch bigger. So I prefered to go the simpler solution.

Please, find the new patch attached. Thanks.

Quoted 1 line

From f8afcae4af949c1f8c71fc4dbbffdbddbedb7adf Mon Sep 17 00:00:00 2001

From: Eric Leblond <[email protected]>
Date: Sat, 6 Jul 2013 17:33:57 +0200
Subject: [PATCH] src: Add support for insertion inside rule list

This patch adds support to insert and to add rule using a rule handle as reference. The rule handle syntax has an new optional position field which take a handle as argument.

Two examples:

nft add rule filter output position 5 ip daddr 1.2.3.1 drop nft insert rule filter output position 5 ip daddr 1.2.3.1 drop

---
 include/rule.h            |    2 ++
 src/mnl.c                 |    2 +-
 src/netlink.c             |    2 ++
 src/netlink_delinearize.c |    2 ++
 src/parser.y              |   17 +++++++++++++++--
 src/rule.c                |    2 ++
 src/scanner.l             |    2 ++
 7 files changed, 26 insertions(+), 3 deletions(-)
include/rule.h +2 -0
index e0debe3..2577cff 100644
@@ -13,6 +13,7 @@
  * @chain:	chain name (chains and rules only)
  * @set:	set name (sets only)
  * @handle:	rule handle (rules only)
+ * @position:	rule position (rules only)
  */
 struct handle {
 	uint32_t		family;
@@ -20,6 +21,7 @@ struct handle {
 	const char		*chain;
 	const char		*set;
 	uint64_t		handle;
+	uint64_t		position;
 };
 
 extern void handle_merge(struct handle *dst, const struct handle *src);
src/mnl.c +1 -1
index a58f7ea..928d692 100644
@@ -61,7 +61,7 @@ int mnl_nft_rule_add(struct mnl_socket *nf_sock, struct nft_rule *nlr,
 
 	nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_NEWRULE,
 			nft_rule_attr_get_u32(nlr, NFT_RULE_ATTR_FAMILY),
-			NLM_F_APPEND|NLM_F_ACK|NLM_F_CREATE, seq);
+			flags|NLM_F_ACK|NLM_F_CREATE, seq);
 	nft_rule_nlmsg_build_payload(nlh, nlr);
 
 	return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL);
src/netlink.c +2 -0
index 2a7bdb5..5129cac 100644
@@ -105,6 +105,8 @@ struct nft_rule *alloc_nft_rule(const struct handle *h)
 		nft_rule_attr_set_str(nlr, NFT_RULE_ATTR_CHAIN, h->chain);
 	if (h->handle)
 		nft_rule_attr_set_u64(nlr, NFT_RULE_ATTR_HANDLE, h->handle);
+	if (h->position)
+		nft_rule_attr_set_u64(nlr, NFT_RULE_ATTR_POSITION, h->position);
 	return nlr;
 }
 
src/netlink_delinearize.c +2 -0
index 9348913..f92e83f 100644
@@ -796,6 +796,8 @@ struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
 	h.table  = xstrdup(nft_rule_attr_get_str(nlr, NFT_RULE_ATTR_TABLE));
 	h.chain  = xstrdup(nft_rule_attr_get_str(nlr, NFT_RULE_ATTR_CHAIN));
 	h.handle = nft_rule_attr_get_u64(nlr, NFT_RULE_ATTR_HANDLE);
+	if (nft_rule_attr_is_set(nlr, NFT_RULE_ATTR_POSITION))
+		h.position = nft_rule_attr_get_u64(nlr, NFT_RULE_ATTR_POSITION);
 
 	pctx->rule = rule_alloc(&internal_location, &h);
 	pctx->table = table_lookup(&h);
src/parser.y +15 -2
index 2923b59..91981e9 100644
@@ -326,6 +326,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %token SNAT			"snat"
 %token DNAT			"dnat"
 
+%token POSITION			"position"
+
 %type <string>			identifier string
 %destructor { xfree($$); }	identifier string
 
@@ -339,7 +341,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %destructor { handle_free(&$$); } table_spec tables_spec chain_spec chain_identifier ruleid_spec
 %type <handle>			set_spec set_identifier
 %destructor { handle_free(&$$); } set_spec set_identifier
-%type <val>			handle_spec family_spec
+%type <val>			handle_spec family_spec position_spec
 
 %type <table>			table_block_alloc table_block
 %destructor { table_free($$); }	table_block_alloc
@@ -842,10 +844,21 @@ handle_spec		:	/* empty */
 			}
 			;
 
-ruleid_spec		:	chain_spec	handle_spec
+position_spec		:	/* empty */
+			{
+				$$ = 0;
+			}
+			|	POSITION	NUM
+			{
+				$$ = $2;
+			}
+			;
+
+ruleid_spec		:	chain_spec	handle_spec	position_spec
 			{
 				$$		= $1;
 				$$.handle	= $2;
+				$$.position	= $3;
 			}
 			;
 
src/rule.c +2 -0
index 5a894cc..8368624 100644
@@ -41,6 +41,8 @@ void handle_merge(struct handle *dst, const struct handle *src)
 		dst->set = xstrdup(src->set);
 	if (dst->handle == 0)
 		dst->handle = src->handle;
+	if (dst->position == 0)
+		dst->position = src->position;
 }
 
 struct set *set_alloc(const struct location *loc)
src/scanner.l +2 -0
index fe7b86c..7946e94 100644
@@ -249,6 +249,8 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 "flush"			{ return FLUSH; }
 "rename"		{ return RENAME; }
 
+"position"		{ return POSITION; }
+
 "counter"		{ return COUNTER; }
 "packets"		{ return PACKETS; }
 "bytes"			{ return BYTES; }
Signature · 1 line
1.7.10.4
#37 lore raw

Re: [nftables PATCH] Add support for insertion inside rule list

Hello,

Quoted 11 lines · Pablo Neira Ayuso

Hi Eric,

Quoted 7 lines · Eric Leblond

This patch adds support for "insert before" and "add after" rule operation.
The rule handle syntax has an new optional after/before field which take a handle as argument.
Here is two examples:
nft add rule filter output after 5 ip daddr 1.2.3.1 drop nft insert rule filter output before 5 ip daddr 1.2.3.1 drop

Quoted 8 lines

While testing this new feature, I noticed that the parser was accepting this:

nft add rule filter output after 5 ip daddr 1.2.3.1 drop nft insert rule filter output after 5 ip daddr 1.2.3.1 drop

Note that 'add' and 'insert' become semantically equivalent, which seems inconsistent to me.

Yes, forgot to mention that.

Quoted 11 lines

While fixing it using the 'before' and 'after', I noticed that 'add' and 'insert' already tell us where to put the new rule, so 'after' and 'before' were repeating again what we want to do. I have reworked this patch to change this initial syntax:

nft add rule filter output position 5 ip daddr 1.2.3.1 drop nft insert rule filter output position 5 ip daddr 1.2.3.1 drop

We can support the after and before, but that would imply some extra evaluation after the parsing that would make the patch bigger. So I prefered to go the simpler solution.

I agree with the following modification. I did not find better than this so, it is ok for me :)

Patch tested. It works well.

BR,
--
Eric

#38 lore raw

Re: [nftables PATCH] Add support for insertion inside rule list

On Fri, Jul 19, 2013 at 04:31:27PM +0200, Eric Leblond wrote:
[...]

Quoted 8 lines
Quoted 8 lines

While fixing it using the 'before' and 'after', I noticed that 'add' and 'insert' already tell us where to put the new rule, so 'after' and 'before' were repeating again what we want to do. I have reworked this patch to change this initial syntax:

nft add rule filter output position 5 ip daddr 1.2.3.1 drop nft insert rule filter output position 5 ip daddr 1.2.3.1 drop

Quoted 8 lines
Quoted 3 lines

We can support the after and before, but that would imply some extra evaluation after the parsing that would make the patch bigger. So I prefered to go the simpler solution.

I agree with the following modification. I did not find better than this so, it is ok for me :)

Patch tested. It works well.

I have applied this patch, thanks for testing.

#39 lore raw

Re: [RFC PATCHv2] netfilter: nf_tables: add insert operation

In reply to Eric Leblond

Hi Eric,

There is 2 long lines it seems,

net/netfilter/nf_tables_api.c static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq, · line 1304

Quoted 2 lines
net/netfilter/nf_tables_api.c +2 -0
+		if (nla_put_be64(skb, NFTA_RULE_POSITION,
+				 cpu_to_be64(((struct nft_rule *)rule->list.prev)->handle)))

Here,

net/netfilter/nf_tables_api.c static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq, · line 1308

Quoted 4 lines
net/netfilter/nf_tables_api.c +4 -0
+			goto nla_put_failure;
+	} else if (rule->list.next) {
+		if (nla_put_be64(skb, NFTA_RULE_POSITION,
+				 cpu_to_be64(((struct nft_rule *)rule->list.next)->handle)))

and there.

Tomasz