All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/6] nftables trace support
@ 2015-11-24 10:02 Florian Westphal
  2015-11-24 10:02 ` [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure Florian Westphal
                   ` (5 more replies)
  0 siblings, 6 replies; 80+ messages in thread
From: Florian Westphal @ 2015-11-24 10:02 UTC (permalink / raw)
  To: netfilter-devel

Hi.

This is formal first-round submission of the nft trace infrastructure.

Changes since various rfc proposals:
- old nf_log_packet based infrastructure still in place
- serializes interesting parts, such as verdict, rule handle, table and chain
names into netlink attributes
- first message contains header data in exta attributes for the three bases
(ll, nh, th).

I tested this with nft ingress, bridge and ip families with ipv4 and ipv6 on top.

Sample output:

trace id 848e1d00 bridge packet src 5e:95:99:72:ea:c5 dst 52:54:00:12:34:56 src 192.168.7.1 dst 192.168.7.10 len 84 ttl 64 id 39991 protocol 1 iif eth0
trace id 848e1d00 bridge raw prerouting rule verdict continue iif eth0
trace id 848e1d00 rule limit rate 1/second nftrace set 1 
trace id 848e1d00 bridge raw prerouting policy verdict accept iif eth0
trace id 848e1d00 ip filter input rule verdict accept iif br0
trace id 848e1d00 rule ip protocol icmp accept 
trace id 848e1c00 bridge packet src 5e:95:99:72:ea:c5 dst 52:54:ea:fe:ad:a6 src dead::47ed:79b0:2f7f dst dead::6438:3436:3a34:6430 len 64 hoplimit 64 protocol 58 iif eth0
trace id 848e1c00 bridge raw prerouting rule verdict continue iif eth0
trace id 848e1c00 rule limit rate 1/second nftrace set 1 
trace id 848e1c00 bridge raw prerouting policy verdict accept iif eth0
trace id 836fe400 bridge packet src 5e:95:99:72:ea:c5 dst 52:54:00:12:34:56 arpop 0x1 iif eth0
...

Note that I did not (yet?) add json or xml format for this, I'm not sure its worth it or needed.

First three patches are for the kernel.
Next two are for libnftl (most of the print/format stuff is there).
last patch is the nftables patch.

Cheers,
Florian


^ permalink raw reply	[flat|nested] 80+ messages in thread

* [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-24 10:02 [PATCH 0/6] nftables trace support Florian Westphal
@ 2015-11-24 10:02 ` Florian Westphal
  2015-11-24 10:17   ` Pablo Neira Ayuso
                     ` (3 more replies)
  2015-11-24 10:02 ` [PATCH nf-next 2/6] netfilter: nf_tables: wrap tracing with a static key Florian Westphal
                   ` (4 subsequent siblings)
  5 siblings, 4 replies; 80+ messages in thread
From: Florian Westphal @ 2015-11-24 10:02 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Florian Westphal

nft monitor mode can then decode and display this trace data.

Parts of LL/Network/Transport headers are provided as separate
attributes.

Otherwise, printing IP address data becomes virtually impossible
for userspace since in the case of the netdev family we really don't
want userspace to have to know all the possible link layer types
and/or sizes just to display/print an ip address.

We also don't want userspace to have to follow ipv6 header chains
to get the s/dport info, the kernel already did this work so just
follow suit.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 include/net/netfilter/nf_tables.h        |   6 +
 include/uapi/linux/netfilter/nf_tables.h |  32 ++++++
 net/netfilter/nf_tables_api.c            | 190 +++++++++++++++++++++++++++++++
 net/netfilter/nf_tables_core.c           |  28 +++--
 net/netfilter/nft_meta.c                 |   3 +
 5 files changed, 252 insertions(+), 7 deletions(-)

diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 4bd7508..5131ad4 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -890,6 +890,12 @@ void nft_unregister_chain_type(const struct nf_chain_type *);
 int nft_register_expr(struct nft_expr_type *);
 void nft_unregister_expr(struct nft_expr_type *);
 
+void nf_tables_trace_notify(const struct nft_pktinfo *pkt,
+			    const struct nft_chain *chain,
+			    const struct nft_rule *rule,
+			    u32 verdict,
+			    enum nft_trace_types type);
+
 #define nft_dereference(p)					\
 	nfnl_dereference(p, NFNL_SUBSYS_NFTABLES)
 
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index d8c8a7c..88bcd00 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -83,6 +83,7 @@ enum nft_verdicts {
  * @NFT_MSG_DELSETELEM: delete a set element (enum nft_set_elem_attributes)
  * @NFT_MSG_NEWGEN: announce a new generation, only for events (enum nft_gen_attributes)
  * @NFT_MSG_GETGEN: get the rule-set generation (enum nft_gen_attributes)
+ * @NFT_MSG_TRACE: trace event (enum nft_trace_attributes)
  */
 enum nf_tables_msg_types {
 	NFT_MSG_NEWTABLE,
@@ -102,6 +103,7 @@ enum nf_tables_msg_types {
 	NFT_MSG_DELSETELEM,
 	NFT_MSG_NEWGEN,
 	NFT_MSG_GETGEN,
+	NFT_MSG_TRACE,
 	NFT_MSG_MAX,
 };
 
@@ -970,4 +972,34 @@ enum nft_gen_attributes {
 };
 #define NFTA_GEN_MAX		(__NFTA_GEN_MAX - 1)
 
+enum nft_trace_attibutes {
+	NFTA_TRACE_UNSPEC,
+	NFTA_TRACE_CHAIN,
+	NFTA_TRACE_DEV_TYPE,
+	NFTA_TRACE_ID,
+	NFTA_TRACE_IIF,
+	NFTA_TRACE_OIF,
+	NFTA_TRACE_LL_HEADER,
+	NFTA_TRACE_MARK,
+	NFTA_TRACE_NETWORK_HEADER,
+	NFTA_TRACE_TABLE,
+	NFTA_TRACE_TRANSPORT_HEADER,
+	NFTA_TRACE_TRANSPORT_PROTO,
+	NFTA_TRACE_TYPE,
+	NFTA_TRACE_RULE_HANDLE,
+	NFTA_TRACE_VERDICT,
+	NFTA_TRACE_VLAN_TAG,
+	__NFTA_TRACE_MAX
+};
+#define NFTA_TRACE_MAX (__NFTA_TRACE_MAX - 1)
+
+enum nft_trace_types {
+	NFT_TRACETYPE_UNSPEC,
+	NFT_TRACETYPE_PACKET,
+	NFT_TRACETYPE_POLICY,
+	NFT_TRACETYPE_RETURN,
+	NFT_TRACETYPE_RULE,
+	__NFT_TRACETYPE_MAX
+};
+#define NFT_TRACETYPE_MAX (__NFT_TRACETYPE_MAX - 1)
 #endif /* _LINUX_NF_TABLES_H */
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 93cc473..25d8168 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -9,6 +9,8 @@
  */
 
 #include <linux/module.h>
+#include <linux/hash.h>
+#include <linux/if_vlan.h>
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/skbuff.h>
@@ -21,6 +23,10 @@
 #include <net/net_namespace.h>
 #include <net/sock.h>
 
+#define NFT_TRACETYPE_LL_HSIZE		20
+#define NFT_TRACETYPE_NETWORK_HSIZE	32
+#define NFT_TRACETYPE_TRANSPORT_HSIZE	 4
+
 static LIST_HEAD(nf_tables_expressions);
 
 /**
@@ -468,6 +474,84 @@ nla_put_failure:
 	return -1;
 }
 
+static bool trace_notify_put_data(struct sk_buff *nlskb, u16 type,
+				  const struct sk_buff *skb,
+				  int off, unsigned int plen)
+{
+	struct nlattr *nla;
+
+	if (skb_tailroom(nlskb) < nla_total_size(plen))
+		return false;
+
+	nla = (struct nlattr *)skb_put(nlskb, nla_total_size(plen));
+	nla->nla_type = type;
+	nla->nla_len = nla_attr_size(plen);
+
+	if (skb_copy_bits(skb, off, nla_data(nla), plen))
+		return false;
+
+	return true;
+}
+
+static bool
+trace_notify_put_packet(struct sk_buff *nlskb, const struct nft_pktinfo *pkt)
+{
+	const struct sk_buff *skb = pkt->skb;
+	unsigned int plen = min_t(unsigned int,
+				  pkt->xt.thoff - skb_network_offset(skb),
+				  NFT_TRACETYPE_NETWORK_HSIZE);
+	int mac_off;
+
+	if (plen >= 20u && /* minimum iphdr size */
+	    !trace_notify_put_data(nlskb, NFTA_TRACE_NETWORK_HEADER,
+				   skb, skb_network_offset(skb), plen))
+		return false;
+
+	if (nla_put_u8(nlskb, NFTA_TRACE_TRANSPORT_PROTO, pkt->tprot))
+		return false;
+
+	plen = min_t(unsigned int, skb->len - pkt->xt.thoff,
+		     NFT_TRACETYPE_TRANSPORT_HSIZE);
+
+	if (plen >= sizeof(u32) &&
+	    !trace_notify_put_data(nlskb, NFTA_TRACE_TRANSPORT_HEADER,
+				   skb, pkt->xt.thoff, plen))
+		return false;
+
+	switch (pkt->pf) {
+	case NFPROTO_ARP: /* fallthrough */
+	case NFPROTO_BRIDGE:
+		break;
+	case NFPROTO_NETDEV:
+		if (WARN_ON_ONCE(!skb->dev))
+			break;
+		if (nla_put_be16(nlskb, NFTA_TRACE_DEV_TYPE,
+				 htons(skb->dev->type)))
+			return false;
+		break;
+	default:
+		return true;
+	}
+
+	if (skb_vlan_tag_get(skb) &&
+	    !nla_put_be16(nlskb, NFTA_TRACE_VLAN_TAG,
+			  htons(skb_vlan_tag_get(skb))))
+		return false;
+
+	if (!skb_mac_header_was_set(skb))
+		return true;
+
+	plen = min_t(unsigned int,
+		     skb->data - skb_mac_header(skb), NFT_TRACETYPE_LL_HSIZE);
+	mac_off = skb_mac_header(skb) - skb->data;
+
+	if (plen && !trace_notify_put_data(nlskb, NFTA_TRACE_LL_HEADER,
+					   skb, mac_off, plen))
+		return false;
+
+	return true;
+}
+
 static int nf_tables_table_notify(const struct nft_ctx *ctx, int event)
 {
 	struct sk_buff *skb;
@@ -499,6 +583,112 @@ err:
 	return err;
 }
 
+void nf_tables_trace_notify(const struct nft_pktinfo *pkt,
+			    const struct nft_chain *chain,
+			    const struct nft_rule *rule,
+			    u32 verdict,
+			    enum nft_trace_types type)
+{
+	struct nfgenmsg *nfmsg;
+	struct nlmsghdr *nlh;
+	struct sk_buff *skb;
+	unsigned int size;
+	int event = (NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_TRACE;
+
+	if (!nfnetlink_has_listeners(pkt->net, NFNLGRP_NFTABLES))
+		return;
+
+	/* Unlike other notifiers we need GFP_ATOMIC so use actual size
+	 * needed instead of NLMSG_GOODSIZE.
+	 */
+	size = nlmsg_total_size(sizeof(struct nfgenmsg))
+		+ nla_total_size(sizeof(__be32))	/* trace type */
+		+ nla_total_size(NFT_TABLE_MAXNAMELEN)
+		+ nla_total_size(NFT_CHAIN_MAXNAMELEN)
+		+ nla_total_size(sizeof(u32))	/* iif */
+		+ nla_total_size(sizeof(u32))	/* oif */
+		+ nla_total_size(sizeof(u32))	/* id */
+		+ nla_total_size(sizeof(u32))	/* mark */
+		+ nla_total_size(sizeof(u32))	/* verdict */
+		+ nla_total_size(sizeof(__be64)); /* rule handle */
+
+	switch (type) {
+	case NFT_TRACETYPE_PACKET:
+		size += nla_total_size(NFT_TRACETYPE_NETWORK_HSIZE)
+			+ nla_total_size(NFT_TRACETYPE_TRANSPORT_HSIZE)
+			+ nla_total_size(NFT_TRACETYPE_LL_HSIZE)
+			+ nla_total_size(sizeof(__be16)) /* vlan tag */
+			+ nla_total_size(sizeof(__be16)) /* device type */
+			+ nla_total_size(sizeof(__u8));  /* transport prot */
+		break;
+	default:
+		break;
+	}
+
+	skb = nlmsg_new(size, GFP_ATOMIC);
+	if (!skb)
+		return;
+
+	nlh = nlmsg_put(skb, 0, 0, event, sizeof(struct nfgenmsg), 0);
+	if (!nlh)
+		goto nla_put_failure;
+
+	nfmsg = nlmsg_data(nlh);
+	nfmsg->nfgen_family	= pkt->pf;
+	nfmsg->version		= NFNETLINK_V0;
+	nfmsg->res_id		= htons(pkt->net->nft.base_seq & 0xffff);
+
+	if (nla_put_be32(skb, NFTA_TRACE_TYPE, htonl(type)))
+		goto nla_put_failure;
+
+	if (nla_put_be32(skb, NFTA_TRACE_ID, htonl(hash32_ptr(pkt->skb))))
+		goto nla_put_failure;
+
+	if (chain) {
+		if (nla_put_string(skb, NFTA_TRACE_TABLE, chain->table->name))
+			goto nla_put_failure;
+		if (nla_put_string(skb, NFTA_TRACE_CHAIN, chain->name))
+			goto nla_put_failure;
+	}
+
+	if (rule && nla_put_be64(skb, NFTA_TRACE_RULE_HANDLE,
+				 cpu_to_be64(rule->handle)))
+		goto nla_put_failure;
+
+	if (pkt->in &&
+	    nla_put_be32(skb, NFTA_TRACE_IIF, htonl(pkt->in->ifindex)))
+		goto nla_put_failure;
+	if (pkt->out &&
+	    nla_put_be32(skb, NFTA_TRACE_OIF, htonl(pkt->out->ifindex)))
+		goto nla_put_failure;
+	if (pkt->skb->mark &&
+	    nla_put_be32(skb, NFTA_TRACE_MARK, htonl(pkt->skb->mark)))
+		goto nla_put_failure;
+
+	switch (type) {
+	case NFT_TRACETYPE_POLICY:
+	case NFT_TRACETYPE_RETURN:
+	case NFT_TRACETYPE_RULE:
+		if (nla_put_be32(skb, NFTA_TRACE_VERDICT, htonl(verdict)))
+			goto nla_put_failure;
+		break;
+	case NFT_TRACETYPE_PACKET:
+		if (!trace_notify_put_packet(skb, pkt))
+			goto nla_put_failure;
+		break;
+	default:
+		break;
+	}
+
+	nlmsg_end(skb, nlh);
+	nfnetlink_send(skb, pkt->net, 0, NFNLGRP_NFTABLES, 0, GFP_ATOMIC);
+	return;
+
+ nla_put_failure:
+	WARN_ON_ONCE(1);
+	kfree_skb(skb);
+}
+
 static int nf_tables_dump_tables(struct sk_buff *skb,
 				 struct netlink_callback *cb)
 {
diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
index f3695a4..29a6ca9 100644
--- a/net/netfilter/nf_tables_core.c
+++ b/net/netfilter/nf_tables_core.c
@@ -56,10 +56,15 @@ static void __nft_trace_packet(const struct nft_pktinfo *pkt,
 
 static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
 				    const struct nft_chain *chain,
-				    int rulenum, enum nft_trace type)
+				    const struct nft_rule *rule,
+				    int rulenum,
+				    u32 verdict,
+				    enum nft_trace_types type)
 {
-	if (unlikely(pkt->skb->nf_trace))
+	if (unlikely(pkt->skb->nf_trace)) {
+		nf_tables_trace_notify(pkt, chain, rule, verdict, type);
 		__nft_trace_packet(pkt, chain, rulenum, type);
+	}
 }
 
 static void nft_cmp_fast_eval(const struct nft_expr *expr,
@@ -151,7 +156,8 @@ next_rule:
 			regs.verdict.code = NFT_CONTINUE;
 			continue;
 		case NFT_CONTINUE:
-			nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
+			nft_trace_packet(pkt, chain, rule, rulenum,
+					 regs.verdict.code, NFT_TRACETYPE_RULE);
 			continue;
 		}
 		break;
@@ -161,7 +167,9 @@ next_rule:
 	case NF_ACCEPT:
 	case NF_DROP:
 	case NF_QUEUE:
-		nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
+		nft_trace_packet(pkt, chain, rule, rulenum,
+				 regs.verdict.code & NF_VERDICT_MASK,
+				 NFT_TRACETYPE_RULE);
 		return regs.verdict.code;
 	}
 
@@ -174,7 +182,8 @@ next_rule:
 		stackptr++;
 		/* fall through */
 	case NFT_GOTO:
-		nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
+		nft_trace_packet(pkt, chain, rule, rulenum,
+				 regs.verdict.code, NFT_TRACETYPE_RULE);
 
 		chain = regs.verdict.chain;
 		goto do_chain;
@@ -182,7 +191,10 @@ next_rule:
 		rulenum++;
 		/* fall through */
 	case NFT_RETURN:
-		nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RETURN);
+		if (stackptr)
+			nft_trace_packet(pkt, chain, rule, rulenum,
+					 regs.verdict.code,
+					 NFT_TRACETYPE_RETURN);
 		break;
 	default:
 		WARN_ON(1);
@@ -196,7 +208,9 @@ next_rule:
 		goto next_rule;
 	}
 
-	nft_trace_packet(pkt, basechain, -1, NFT_TRACE_POLICY);
+	nft_trace_packet(pkt, basechain, NULL, -1,
+			 nft_base_chain(basechain)->policy,
+			 NFT_TRACETYPE_POLICY);
 
 	rcu_read_lock_bh();
 	stats = this_cpu_ptr(rcu_dereference(nft_base_chain(basechain)->stats));
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
index 9dfaf4d..e94526a 100644
--- a/net/netfilter/nft_meta.c
+++ b/net/netfilter/nft_meta.c
@@ -204,6 +204,9 @@ void nft_meta_set_eval(const struct nft_expr *expr,
 		skb->priority = value;
 		break;
 	case NFT_META_NFTRACE:
+		if (skb->nf_trace == 0)
+			nf_tables_trace_notify(pkt, NULL, NULL, 0,
+					       NFT_TRACETYPE_PACKET);
 		skb->nf_trace = 1;
 		break;
 	default:
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH nf-next 2/6] netfilter: nf_tables: wrap tracing with a static key
  2015-11-24 10:02 [PATCH 0/6] nftables trace support Florian Westphal
  2015-11-24 10:02 ` [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure Florian Westphal
@ 2015-11-24 10:02 ` Florian Westphal
  2015-11-24 10:13   ` Patrick McHardy
  2015-11-24 10:19   ` Pablo Neira Ayuso
  2015-11-24 10:02 ` [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present Florian Westphal
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 80+ messages in thread
From: Florian Westphal @ 2015-11-24 10:02 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Florian Westphal

Only needed when meta nftrace rule(s) were added.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 include/net/netfilter/nf_tables_core.h |  1 +
 include/net/netfilter/nft_meta.h       |  3 +++
 net/bridge/netfilter/nft_meta_bridge.c |  1 +
 net/netfilter/nf_tables_core.c         | 20 +++++++++++++++-----
 net/netfilter/nft_meta.c               | 15 +++++++++++++++
 5 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/include/net/netfilter/nf_tables_core.h b/include/net/netfilter/nf_tables_core.h
index c6f400c..8ad6240 100644
--- a/include/net/netfilter/nf_tables_core.h
+++ b/include/net/netfilter/nf_tables_core.h
@@ -48,6 +48,7 @@ struct nft_payload {
 };
 
 extern const struct nft_expr_ops nft_payload_fast_ops;
+extern struct static_key nft_trace_enabled;
 
 int nft_payload_module_init(void);
 void nft_payload_module_exit(void);
diff --git a/include/net/netfilter/nft_meta.h b/include/net/netfilter/nft_meta.h
index 711887a..d27588c 100644
--- a/include/net/netfilter/nft_meta.h
+++ b/include/net/netfilter/nft_meta.h
@@ -33,4 +33,7 @@ void nft_meta_set_eval(const struct nft_expr *expr,
 		       struct nft_regs *regs,
 		       const struct nft_pktinfo *pkt);
 
+void nft_meta_set_destroy(const struct nft_ctx *ctx,
+			  const struct nft_expr *expr);
+
 #endif
diff --git a/net/bridge/netfilter/nft_meta_bridge.c b/net/bridge/netfilter/nft_meta_bridge.c
index a21269b..4b901d9 100644
--- a/net/bridge/netfilter/nft_meta_bridge.c
+++ b/net/bridge/netfilter/nft_meta_bridge.c
@@ -84,6 +84,7 @@ static const struct nft_expr_ops nft_meta_bridge_set_ops = {
 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_meta)),
 	.eval		= nft_meta_set_eval,
 	.init		= nft_meta_set_init,
+	.destroy	= nft_meta_set_destroy,
 	.dump		= nft_meta_set_dump,
 };
 
diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
index 29a6ca9..dabf5ed 100644
--- a/net/netfilter/nf_tables_core.c
+++ b/net/netfilter/nf_tables_core.c
@@ -16,6 +16,7 @@
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
 #include <linux/netfilter.h>
+#include <linux/static_key.h>
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nf_tables.h>
 #include <net/netfilter/nf_tables_core.h>
@@ -54,6 +55,9 @@ static void __nft_trace_packet(const struct nft_pktinfo *pkt,
 		     rulenum);
 }
 
+struct static_key nft_trace_enabled __read_mostly;
+EXPORT_SYMBOL_GPL(nft_trace_enabled);
+
 static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
 				    const struct nft_chain *chain,
 				    const struct nft_rule *rule,
@@ -61,7 +65,9 @@ static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
 				    u32 verdict,
 				    enum nft_trace_types type)
 {
-	if (unlikely(pkt->skb->nf_trace)) {
+	if (static_key_false(&nft_trace_enabled)) {
+		if (!pkt->skb->nf_trace)
+			return;
 		nf_tables_trace_notify(pkt, chain, rule, verdict, type);
 		__nft_trace_packet(pkt, chain, rulenum, type);
 	}
@@ -138,7 +144,8 @@ next_rule:
 		if (unlikely(rule->genmask & (1 << gencursor)))
 			continue;
 
-		rulenum++;
+		if (static_key_false(&nft_trace_enabled))
+			rulenum++;
 
 		nft_rule_for_each_expr(expr, last, rule) {
 			if (expr->ops == &nft_cmp_fast_ops)
@@ -178,7 +185,8 @@ next_rule:
 		BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE);
 		jumpstack[stackptr].chain = chain;
 		jumpstack[stackptr].rule  = rule;
-		jumpstack[stackptr].rulenum = rulenum;
+		if (static_key_false(&nft_trace_enabled))
+			jumpstack[stackptr].rulenum = rulenum;
 		stackptr++;
 		/* fall through */
 	case NFT_GOTO:
@@ -188,7 +196,8 @@ next_rule:
 		chain = regs.verdict.chain;
 		goto do_chain;
 	case NFT_CONTINUE:
-		rulenum++;
+		if (static_key_false(&nft_trace_enabled))
+			rulenum++;
 		/* fall through */
 	case NFT_RETURN:
 		if (stackptr)
@@ -204,7 +213,8 @@ next_rule:
 		stackptr--;
 		chain = jumpstack[stackptr].chain;
 		rule  = jumpstack[stackptr].rule;
-		rulenum = jumpstack[stackptr].rulenum;
+		if (static_key_false(&nft_trace_enabled))
+			rulenum = jumpstack[stackptr].rulenum;
 		goto next_rule;
 	}
 
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
index e94526a..c2a60ac 100644
--- a/net/netfilter/nft_meta.c
+++ b/net/netfilter/nft_meta.c
@@ -18,10 +18,12 @@
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/smp.h>
+#include <linux/static_key.h>
 #include <net/dst.h>
 #include <net/sock.h>
 #include <net/tcp_states.h> /* for TCP_TIME_WAIT */
 #include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nf_tables_core.h>
 #include <net/netfilter/nft_meta.h>
 
 void nft_meta_get_eval(const struct nft_expr *expr,
@@ -300,6 +302,9 @@ int nft_meta_set_init(const struct nft_ctx *ctx,
 	if (err < 0)
 		return err;
 
+	if (priv->key == NFT_META_NFTRACE)
+		static_key_slow_inc(&nft_trace_enabled);
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(nft_meta_set_init);
@@ -337,6 +342,15 @@ nla_put_failure:
 }
 EXPORT_SYMBOL_GPL(nft_meta_set_dump);
 
+void nft_meta_set_destroy(const struct nft_ctx *ctx,
+			  const struct nft_expr *expr)
+{
+	const struct nft_meta *priv = nft_expr_priv(expr);
+
+	if (priv->key == NFT_META_NFTRACE)
+		static_key_slow_dec(&nft_trace_enabled);
+}
+
 static struct nft_expr_type nft_meta_type;
 static const struct nft_expr_ops nft_meta_get_ops = {
 	.type		= &nft_meta_type,
@@ -351,6 +365,7 @@ static const struct nft_expr_ops nft_meta_set_ops = {
 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_meta)),
 	.eval		= nft_meta_set_eval,
 	.init		= nft_meta_set_init,
+	.destroy	= nft_meta_set_destroy,
 	.dump		= nft_meta_set_dump,
 };
 
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-24 10:02 [PATCH 0/6] nftables trace support Florian Westphal
  2015-11-24 10:02 ` [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure Florian Westphal
  2015-11-24 10:02 ` [PATCH nf-next 2/6] netfilter: nf_tables: wrap tracing with a static key Florian Westphal
@ 2015-11-24 10:02 ` Florian Westphal
  2015-11-24 10:16   ` Patrick McHardy
                     ` (2 more replies)
  2015-11-24 10:02 ` [PATCH libnftnl 4/6] src: rename EXPORT_SYMBOL to EXPORT_SYMBOL_ALIAS Florian Westphal
                   ` (2 subsequent siblings)
  5 siblings, 3 replies; 80+ messages in thread
From: Florian Westphal @ 2015-11-24 10:02 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Florian Westphal

No need to clutter nflog/dmesg ring buffer with the old tracing output
when the 'native' nfnetlink interface is used.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 net/netfilter/nf_tables_core.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
index dabf5ed..69bdd9a 100644
--- a/net/netfilter/nf_tables_core.c
+++ b/net/netfilter/nf_tables_core.c
@@ -55,6 +55,7 @@ static void __nft_trace_packet(const struct nft_pktinfo *pkt,
 		     rulenum);
 }
 
+static bool prefer_native_trace __read_mostly;
 struct static_key nft_trace_enabled __read_mostly;
 EXPORT_SYMBOL_GPL(nft_trace_enabled);
 
@@ -69,7 +70,13 @@ static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
 		if (!pkt->skb->nf_trace)
 			return;
 		nf_tables_trace_notify(pkt, chain, rule, verdict, type);
-		__nft_trace_packet(pkt, chain, rulenum, type);
+		if (prefer_native_trace)
+			return;
+
+		if (nfnetlink_has_listeners(pkt->net, NFNLGRP_NFTABLES))
+			prefer_native_trace = true;
+		else
+			__nft_trace_packet(pkt, chain, rulenum, type);
 	}
 }
 
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH libnftnl 4/6] src: rename EXPORT_SYMBOL to EXPORT_SYMBOL_ALIAS
  2015-11-24 10:02 [PATCH 0/6] nftables trace support Florian Westphal
                   ` (2 preceding siblings ...)
  2015-11-24 10:02 ` [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present Florian Westphal
@ 2015-11-24 10:02 ` Florian Westphal
  2015-11-24 10:11   ` Pablo Neira Ayuso
  2015-11-24 10:02 ` [PATCH libnftnl 5/6] src: add trace infrastructure support Florian Westphal
  2015-11-24 10:02 ` [PATCH nftables 6/6] src: add trace support to nft monitor mode Florian Westphal
  5 siblings, 1 reply; 80+ messages in thread
From: Florian Westphal @ 2015-11-24 10:02 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Florian Westphal

Future symbols don't need backwards-compat aliases.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 include/utils.h |  4 +++-
 src/batch.c     | 14 +++++------
 src/chain.c     | 68 ++++++++++++++++++++++++++--------------------------
 src/common.c    | 14 +++++------
 src/expr.c      | 32 ++++++++++++-------------
 src/gen.c       | 26 ++++++++++----------
 src/rule.c      | 74 ++++++++++++++++++++++++++++-----------------------------
 src/ruleset.c   | 32 ++++++++++++-------------
 src/set.c       | 64 ++++++++++++++++++++++++-------------------------
 src/set_elem.c  | 48 ++++++++++++++++++-------------------
 src/table.c     | 60 +++++++++++++++++++++++-----------------------
 11 files changed, 219 insertions(+), 217 deletions(-)

diff --git a/include/utils.h b/include/utils.h
index f7436fa..0087dbb 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -10,9 +10,11 @@
 #include "config.h"
 #ifdef HAVE_VISIBILITY_HIDDEN
 #	define __visible	__attribute__((visibility("default")))
-#	define EXPORT_SYMBOL(x, y)	typeof(x) (x) __visible; __typeof (y) y __attribute ((alias (#x), visibility ("default")))
+#	define EXPORT_SYMBOL(x)	typeof(x) (x) __visible;
+#	define EXPORT_SYMBOL_ALIAS(x, y)	typeof(x) (x) __visible; __typeof (y) y __attribute ((alias (#x), visibility ("default")))
 #else
 #	define EXPORT_SYMBOL
+#	define EXPORT_SYMBOL_ALIAS
 #endif
 
 #define __noreturn	__attribute__((__noreturn__))
diff --git a/src/batch.c b/src/batch.c
index a001288..7299ff6 100644
--- a/src/batch.c
+++ b/src/batch.c
@@ -80,7 +80,7 @@ err1:
 	free(batch);
 	return NULL;
 }
-EXPORT_SYMBOL(nftnl_batch_alloc, nft_batch_alloc);
+EXPORT_SYMBOL_ALIAS(nftnl_batch_alloc, nft_batch_alloc);
 
 void nftnl_batch_free(struct nftnl_batch *batch)
 {
@@ -94,7 +94,7 @@ void nftnl_batch_free(struct nftnl_batch *batch)
 
 	free(batch);
 }
-EXPORT_SYMBOL(nftnl_batch_free, nft_batch_free);
+EXPORT_SYMBOL_ALIAS(nftnl_batch_free, nft_batch_free);
 
 int nftnl_batch_update(struct nftnl_batch *batch)
 {
@@ -119,19 +119,19 @@ int nftnl_batch_update(struct nftnl_batch *batch)
 err1:
 	return -1;
 }
-EXPORT_SYMBOL(nftnl_batch_update, nft_batch_update);
+EXPORT_SYMBOL_ALIAS(nftnl_batch_update, nft_batch_update);
 
 void *nftnl_batch_buffer(struct nftnl_batch *batch)
 {
 	return mnl_nlmsg_batch_current(batch->current_page->batch);
 }
-EXPORT_SYMBOL(nftnl_batch_buffer, nft_batch_buffer);
+EXPORT_SYMBOL_ALIAS(nftnl_batch_buffer, nft_batch_buffer);
 
 uint32_t nftnl_batch_buffer_len(struct nftnl_batch *batch)
 {
 	return mnl_nlmsg_batch_size(batch->current_page->batch);
 }
-EXPORT_SYMBOL(nftnl_batch_buffer_len, nft_batch_buffer_len);
+EXPORT_SYMBOL_ALIAS(nftnl_batch_buffer_len, nft_batch_buffer_len);
 
 int nftnl_batch_iovec_len(struct nftnl_batch *batch)
 {
@@ -143,7 +143,7 @@ int nftnl_batch_iovec_len(struct nftnl_batch *batch)
 
 	return num_pages;
 }
-EXPORT_SYMBOL(nftnl_batch_iovec_len, nft_batch_iovec_len);
+EXPORT_SYMBOL_ALIAS(nftnl_batch_iovec_len, nft_batch_iovec_len);
 
 void nftnl_batch_iovec(struct nftnl_batch *batch, struct iovec *iov,
 		       uint32_t iovlen)
@@ -160,4 +160,4 @@ void nftnl_batch_iovec(struct nftnl_batch *batch, struct iovec *iov,
 		i++;
 	}
 }
-EXPORT_SYMBOL(nftnl_batch_iovec, nft_batch_iovec);
+EXPORT_SYMBOL_ALIAS(nftnl_batch_iovec, nft_batch_iovec);
diff --git a/src/chain.c b/src/chain.c
index 2b44a31..abfc58f 100644
--- a/src/chain.c
+++ b/src/chain.c
@@ -91,7 +91,7 @@ struct nftnl_chain *nftnl_chain_alloc(void)
 {
 	return calloc(1, sizeof(struct nftnl_chain));
 }
-EXPORT_SYMBOL(nftnl_chain_alloc, nft_chain_alloc);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_alloc, nft_chain_alloc);
 
 void nftnl_chain_free(struct nftnl_chain *c)
 {
@@ -104,13 +104,13 @@ void nftnl_chain_free(struct nftnl_chain *c)
 
 	xfree(c);
 }
-EXPORT_SYMBOL(nftnl_chain_free, nft_chain_free);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_free, nft_chain_free);
 
 bool nftnl_chain_is_set(const struct nftnl_chain *c, uint16_t attr)
 {
 	return c->flags & (1 << attr);
 }
-EXPORT_SYMBOL(nftnl_chain_is_set, nft_chain_attr_is_set);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_is_set, nft_chain_attr_is_set);
 
 void nftnl_chain_unset(struct nftnl_chain *c, uint16_t attr)
 {
@@ -153,7 +153,7 @@ void nftnl_chain_unset(struct nftnl_chain *c, uint16_t attr)
 
 	c->flags &= ~(1 << attr);
 }
-EXPORT_SYMBOL(nftnl_chain_unset, nft_chain_attr_unset);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_unset, nft_chain_attr_unset);
 
 static uint32_t nftnl_chain_validate[NFTNL_CHAIN_MAX + 1] = {
 	[NFTNL_CHAIN_HOOKNUM]	= sizeof(uint32_t),
@@ -222,43 +222,43 @@ void nftnl_chain_set_data(struct nftnl_chain *c, uint16_t attr,
 	}
 	c->flags |= (1 << attr);
 }
-EXPORT_SYMBOL(nftnl_chain_set_data, nft_chain_attr_set_data);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_set_data, nft_chain_attr_set_data);
 
 void nftnl_chain_set(struct nftnl_chain *c, uint16_t attr, const void *data)
 {
 	nftnl_chain_set_data(c, attr, data, nftnl_chain_validate[attr]);
 }
-EXPORT_SYMBOL(nftnl_chain_set, nft_chain_attr_set);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_set, nft_chain_attr_set);
 
 void nftnl_chain_set_u32(struct nftnl_chain *c, uint16_t attr, uint32_t data)
 {
 	nftnl_chain_set_data(c, attr, &data, sizeof(uint32_t));
 }
-EXPORT_SYMBOL(nftnl_chain_set_u32, nft_chain_attr_set_u32);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_set_u32, nft_chain_attr_set_u32);
 
 void nftnl_chain_set_s32(struct nftnl_chain *c, uint16_t attr, int32_t data)
 {
 	nftnl_chain_set_data(c, attr, &data, sizeof(int32_t));
 }
-EXPORT_SYMBOL(nftnl_chain_set_s32, nft_chain_attr_set_s32);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_set_s32, nft_chain_attr_set_s32);
 
 void nftnl_chain_set_u64(struct nftnl_chain *c, uint16_t attr, uint64_t data)
 {
 	nftnl_chain_set_data(c, attr, &data, sizeof(uint64_t));
 }
-EXPORT_SYMBOL(nftnl_chain_set_u64, nft_chain_attr_set_u64);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_set_u64, nft_chain_attr_set_u64);
 
 void nftnl_chain_set_u8(struct nftnl_chain *c, uint16_t attr, uint8_t data)
 {
 	nftnl_chain_set_data(c, attr, &data, sizeof(uint8_t));
 }
-EXPORT_SYMBOL(nftnl_chain_set_u8, nft_chain_attr_set_u8);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_set_u8, nft_chain_attr_set_u8);
 
 void nftnl_chain_set_str(struct nftnl_chain *c, uint16_t attr, const char *str)
 {
 	nftnl_chain_set_data(c, attr, str, strlen(str));
 }
-EXPORT_SYMBOL(nftnl_chain_set_str, nft_chain_attr_set_str);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_set_str, nft_chain_attr_set_str);
 
 const void *nftnl_chain_get_data(struct nftnl_chain *c, uint16_t attr,
 				    uint32_t *data_len)
@@ -303,20 +303,20 @@ const void *nftnl_chain_get_data(struct nftnl_chain *c, uint16_t attr,
 	}
 	return NULL;
 }
-EXPORT_SYMBOL(nftnl_chain_get_data, nft_chain_attr_get_data);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_get_data, nft_chain_attr_get_data);
 
 const void *nftnl_chain_get(struct nftnl_chain *c, uint16_t attr)
 {
 	uint32_t data_len;
 	return nftnl_chain_get_data(c, attr, &data_len);
 }
-EXPORT_SYMBOL(nftnl_chain_get, nft_chain_attr_get);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_get, nft_chain_attr_get);
 
 const char *nftnl_chain_get_str(struct nftnl_chain *c, uint16_t attr)
 {
 	return nftnl_chain_get(c, attr);
 }
-EXPORT_SYMBOL(nftnl_chain_get_str, nft_chain_attr_get_str);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_get_str, nft_chain_attr_get_str);
 
 uint32_t nftnl_chain_get_u32(struct nftnl_chain *c, uint16_t attr)
 {
@@ -327,7 +327,7 @@ uint32_t nftnl_chain_get_u32(struct nftnl_chain *c, uint16_t attr)
 
 	return val ? *val : 0;
 }
-EXPORT_SYMBOL(nftnl_chain_get_u32, nft_chain_attr_get_u32);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_get_u32, nft_chain_attr_get_u32);
 
 int32_t nftnl_chain_get_s32(struct nftnl_chain *c, uint16_t attr)
 {
@@ -338,7 +338,7 @@ int32_t nftnl_chain_get_s32(struct nftnl_chain *c, uint16_t attr)
 
 	return val ? *val : 0;
 }
-EXPORT_SYMBOL(nftnl_chain_get_s32, nft_chain_attr_get_s32);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_get_s32, nft_chain_attr_get_s32);
 
 uint64_t nftnl_chain_get_u64(struct nftnl_chain *c, uint16_t attr)
 {
@@ -349,7 +349,7 @@ uint64_t nftnl_chain_get_u64(struct nftnl_chain *c, uint16_t attr)
 
 	return val ? *val : 0;
 }
-EXPORT_SYMBOL(nftnl_chain_get_u64, nft_chain_attr_get_u64);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_get_u64, nft_chain_attr_get_u64);
 
 uint8_t nftnl_chain_get_u8(struct nftnl_chain *c, uint16_t attr)
 {
@@ -360,7 +360,7 @@ uint8_t nftnl_chain_get_u8(struct nftnl_chain *c, uint16_t attr)
 
 	return val ? *val : 0;
 }
-EXPORT_SYMBOL(nftnl_chain_get_u8, nft_chain_attr_get_u8);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_get_u8, nft_chain_attr_get_u8);
 
 void nftnl_chain_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_chain *c)
 {
@@ -397,7 +397,7 @@ void nftnl_chain_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_ch
 	if (c->flags & (1 << NFTNL_CHAIN_TYPE))
 		mnl_attr_put_strz(nlh, NFTA_CHAIN_TYPE, c->type);
 }
-EXPORT_SYMBOL(nftnl_chain_nlmsg_build_payload, nft_chain_nlmsg_build_payload);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_nlmsg_build_payload, nft_chain_nlmsg_build_payload);
 
 static int nftnl_chain_parse_attr_cb(const struct nlattr *attr, void *data)
 {
@@ -572,7 +572,7 @@ int nftnl_chain_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_chain *c)
 
 	return ret;
 }
-EXPORT_SYMBOL(nftnl_chain_nlmsg_parse, nft_chain_nlmsg_parse);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_nlmsg_parse, nft_chain_nlmsg_parse);
 
 static inline int nftnl_str2hooknum(int family, const char *hook)
 {
@@ -824,14 +824,14 @@ int nftnl_chain_parse(struct nftnl_chain *c, enum nftnl_parse_type type,
 {
 	return nftnl_chain_do_parse(c, type, data, err, NFTNL_PARSE_BUFFER);
 }
-EXPORT_SYMBOL(nftnl_chain_parse, nft_chain_parse);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_parse, nft_chain_parse);
 
 int nftnl_chain_parse_file(struct nftnl_chain *c, enum nftnl_parse_type type,
 			 FILE *fp, struct nftnl_parse_err *err)
 {
 	return nftnl_chain_do_parse(c, type, fp, err, NFTNL_PARSE_FILE);
 }
-EXPORT_SYMBOL(nftnl_chain_parse_file, nft_chain_parse_file);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_parse_file, nft_chain_parse_file);
 
 static int nftnl_chain_export(char *buf, size_t size, struct nftnl_chain *c,
 			    int type)
@@ -933,7 +933,7 @@ int nftnl_chain_snprintf(char *buf, size_t size, struct nftnl_chain *c,
 	return nftnl_chain_cmd_snprintf(buf, size, c, nftnl_flag2cmd(flags), type,
 				      flags);
 }
-EXPORT_SYMBOL(nftnl_chain_snprintf, nft_chain_snprintf);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_snprintf, nft_chain_snprintf);
 
 static inline int nftnl_chain_do_snprintf(char *buf, size_t size, void *c,
 					uint32_t cmd, uint32_t type,
@@ -948,7 +948,7 @@ int nftnl_chain_fprintf(FILE *fp, struct nftnl_chain *c, uint32_t type,
 	return nftnl_fprintf(fp, c, NFTNL_CMD_UNSPEC, type, flags,
 			   nftnl_chain_do_snprintf);
 }
-EXPORT_SYMBOL(nftnl_chain_fprintf, nft_chain_fprintf);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_fprintf, nft_chain_fprintf);
 
 struct nftnl_chain_list {
 	struct list_head list;
@@ -966,7 +966,7 @@ struct nftnl_chain_list *nftnl_chain_list_alloc(void)
 
 	return list;
 }
-EXPORT_SYMBOL(nftnl_chain_list_alloc, nft_chain_list_alloc);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_list_alloc, nft_chain_list_alloc);
 
 void nftnl_chain_list_free(struct nftnl_chain_list *list)
 {
@@ -978,31 +978,31 @@ void nftnl_chain_list_free(struct nftnl_chain_list *list)
 	}
 	xfree(list);
 }
-EXPORT_SYMBOL(nftnl_chain_list_free, nft_chain_list_free);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_list_free, nft_chain_list_free);
 
 int nftnl_chain_list_is_empty(struct nftnl_chain_list *list)
 {
 	return list_empty(&list->list);
 }
-EXPORT_SYMBOL(nftnl_chain_list_is_empty, nft_chain_list_is_empty);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_list_is_empty, nft_chain_list_is_empty);
 
 void nftnl_chain_list_add(struct nftnl_chain *r, struct nftnl_chain_list *list)
 {
 	list_add(&r->head, &list->list);
 }
-EXPORT_SYMBOL(nftnl_chain_list_add, nft_chain_list_add);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_list_add, nft_chain_list_add);
 
 void nftnl_chain_list_add_tail(struct nftnl_chain *r, struct nftnl_chain_list *list)
 {
 	list_add_tail(&r->head, &list->list);
 }
-EXPORT_SYMBOL(nftnl_chain_list_add_tail, nft_chain_list_add_tail);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_list_add_tail, nft_chain_list_add_tail);
 
 void nftnl_chain_list_del(struct nftnl_chain *r)
 {
 	list_del(&r->head);
 }
-EXPORT_SYMBOL(nftnl_chain_list_del, nft_chain_list_del);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_list_del, nft_chain_list_del);
 
 int nftnl_chain_list_foreach(struct nftnl_chain_list *chain_list,
 			   int (*cb)(struct nftnl_chain *r, void *data),
@@ -1018,7 +1018,7 @@ int nftnl_chain_list_foreach(struct nftnl_chain_list *chain_list,
 	}
 	return 0;
 }
-EXPORT_SYMBOL(nftnl_chain_list_foreach, nft_chain_list_foreach);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_list_foreach, nft_chain_list_foreach);
 
 struct nftnl_chain_list_iter {
 	struct nftnl_chain_list	*list;
@@ -1041,7 +1041,7 @@ struct nftnl_chain_list_iter *nftnl_chain_list_iter_create(struct nftnl_chain_li
 
 	return iter;
 }
-EXPORT_SYMBOL(nftnl_chain_list_iter_create, nft_chain_list_iter_create);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_list_iter_create, nft_chain_list_iter_create);
 
 struct nftnl_chain *nftnl_chain_list_iter_next(struct nftnl_chain_list_iter *iter)
 {
@@ -1057,10 +1057,10 @@ struct nftnl_chain *nftnl_chain_list_iter_next(struct nftnl_chain_list_iter *ite
 
 	return r;
 }
-EXPORT_SYMBOL(nftnl_chain_list_iter_next, nft_chain_list_iter_next);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_list_iter_next, nft_chain_list_iter_next);
 
 void nftnl_chain_list_iter_destroy(struct nftnl_chain_list_iter *iter)
 {
 	xfree(iter);
 }
-EXPORT_SYMBOL(nftnl_chain_list_iter_destroy, nft_chain_list_iter_destroy);
+EXPORT_SYMBOL_ALIAS(nftnl_chain_list_iter_destroy, nft_chain_list_iter_destroy);
diff --git a/src/common.c b/src/common.c
index 43d2cfd..5dda52f 100644
--- a/src/common.c
+++ b/src/common.c
@@ -40,7 +40,7 @@ struct nlmsghdr *nftnl_nlmsg_build_hdr(char *buf, uint16_t cmd, uint16_t family,
 
 	return nlh;
 }
-EXPORT_SYMBOL(nftnl_nlmsg_build_hdr, nft_nlmsg_build_hdr);
+EXPORT_SYMBOL_ALIAS(nftnl_nlmsg_build_hdr, nft_nlmsg_build_hdr);
 
 struct nftnl_parse_err *nftnl_parse_err_alloc(void)
 {
@@ -54,13 +54,13 @@ struct nftnl_parse_err *nftnl_parse_err_alloc(void)
 
 	return err;
 }
-EXPORT_SYMBOL(nftnl_parse_err_alloc, nft_parse_err_alloc);
+EXPORT_SYMBOL_ALIAS(nftnl_parse_err_alloc, nft_parse_err_alloc);
 
 void nftnl_parse_err_free(struct nftnl_parse_err *err)
 {
 	xfree(err);
 }
-EXPORT_SYMBOL(nftnl_parse_err_free, nft_parse_err_free);
+EXPORT_SYMBOL_ALIAS(nftnl_parse_err_free, nft_parse_err_free);
 
 int nftnl_parse_perror(const char *msg, struct nftnl_parse_err *err)
 {
@@ -80,7 +80,7 @@ int nftnl_parse_perror(const char *msg, struct nftnl_parse_err *err)
 		return fprintf(stderr, "%s: Undefined error\n", msg);
 	}
 }
-EXPORT_SYMBOL(nftnl_parse_perror, nft_parse_perror);
+EXPORT_SYMBOL_ALIAS(nftnl_parse_perror, nft_parse_perror);
 
 int nftnl_cmd_header_snprintf(char *buf, size_t size, uint32_t cmd, uint32_t type,
 			    uint32_t flags)
@@ -176,13 +176,13 @@ void nftnl_batch_begin(char *buf, uint32_t seq)
 {
 	nftnl_batch_build_hdr(buf, NFNL_MSG_BATCH_BEGIN, seq);
 }
-EXPORT_SYMBOL(nftnl_batch_begin, nft_batch_begin);
+EXPORT_SYMBOL_ALIAS(nftnl_batch_begin, nft_batch_begin);
 
 void nftnl_batch_end(char *buf, uint32_t seq)
 {
 	nftnl_batch_build_hdr(buf, NFNL_MSG_BATCH_END, seq);
 }
-EXPORT_SYMBOL(nftnl_batch_end, nft_batch_end);
+EXPORT_SYMBOL_ALIAS(nftnl_batch_end, nft_batch_end);
 
 int nftnl_batch_is_supported(void)
 {
@@ -241,4 +241,4 @@ err:
 	mnl_nlmsg_batch_stop(b);
 	return -1;
 }
-EXPORT_SYMBOL(nftnl_batch_is_supported, nft_batch_is_supported);
+EXPORT_SYMBOL_ALIAS(nftnl_batch_is_supported, nft_batch_is_supported);
diff --git a/src/expr.c b/src/expr.c
index 3249a5c..16d40d6 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -43,7 +43,7 @@ struct nftnl_expr *nftnl_expr_alloc(const char *name)
 
 	return expr;
 }
-EXPORT_SYMBOL(nftnl_expr_alloc, nft_rule_expr_alloc);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_alloc, nft_rule_expr_alloc);
 
 void nftnl_expr_free(struct nftnl_expr *expr)
 {
@@ -52,13 +52,13 @@ void nftnl_expr_free(struct nftnl_expr *expr)
 
 	xfree(expr);
 }
-EXPORT_SYMBOL(nftnl_expr_free, nft_rule_expr_free);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_free, nft_rule_expr_free);
 
 bool nftnl_expr_is_set(const struct nftnl_expr *expr, uint16_t type)
 {
 	return expr->flags & (1 << type);
 }
-EXPORT_SYMBOL(nftnl_expr_is_set, nft_rule_expr_is_set);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_is_set, nft_rule_expr_is_set);
 
 void
 nftnl_expr_set(struct nftnl_expr *expr, uint16_t type,
@@ -73,42 +73,42 @@ nftnl_expr_set(struct nftnl_expr *expr, uint16_t type,
 	}
 	expr->flags |= (1 << type);
 }
-EXPORT_SYMBOL(nftnl_expr_set, nft_rule_expr_set);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_set, nft_rule_expr_set);
 
 void
 nftnl_expr_set_u8(struct nftnl_expr *expr, uint16_t type, uint8_t data)
 {
 	nftnl_expr_set(expr, type, &data, sizeof(uint8_t));
 }
-EXPORT_SYMBOL(nftnl_expr_set_u8, nft_rule_expr_set_u8);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_set_u8, nft_rule_expr_set_u8);
 
 void
 nftnl_expr_set_u16(struct nftnl_expr *expr, uint16_t type, uint16_t data)
 {
 	nftnl_expr_set(expr, type, &data, sizeof(uint16_t));
 }
-EXPORT_SYMBOL(nftnl_expr_set_u16, nft_rule_expr_set_u16);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_set_u16, nft_rule_expr_set_u16);
 
 void
 nftnl_expr_set_u32(struct nftnl_expr *expr, uint16_t type, uint32_t data)
 {
 	nftnl_expr_set(expr, type, &data, sizeof(uint32_t));
 }
-EXPORT_SYMBOL(nftnl_expr_set_u32, nft_rule_expr_set_u32);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_set_u32, nft_rule_expr_set_u32);
 
 void
 nftnl_expr_set_u64(struct nftnl_expr *expr, uint16_t type, uint64_t data)
 {
 	nftnl_expr_set(expr, type, &data, sizeof(uint64_t));
 }
-EXPORT_SYMBOL(nftnl_expr_set_u64, nft_rule_expr_set_u64);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_set_u64, nft_rule_expr_set_u64);
 
 void
 nftnl_expr_set_str(struct nftnl_expr *expr, uint16_t type, const char *str)
 {
 	nftnl_expr_set(expr, type, str, strlen(str)+1);
 }
-EXPORT_SYMBOL(nftnl_expr_set_str, nft_rule_expr_set_str);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_set_str, nft_rule_expr_set_str);
 
 const void *nftnl_expr_get(const struct nftnl_expr *expr,
 			      uint16_t type, uint32_t *data_len)
@@ -129,7 +129,7 @@ const void *nftnl_expr_get(const struct nftnl_expr *expr,
 
 	return ret;
 }
-EXPORT_SYMBOL(nftnl_expr_get, nft_rule_expr_get);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_get, nft_rule_expr_get);
 
 uint8_t nftnl_expr_get_u8(const struct nftnl_expr *expr, uint16_t type)
 {
@@ -145,7 +145,7 @@ uint8_t nftnl_expr_get_u8(const struct nftnl_expr *expr, uint16_t type)
 
 	return *((uint8_t *)data);
 }
-EXPORT_SYMBOL(nftnl_expr_get_u8, nft_rule_expr_get_u8);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_get_u8, nft_rule_expr_get_u8);
 
 uint16_t nftnl_expr_get_u16(const struct nftnl_expr *expr, uint16_t type)
 {
@@ -161,7 +161,7 @@ uint16_t nftnl_expr_get_u16(const struct nftnl_expr *expr, uint16_t type)
 
 	return *((uint16_t *)data);
 }
-EXPORT_SYMBOL(nftnl_expr_get_u16, nft_rule_expr_get_u16);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_get_u16, nft_rule_expr_get_u16);
 
 uint32_t nftnl_expr_get_u32(const struct nftnl_expr *expr, uint16_t type)
 {
@@ -177,7 +177,7 @@ uint32_t nftnl_expr_get_u32(const struct nftnl_expr *expr, uint16_t type)
 
 	return *((uint32_t *)data);
 }
-EXPORT_SYMBOL(nftnl_expr_get_u32, nft_rule_expr_get_u32);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_get_u32, nft_rule_expr_get_u32);
 
 uint64_t nftnl_expr_get_u64(const struct nftnl_expr *expr, uint16_t type)
 {
@@ -193,7 +193,7 @@ uint64_t nftnl_expr_get_u64(const struct nftnl_expr *expr, uint16_t type)
 
 	return *((uint64_t *)data);
 }
-EXPORT_SYMBOL(nftnl_expr_get_u64, nft_rule_expr_get_u64);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_get_u64, nft_rule_expr_get_u64);
 
 const char *nftnl_expr_get_str(const struct nftnl_expr *expr, uint16_t type)
 {
@@ -201,7 +201,7 @@ const char *nftnl_expr_get_str(const struct nftnl_expr *expr, uint16_t type)
 
 	return (const char *)nftnl_expr_get(expr, type, &data_len);
 }
-EXPORT_SYMBOL(nftnl_expr_get_str, nft_rule_expr_get_str);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_get_str, nft_rule_expr_get_str);
 
 void
 nftnl_expr_build_payload(struct nlmsghdr *nlh, struct nftnl_expr *expr)
@@ -273,4 +273,4 @@ int nftnl_expr_snprintf(char *buf, size_t size, struct nftnl_expr *expr,
 
 	return offset;
 }
-EXPORT_SYMBOL(nftnl_expr_snprintf, nft_rule_expr_snprintf);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_snprintf, nft_rule_expr_snprintf);
diff --git a/src/gen.c b/src/gen.c
index eb3b70d..f864333 100644
--- a/src/gen.c
+++ b/src/gen.c
@@ -33,19 +33,19 @@ struct nftnl_gen *nftnl_gen_alloc(void)
 {
 	return calloc(1, sizeof(struct nftnl_gen));
 }
-EXPORT_SYMBOL(nftnl_gen_alloc, nft_gen_alloc);
+EXPORT_SYMBOL_ALIAS(nftnl_gen_alloc, nft_gen_alloc);
 
 void nftnl_gen_free(struct nftnl_gen *gen)
 {
 	xfree(gen);
 }
-EXPORT_SYMBOL(nftnl_gen_free, nft_gen_free);
+EXPORT_SYMBOL_ALIAS(nftnl_gen_free, nft_gen_free);
 
 bool nftnl_gen_is_set(const struct nftnl_gen *gen, uint16_t attr)
 {
 	return gen->flags & (1 << attr);
 }
-EXPORT_SYMBOL(nftnl_gen_is_set, nft_gen_attr_is_set);
+EXPORT_SYMBOL_ALIAS(nftnl_gen_is_set, nft_gen_attr_is_set);
 
 void nftnl_gen_unset(struct nftnl_gen *gen, uint16_t attr)
 {
@@ -58,7 +58,7 @@ void nftnl_gen_unset(struct nftnl_gen *gen, uint16_t attr)
 	}
 	gen->flags &= ~(1 << attr);
 }
-EXPORT_SYMBOL(nftnl_gen_unset, nft_gen_attr_unset);
+EXPORT_SYMBOL_ALIAS(nftnl_gen_unset, nft_gen_attr_unset);
 
 static uint32_t nftnl_gen_validate[NFTNL_GEN_MAX + 1] = {
 	[NFTNL_GEN_ID]	= sizeof(uint32_t),
@@ -79,19 +79,19 @@ void nftnl_gen_set_data(struct nftnl_gen *gen, uint16_t attr,
 	}
 	gen->flags |= (1 << attr);
 }
-EXPORT_SYMBOL(nftnl_gen_set_data, nft_gen_attr_set_data);
+EXPORT_SYMBOL_ALIAS(nftnl_gen_set_data, nft_gen_attr_set_data);
 
 void nftnl_gen_set(struct nftnl_gen *gen, uint16_t attr, const void *data)
 {
 	nftnl_gen_set_data(gen, attr, data, nftnl_gen_validate[attr]);
 }
-EXPORT_SYMBOL(nftnl_gen_set, nft_gen_attr_set);
+EXPORT_SYMBOL_ALIAS(nftnl_gen_set, nft_gen_attr_set);
 
 void nftnl_gen_set_u32(struct nftnl_gen *gen, uint16_t attr, uint32_t val)
 {
 	nftnl_gen_set_data(gen, attr, &val, sizeof(uint32_t));
 }
-EXPORT_SYMBOL(nftnl_gen_set_u32, nft_gen_attr_set_u32);
+EXPORT_SYMBOL_ALIAS(nftnl_gen_set_u32, nft_gen_attr_set_u32);
 
 const void *nftnl_gen_get_data(struct nftnl_gen *gen, uint16_t attr,
 				  uint32_t *data_len)
@@ -105,21 +105,21 @@ const void *nftnl_gen_get_data(struct nftnl_gen *gen, uint16_t attr,
 	}
 	return NULL;
 }
-EXPORT_SYMBOL(nftnl_gen_get_data, nft_gen_attr_get_data);
+EXPORT_SYMBOL_ALIAS(nftnl_gen_get_data, nft_gen_attr_get_data);
 
 const void *nftnl_gen_get(struct nftnl_gen *gen, uint16_t attr)
 {
 	uint32_t data_len;
 	return nftnl_gen_get_data(gen, attr, &data_len);
 }
-EXPORT_SYMBOL(nftnl_gen_get, nft_gen_attr_get);
+EXPORT_SYMBOL_ALIAS(nftnl_gen_get, nft_gen_attr_get);
 
 uint32_t nftnl_gen_get_u32(struct nftnl_gen *gen, uint16_t attr)
 {
 	const void *ret = nftnl_gen_get(gen, attr);
 	return ret == NULL ? 0 : *((uint32_t *)ret);
 }
-EXPORT_SYMBOL(nftnl_gen_get_u32, nft_gen_attr_get_u32);
+EXPORT_SYMBOL_ALIAS(nftnl_gen_get_u32, nft_gen_attr_get_u32);
 
 static int nftnl_gen_parse_attr_cb(const struct nlattr *attr, void *data)
 {
@@ -154,7 +154,7 @@ int nftnl_gen_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_gen *gen)
 	}
 	return 0;
 }
-EXPORT_SYMBOL(nftnl_gen_nlmsg_parse, nft_gen_nlmsg_parse);
+EXPORT_SYMBOL_ALIAS(nftnl_gen_nlmsg_parse, nft_gen_nlmsg_parse);
 
 static int nftnl_gen_snprintf_default(char *buf, size_t size, struct nftnl_gen *gen)
 {
@@ -190,7 +190,7 @@ int nftnl_gen_snprintf(char *buf, size_t size, struct nftnl_gen *gen, uint32_t t
 	return nftnl_gen_cmd_snprintf(buf, size, gen, nftnl_flag2cmd(flags), type,
 				    flags);
 }
-EXPORT_SYMBOL(nftnl_gen_snprintf, nft_gen_snprintf);
+EXPORT_SYMBOL_ALIAS(nftnl_gen_snprintf, nft_gen_snprintf);
 
 static inline int nftnl_gen_do_snprintf(char *buf, size_t size, void *gen,
 				      uint32_t cmd, uint32_t type,
@@ -205,4 +205,4 @@ int nftnl_gen_fprintf(FILE *fp, struct nftnl_gen *gen, uint32_t type,
 	return nftnl_fprintf(fp, gen, NFTNL_CMD_UNSPEC, type, flags,
 			   nftnl_gen_do_snprintf);
 }
-EXPORT_SYMBOL(nftnl_gen_fprintf, nft_gen_fprintf);
+EXPORT_SYMBOL_ALIAS(nftnl_gen_fprintf, nft_gen_fprintf);
diff --git a/src/rule.c b/src/rule.c
index 0fb27ed..3a32bf6 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -62,7 +62,7 @@ struct nftnl_rule *nftnl_rule_alloc(void)
 
 	return r;
 }
-EXPORT_SYMBOL(nftnl_rule_alloc, nft_rule_alloc);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_alloc, nft_rule_alloc);
 
 void nftnl_rule_free(struct nftnl_rule *r)
 {
@@ -78,13 +78,13 @@ void nftnl_rule_free(struct nftnl_rule *r)
 
 	xfree(r);
 }
-EXPORT_SYMBOL(nftnl_rule_free, nft_rule_free);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_free, nft_rule_free);
 
 bool nftnl_rule_is_set(const struct nftnl_rule *r, uint16_t attr)
 {
 	return r->flags & (1 << attr);
 }
-EXPORT_SYMBOL(nftnl_rule_is_set, nft_rule_attr_is_set);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_is_set, nft_rule_attr_is_set);
 
 void nftnl_rule_unset(struct nftnl_rule *r, uint16_t attr)
 {
@@ -115,7 +115,7 @@ void nftnl_rule_unset(struct nftnl_rule *r, uint16_t attr)
 
 	r->flags &= ~(1 << attr);
 }
-EXPORT_SYMBOL(nftnl_rule_unset, nft_rule_attr_unset);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_unset, nft_rule_attr_unset);
 
 static uint32_t nftnl_rule_validate[NFTNL_RULE_MAX + 1] = {
 	[NFTNL_RULE_HANDLE]		= sizeof(uint64_t),
@@ -168,31 +168,31 @@ void nftnl_rule_set_data(struct nftnl_rule *r, uint16_t attr,
 	}
 	r->flags |= (1 << attr);
 }
-EXPORT_SYMBOL(nftnl_rule_set_data, nft_rule_attr_set_data);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_set_data, nft_rule_attr_set_data);
 
 void nftnl_rule_set(struct nftnl_rule *r, uint16_t attr, const void *data)
 {
 	nftnl_rule_set_data(r, attr, data, nftnl_rule_validate[attr]);
 }
-EXPORT_SYMBOL(nftnl_rule_set, nft_rule_attr_set);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_set, nft_rule_attr_set);
 
 void nftnl_rule_set_u32(struct nftnl_rule *r, uint16_t attr, uint32_t val)
 {
 	nftnl_rule_set_data(r, attr, &val, sizeof(uint32_t));
 }
-EXPORT_SYMBOL(nftnl_rule_set_u32, nft_rule_attr_set_u32);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_set_u32, nft_rule_attr_set_u32);
 
 void nftnl_rule_set_u64(struct nftnl_rule *r, uint16_t attr, uint64_t val)
 {
 	nftnl_rule_set_data(r, attr, &val, sizeof(uint64_t));
 }
-EXPORT_SYMBOL(nftnl_rule_set_u64, nft_rule_attr_set_u64);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_set_u64, nft_rule_attr_set_u64);
 
 void nftnl_rule_set_str(struct nftnl_rule *r, uint16_t attr, const char *str)
 {
 	nftnl_rule_set_data(r, attr, str, strlen(str));
 }
-EXPORT_SYMBOL(nftnl_rule_set_str, nft_rule_attr_set_str);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_set_str, nft_rule_attr_set_str);
 
 const void *nftnl_rule_get_data(const struct nftnl_rule *r, uint16_t attr,
 				   uint32_t *data_len)
@@ -226,20 +226,20 @@ const void *nftnl_rule_get_data(const struct nftnl_rule *r, uint16_t attr,
 	}
 	return NULL;
 }
-EXPORT_SYMBOL(nftnl_rule_get_data, nft_rule_attr_get_data);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_get_data, nft_rule_attr_get_data);
 
 const void *nftnl_rule_get(const struct nftnl_rule *r, uint16_t attr)
 {
 	uint32_t data_len;
 	return nftnl_rule_get_data(r, attr, &data_len);
 }
-EXPORT_SYMBOL(nftnl_rule_get, nft_rule_attr_get);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_get, nft_rule_attr_get);
 
 const char *nftnl_rule_get_str(const struct nftnl_rule *r, uint16_t attr)
 {
 	return nftnl_rule_get(r, attr);
 }
-EXPORT_SYMBOL(nftnl_rule_get_str, nft_rule_attr_get_str);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_get_str, nft_rule_attr_get_str);
 
 uint32_t nftnl_rule_get_u32(const struct nftnl_rule *r, uint16_t attr)
 {
@@ -250,7 +250,7 @@ uint32_t nftnl_rule_get_u32(const struct nftnl_rule *r, uint16_t attr)
 
 	return val ? *val : 0;
 }
-EXPORT_SYMBOL(nftnl_rule_get_u32, nft_rule_attr_get_u32);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_get_u32, nft_rule_attr_get_u32);
 
 uint64_t nftnl_rule_get_u64(const struct nftnl_rule *r, uint16_t attr)
 {
@@ -261,7 +261,7 @@ uint64_t nftnl_rule_get_u64(const struct nftnl_rule *r, uint16_t attr)
 
 	return val ? *val : 0;
 }
-EXPORT_SYMBOL(nftnl_rule_get_u64, nft_rule_attr_get_u64);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_get_u64, nft_rule_attr_get_u64);
 
 uint8_t nftnl_rule_get_u8(const struct nftnl_rule *r, uint16_t attr)
 {
@@ -272,7 +272,7 @@ uint8_t nftnl_rule_get_u8(const struct nftnl_rule *r, uint16_t attr)
 
 	return val ? *val : 0;
 }
-EXPORT_SYMBOL(nftnl_rule_get_u8, nft_rule_attr_get_u8);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_get_u8, nft_rule_attr_get_u8);
 
 void nftnl_rule_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_rule *r)
 {
@@ -313,13 +313,13 @@ void nftnl_rule_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_rule *r)
 		mnl_attr_nest_end(nlh, nest);
 	}
 }
-EXPORT_SYMBOL(nftnl_rule_nlmsg_build_payload, nft_rule_nlmsg_build_payload);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_nlmsg_build_payload, nft_rule_nlmsg_build_payload);
 
 void nftnl_rule_add_expr(struct nftnl_rule *r, struct nftnl_expr *expr)
 {
 	list_add_tail(&expr->head, &r->expr_list);
 }
-EXPORT_SYMBOL(nftnl_rule_add_expr, nft_rule_add_expr);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_add_expr, nft_rule_add_expr);
 
 static int nftnl_rule_parse_attr_cb(const struct nlattr *attr, void *data)
 {
@@ -468,7 +468,7 @@ int nftnl_rule_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_rule *r)
 
 	return ret;
 }
-EXPORT_SYMBOL(nftnl_rule_nlmsg_parse, nft_rule_nlmsg_parse);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_nlmsg_parse, nft_rule_nlmsg_parse);
 
 #ifdef JSON_PARSING
 int nftnl_jansson_parse_rule(struct nftnl_rule *r, json_t *tree,
@@ -702,14 +702,14 @@ int nftnl_rule_parse(struct nftnl_rule *r, enum nftnl_parse_type type,
 {
 	return nftnl_rule_do_parse(r, type, data, err, NFTNL_PARSE_BUFFER);
 }
-EXPORT_SYMBOL(nftnl_rule_parse, nft_rule_parse);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_parse, nft_rule_parse);
 
 int nftnl_rule_parse_file(struct nftnl_rule *r, enum nftnl_parse_type type,
 			FILE *fp, struct nftnl_parse_err *err)
 {
 	return nftnl_rule_do_parse(r, type, fp, err, NFTNL_PARSE_FILE);
 }
-EXPORT_SYMBOL(nftnl_rule_parse_file, nft_rule_parse_file);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_parse_file, nft_rule_parse_file);
 
 static int nftnl_rule_snprintf_json(char *buf, size_t size, struct nftnl_rule *r,
 					 uint32_t type, uint32_t flags)
@@ -967,7 +967,7 @@ int nftnl_rule_snprintf(char *buf, size_t size, struct nftnl_rule *r,
 	return nftnl_rule_cmd_snprintf(buf, size, r, nftnl_flag2cmd(flags), type,
 				     flags);
 }
-EXPORT_SYMBOL(nftnl_rule_snprintf, nft_rule_snprintf);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_snprintf, nft_rule_snprintf);
 
 static inline int nftnl_rule_do_snprintf(char *buf, size_t size, void *r,
 				       uint32_t cmd, uint32_t type,
@@ -982,7 +982,7 @@ int nftnl_rule_fprintf(FILE *fp, struct nftnl_rule *r, uint32_t type,
 	return nftnl_fprintf(fp, r, NFTNL_CMD_UNSPEC, type, flags,
 			   nftnl_rule_do_snprintf);
 }
-EXPORT_SYMBOL(nftnl_rule_fprintf, nft_rule_fprintf);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_fprintf, nft_rule_fprintf);
 
 int nftnl_expr_foreach(struct nftnl_rule *r,
                           int (*cb)(struct nftnl_expr *e, void *data),
@@ -998,7 +998,7 @@ int nftnl_expr_foreach(struct nftnl_rule *r,
        }
        return 0;
 }
-EXPORT_SYMBOL(nftnl_expr_foreach, nft_rule_expr_foreach);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_foreach, nft_rule_expr_foreach);
 
 struct nftnl_expr_iter {
 	struct nftnl_rule		*r;
@@ -1022,7 +1022,7 @@ struct nftnl_expr_iter *nftnl_expr_iter_create(struct nftnl_rule *r)
 
 	return iter;
 }
-EXPORT_SYMBOL(nftnl_expr_iter_create, nft_rule_expr_iter_create);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_iter_create, nft_rule_expr_iter_create);
 
 struct nftnl_expr *nftnl_expr_iter_next(struct nftnl_expr_iter *iter)
 {
@@ -1038,13 +1038,13 @@ struct nftnl_expr *nftnl_expr_iter_next(struct nftnl_expr_iter *iter)
 
 	return expr;
 }
-EXPORT_SYMBOL(nftnl_expr_iter_next, nft_rule_expr_iter_next);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_iter_next, nft_rule_expr_iter_next);
 
 void nftnl_expr_iter_destroy(struct nftnl_expr_iter *iter)
 {
 	xfree(iter);
 }
-EXPORT_SYMBOL(nftnl_expr_iter_destroy, nft_rule_expr_iter_destroy);
+EXPORT_SYMBOL_ALIAS(nftnl_expr_iter_destroy, nft_rule_expr_iter_destroy);
 
 struct nftnl_rule_list {
 	struct list_head list;
@@ -1062,7 +1062,7 @@ struct nftnl_rule_list *nftnl_rule_list_alloc(void)
 
 	return list;
 }
-EXPORT_SYMBOL(nftnl_rule_list_alloc, nft_rule_list_alloc);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_list_alloc, nft_rule_list_alloc);
 
 void nftnl_rule_list_free(struct nftnl_rule_list *list)
 {
@@ -1074,31 +1074,31 @@ void nftnl_rule_list_free(struct nftnl_rule_list *list)
 	}
 	xfree(list);
 }
-EXPORT_SYMBOL(nftnl_rule_list_free, nft_rule_list_free);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_list_free, nft_rule_list_free);
 
 int nftnl_rule_list_is_empty(struct nftnl_rule_list *list)
 {
 	return list_empty(&list->list);
 }
-EXPORT_SYMBOL(nftnl_rule_list_is_empty, nft_rule_list_is_empty);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_list_is_empty, nft_rule_list_is_empty);
 
 void nftnl_rule_list_add(struct nftnl_rule *r, struct nftnl_rule_list *list)
 {
 	list_add(&r->head, &list->list);
 }
-EXPORT_SYMBOL(nftnl_rule_list_add, nft_rule_list_add);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_list_add, nft_rule_list_add);
 
 void nftnl_rule_list_add_tail(struct nftnl_rule *r, struct nftnl_rule_list *list)
 {
 	list_add_tail(&r->head, &list->list);
 }
-EXPORT_SYMBOL(nftnl_rule_list_add_tail, nft_rule_list_add_tail);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_list_add_tail, nft_rule_list_add_tail);
 
 void nftnl_rule_list_del(struct nftnl_rule *r)
 {
 	list_del(&r->head);
 }
-EXPORT_SYMBOL(nftnl_rule_list_del, nft_rule_list_del);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_list_del, nft_rule_list_del);
 
 int nftnl_rule_list_foreach(struct nftnl_rule_list *rule_list,
 			  int (*cb)(struct nftnl_rule *r, void *data),
@@ -1114,7 +1114,7 @@ int nftnl_rule_list_foreach(struct nftnl_rule_list *rule_list,
 	}
 	return 0;
 }
-EXPORT_SYMBOL(nftnl_rule_list_foreach, nft_rule_list_foreach);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_list_foreach, nft_rule_list_foreach);
 
 struct nftnl_rule_list_iter {
 	struct nftnl_rule_list	*list;
@@ -1137,13 +1137,13 @@ struct nftnl_rule_list_iter *nftnl_rule_list_iter_create(struct nftnl_rule_list
 
 	return iter;
 }
-EXPORT_SYMBOL(nftnl_rule_list_iter_create, nft_rule_list_iter_create);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_list_iter_create, nft_rule_list_iter_create);
 
 struct nftnl_rule *nftnl_rule_list_iter_cur(struct nftnl_rule_list_iter *iter)
 {
 	return iter->cur;
 }
-EXPORT_SYMBOL(nftnl_rule_list_iter_cur, nft_rule_list_iter_cur);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_list_iter_cur, nft_rule_list_iter_cur);
 
 struct nftnl_rule *nftnl_rule_list_iter_next(struct nftnl_rule_list_iter *iter)
 {
@@ -1159,10 +1159,10 @@ struct nftnl_rule *nftnl_rule_list_iter_next(struct nftnl_rule_list_iter *iter)
 
 	return r;
 }
-EXPORT_SYMBOL(nftnl_rule_list_iter_next, nft_rule_list_iter_next);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_list_iter_next, nft_rule_list_iter_next);
 
 void nftnl_rule_list_iter_destroy(struct nftnl_rule_list_iter *iter)
 {
 	xfree(iter);
 }
-EXPORT_SYMBOL(nftnl_rule_list_iter_destroy, nft_rule_list_iter_destroy);
+EXPORT_SYMBOL_ALIAS(nftnl_rule_list_iter_destroy, nft_rule_list_iter_destroy);
diff --git a/src/ruleset.c b/src/ruleset.c
index 7b1ab7a..641ff99 100644
--- a/src/ruleset.c
+++ b/src/ruleset.c
@@ -62,7 +62,7 @@ struct nftnl_ruleset *nftnl_ruleset_alloc(void)
 {
 	return calloc(1, sizeof(struct nftnl_ruleset));
 }
-EXPORT_SYMBOL(nftnl_ruleset_alloc, nft_ruleset_alloc);
+EXPORT_SYMBOL_ALIAS(nftnl_ruleset_alloc, nft_ruleset_alloc);
 
 void nftnl_ruleset_free(struct nftnl_ruleset *r)
 {
@@ -76,13 +76,13 @@ void nftnl_ruleset_free(struct nftnl_ruleset *r)
 		nftnl_rule_list_free(r->rule_list);
 	xfree(r);
 }
-EXPORT_SYMBOL(nftnl_ruleset_free, nft_ruleset_free);
+EXPORT_SYMBOL_ALIAS(nftnl_ruleset_free, nft_ruleset_free);
 
 bool nftnl_ruleset_is_set(const struct nftnl_ruleset *r, uint16_t attr)
 {
 	return r->flags & (1 << attr);
 }
-EXPORT_SYMBOL(nftnl_ruleset_is_set, nft_ruleset_attr_is_set);
+EXPORT_SYMBOL_ALIAS(nftnl_ruleset_is_set, nft_ruleset_attr_is_set);
 
 void nftnl_ruleset_unset(struct nftnl_ruleset *r, uint16_t attr)
 {
@@ -109,7 +109,7 @@ void nftnl_ruleset_unset(struct nftnl_ruleset *r, uint16_t attr)
 	}
 	r->flags &= ~(1 << attr);
 }
-EXPORT_SYMBOL(nftnl_ruleset_unset, nft_ruleset_attr_unset);
+EXPORT_SYMBOL_ALIAS(nftnl_ruleset_unset, nft_ruleset_attr_unset);
 
 void nftnl_ruleset_set(struct nftnl_ruleset *r, uint16_t attr, void *data)
 {
@@ -135,7 +135,7 @@ void nftnl_ruleset_set(struct nftnl_ruleset *r, uint16_t attr, void *data)
 	}
 	r->flags |= (1 << attr);
 }
-EXPORT_SYMBOL(nftnl_ruleset_set, nft_ruleset_attr_set);
+EXPORT_SYMBOL_ALIAS(nftnl_ruleset_set, nft_ruleset_attr_set);
 
 void *nftnl_ruleset_get(const struct nftnl_ruleset *r, uint16_t attr)
 {
@@ -155,7 +155,7 @@ void *nftnl_ruleset_get(const struct nftnl_ruleset *r, uint16_t attr)
 		return NULL;
 	}
 }
-EXPORT_SYMBOL(nftnl_ruleset_get, nft_ruleset_attr_get);
+EXPORT_SYMBOL_ALIAS(nftnl_ruleset_get, nft_ruleset_attr_get);
 
 void nftnl_ruleset_ctx_free(const struct nftnl_parse_ctx *ctx)
 {
@@ -178,13 +178,13 @@ void nftnl_ruleset_ctx_free(const struct nftnl_parse_ctx *ctx)
 		break;
 	}
 }
-EXPORT_SYMBOL(nftnl_ruleset_ctx_free, nft_ruleset_ctx_free);
+EXPORT_SYMBOL_ALIAS(nftnl_ruleset_ctx_free, nft_ruleset_ctx_free);
 
 bool nftnl_ruleset_ctx_is_set(const struct nftnl_parse_ctx *ctx, uint16_t attr)
 {
 	return ctx->flags & (1 << attr);
 }
-EXPORT_SYMBOL(nftnl_ruleset_ctx_is_set, nft_ruleset_ctx_is_set);
+EXPORT_SYMBOL_ALIAS(nftnl_ruleset_ctx_is_set, nft_ruleset_ctx_is_set);
 
 void *nftnl_ruleset_ctx_get(const struct nftnl_parse_ctx *ctx, uint16_t attr)
 {
@@ -210,14 +210,14 @@ void *nftnl_ruleset_ctx_get(const struct nftnl_parse_ctx *ctx, uint16_t attr)
 		return NULL;
 	}
 }
-EXPORT_SYMBOL(nftnl_ruleset_ctx_get, nft_ruleset_ctx_get);
+EXPORT_SYMBOL_ALIAS(nftnl_ruleset_ctx_get, nft_ruleset_ctx_get);
 
 uint32_t nftnl_ruleset_ctx_get_u32(const struct nftnl_parse_ctx *ctx, uint16_t attr)
 {
 	const void *ret = nftnl_ruleset_ctx_get(ctx, attr);
 	return ret == NULL ? 0 : *((uint32_t *)ret);
 }
-EXPORT_SYMBOL(nftnl_ruleset_ctx_get_u32, nft_ruleset_ctx_get_u32);
+EXPORT_SYMBOL_ALIAS(nftnl_ruleset_ctx_get_u32, nft_ruleset_ctx_get_u32);
 
 #if defined(JSON_PARSING) || defined(XML_PARSING)
 static void nftnl_ruleset_ctx_set(struct nftnl_parse_ctx *ctx, uint16_t attr,
@@ -751,7 +751,7 @@ int nftnl_ruleset_parse_file_cb(enum nftnl_parse_type type, FILE *fp,
 {
 	return nftnl_ruleset_do_parse(type, fp, err, NFTNL_PARSE_FILE, data, cb);
 }
-EXPORT_SYMBOL(nftnl_ruleset_parse_file_cb, nft_ruleset_parse_file_cb);
+EXPORT_SYMBOL_ALIAS(nftnl_ruleset_parse_file_cb, nft_ruleset_parse_file_cb);
 
 int nftnl_ruleset_parse_buffer_cb(enum nftnl_parse_type type, const char *buffer,
 				struct nftnl_parse_err *err, void *data,
@@ -760,7 +760,7 @@ int nftnl_ruleset_parse_buffer_cb(enum nftnl_parse_type type, const char *buffer
 	return nftnl_ruleset_do_parse(type, buffer, err, NFTNL_PARSE_BUFFER, data,
 				    cb);
 }
-EXPORT_SYMBOL(nftnl_ruleset_parse_buffer_cb, nft_ruleset_parse_buffer_cb);
+EXPORT_SYMBOL_ALIAS(nftnl_ruleset_parse_buffer_cb, nft_ruleset_parse_buffer_cb);
 
 static int nftnl_ruleset_cb(const struct nftnl_parse_ctx *ctx)
 {
@@ -828,14 +828,14 @@ int nftnl_ruleset_parse(struct nftnl_ruleset *r, enum nftnl_parse_type type,
 {
 	return nftnl_ruleset_parse_buffer_cb(type, data, err, r, nftnl_ruleset_cb);
 }
-EXPORT_SYMBOL(nftnl_ruleset_parse, nft_ruleset_parse);
+EXPORT_SYMBOL_ALIAS(nftnl_ruleset_parse, nft_ruleset_parse);
 
 int nftnl_ruleset_parse_file(struct nftnl_ruleset *rs, enum nftnl_parse_type type,
 			   FILE *fp, struct nftnl_parse_err *err)
 {
 	return nftnl_ruleset_parse_file_cb(type, fp, err, rs, nftnl_ruleset_cb);
 }
-EXPORT_SYMBOL(nftnl_ruleset_parse_file, nft_ruleset_parse_file);
+EXPORT_SYMBOL_ALIAS(nftnl_ruleset_parse_file, nft_ruleset_parse_file);
 
 static const char *nftnl_ruleset_o_opentag(uint32_t type)
 {
@@ -1097,7 +1097,7 @@ int nftnl_ruleset_snprintf(char *buf, size_t size, const struct nftnl_ruleset *r
 		return -1;
 	}
 }
-EXPORT_SYMBOL(nftnl_ruleset_snprintf, nft_ruleset_snprintf);
+EXPORT_SYMBOL_ALIAS(nftnl_ruleset_snprintf, nft_ruleset_snprintf);
 
 static int nftnl_ruleset_fprintf_tables(FILE *fp, const struct nftnl_ruleset *rs,
 				      uint32_t type, uint32_t flags)
@@ -1317,4 +1317,4 @@ int nftnl_ruleset_fprintf(FILE *fp, const struct nftnl_ruleset *rs, uint32_t typ
 	return nftnl_ruleset_cmd_fprintf(fp, rs, nftnl_flag2cmd(flags), type,
 				       flags);
 }
-EXPORT_SYMBOL(nftnl_ruleset_fprintf, nft_ruleset_fprintf);
+EXPORT_SYMBOL_ALIAS(nftnl_ruleset_fprintf, nft_ruleset_fprintf);
diff --git a/src/set.c b/src/set.c
index f5a9454..8369f7f 100644
--- a/src/set.c
+++ b/src/set.c
@@ -38,7 +38,7 @@ struct nftnl_set *nftnl_set_alloc(void)
 	INIT_LIST_HEAD(&s->element_list);
 	return s;
 }
-EXPORT_SYMBOL(nftnl_set_alloc, nft_set_alloc);
+EXPORT_SYMBOL_ALIAS(nftnl_set_alloc, nft_set_alloc);
 
 void nftnl_set_free(struct nftnl_set *s)
 {
@@ -55,13 +55,13 @@ void nftnl_set_free(struct nftnl_set *s)
 	}
 	xfree(s);
 }
-EXPORT_SYMBOL(nftnl_set_free, nft_set_free);
+EXPORT_SYMBOL_ALIAS(nftnl_set_free, nft_set_free);
 
 bool nftnl_set_is_set(const struct nftnl_set *s, uint16_t attr)
 {
 	return s->flags & (1 << attr);
 }
-EXPORT_SYMBOL(nftnl_set_is_set, nft_set_attr_is_set);
+EXPORT_SYMBOL_ALIAS(nftnl_set_is_set, nft_set_attr_is_set);
 
 void nftnl_set_unset(struct nftnl_set *s, uint16_t attr)
 {
@@ -98,7 +98,7 @@ void nftnl_set_unset(struct nftnl_set *s, uint16_t attr)
 
 	s->flags &= ~(1 << attr);
 }
-EXPORT_SYMBOL(nftnl_set_unset, nft_set_attr_unset);
+EXPORT_SYMBOL_ALIAS(nftnl_set_unset, nft_set_attr_unset);
 
 static uint32_t nftnl_set_validate[NFTNL_SET_MAX + 1] = {
 	[NFTNL_SET_FLAGS]		= sizeof(uint32_t),
@@ -170,31 +170,31 @@ void nftnl_set_set_data(struct nftnl_set *s, uint16_t attr, const void *data,
 	}
 	s->flags |= (1 << attr);
 }
-EXPORT_SYMBOL(nftnl_set_set_data, nft_set_attr_set_data);
+EXPORT_SYMBOL_ALIAS(nftnl_set_set_data, nft_set_attr_set_data);
 
 void nftnl_set_set(struct nftnl_set *s, uint16_t attr, const void *data)
 {
 	nftnl_set_set_data(s, attr, data, nftnl_set_validate[attr]);
 }
-EXPORT_SYMBOL(nftnl_set_set, nft_set_attr_set);
+EXPORT_SYMBOL_ALIAS(nftnl_set_set, nft_set_attr_set);
 
 void nftnl_set_set_u32(struct nftnl_set *s, uint16_t attr, uint32_t val)
 {
 	nftnl_set_set(s, attr, &val);
 }
-EXPORT_SYMBOL(nftnl_set_set_u32, nft_set_attr_set_u32);
+EXPORT_SYMBOL_ALIAS(nftnl_set_set_u32, nft_set_attr_set_u32);
 
 void nftnl_set_set_u64(struct nftnl_set *s, uint16_t attr, uint64_t val)
 {
 	nftnl_set_set(s, attr, &val);
 }
-EXPORT_SYMBOL(nftnl_set_set_u64, nft_set_attr_set_u64);
+EXPORT_SYMBOL_ALIAS(nftnl_set_set_u64, nft_set_attr_set_u64);
 
 void nftnl_set_set_str(struct nftnl_set *s, uint16_t attr, const char *str)
 {
 	nftnl_set_set(s, attr, str);
 }
-EXPORT_SYMBOL(nftnl_set_set_str, nft_set_attr_set_str);
+EXPORT_SYMBOL_ALIAS(nftnl_set_set_str, nft_set_attr_set_str);
 
 const void *nftnl_set_get_data(struct nftnl_set *s, uint16_t attr,
 				  uint32_t *data_len)
@@ -243,20 +243,20 @@ const void *nftnl_set_get_data(struct nftnl_set *s, uint16_t attr,
 	}
 	return NULL;
 }
-EXPORT_SYMBOL(nftnl_set_get_data, nft_set_attr_get_data);
+EXPORT_SYMBOL_ALIAS(nftnl_set_get_data, nft_set_attr_get_data);
 
 const void *nftnl_set_get(struct nftnl_set *s, uint16_t attr)
 {
 	uint32_t data_len;
 	return nftnl_set_get_data(s, attr, &data_len);
 }
-EXPORT_SYMBOL(nftnl_set_get, nft_set_attr_get);
+EXPORT_SYMBOL_ALIAS(nftnl_set_get, nft_set_attr_get);
 
 const char *nftnl_set_get_str(struct nftnl_set *s, uint16_t attr)
 {
 	return nftnl_set_get(s, attr);
 }
-EXPORT_SYMBOL(nftnl_set_get_str, nft_set_attr_get_str);
+EXPORT_SYMBOL_ALIAS(nftnl_set_get_str, nft_set_attr_get_str);
 
 uint32_t nftnl_set_get_u32(struct nftnl_set *s, uint16_t attr)
 {
@@ -267,7 +267,7 @@ uint32_t nftnl_set_get_u32(struct nftnl_set *s, uint16_t attr)
 
 	return val ? *val : 0;
 }
-EXPORT_SYMBOL(nftnl_set_get_u32, nft_set_attr_get_u32);
+EXPORT_SYMBOL_ALIAS(nftnl_set_get_u32, nft_set_attr_get_u32);
 
 uint64_t nftnl_set_get_u64(struct nftnl_set *s, uint16_t attr)
 {
@@ -278,7 +278,7 @@ uint64_t nftnl_set_get_u64(struct nftnl_set *s, uint16_t attr)
 
 	return val ? *val : 0;
 }
-EXPORT_SYMBOL(nftnl_set_get_u64, nft_set_attr_get_u64);
+EXPORT_SYMBOL_ALIAS(nftnl_set_get_u64, nft_set_attr_get_u64);
 
 struct nftnl_set *nftnl_set_clone(const struct nftnl_set *set)
 {
@@ -349,7 +349,7 @@ void nftnl_set_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set *s)
 	if (s->flags & (1 << NFTNL_SET_GC_INTERVAL))
 		mnl_attr_put_u32(nlh, NFTA_SET_GC_INTERVAL, htonl(s->gc_interval));
 }
-EXPORT_SYMBOL(nftnl_set_nlmsg_build_payload, nft_set_nlmsg_build_payload);
+EXPORT_SYMBOL_ALIAS(nftnl_set_nlmsg_build_payload, nft_set_nlmsg_build_payload);
 
 static int nftnl_set_parse_attr_cb(const struct nlattr *attr, void *data)
 {
@@ -488,7 +488,7 @@ int nftnl_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_set *s)
 
 	return ret;
 }
-EXPORT_SYMBOL(nftnl_set_nlmsg_parse, nft_set_nlmsg_parse);
+EXPORT_SYMBOL_ALIAS(nftnl_set_nlmsg_parse, nft_set_nlmsg_parse);
 
 #ifdef JSON_PARSING
 static int nftnl_jansson_parse_set_info(struct nftnl_set *s, json_t *tree,
@@ -762,14 +762,14 @@ int nftnl_set_parse(struct nftnl_set *s, enum nftnl_parse_type type,
 {
 	return nftnl_set_do_parse(s, type, data, err, NFTNL_PARSE_BUFFER);
 }
-EXPORT_SYMBOL(nftnl_set_parse, nft_set_parse);
+EXPORT_SYMBOL_ALIAS(nftnl_set_parse, nft_set_parse);
 
 int nftnl_set_parse_file(struct nftnl_set *s, enum nftnl_parse_type type,
 		       FILE *fp, struct nftnl_parse_err *err)
 {
 	return nftnl_set_do_parse(s, type, fp, err, NFTNL_PARSE_FILE);
 }
-EXPORT_SYMBOL(nftnl_set_parse_file, nft_set_parse_file);
+EXPORT_SYMBOL_ALIAS(nftnl_set_parse_file, nft_set_parse_file);
 
 static int nftnl_set_snprintf_json(char *buf, size_t size, struct nftnl_set *s,
 				  uint32_t type, uint32_t flags)
@@ -1036,7 +1036,7 @@ int nftnl_set_snprintf(char *buf, size_t size, struct nftnl_set *s,
 	return nftnl_set_cmd_snprintf(buf, size, s, nftnl_flag2cmd(flags), type,
 				    flags);
 }
-EXPORT_SYMBOL(nftnl_set_snprintf, nft_set_snprintf);
+EXPORT_SYMBOL_ALIAS(nftnl_set_snprintf, nft_set_snprintf);
 
 static inline int nftnl_set_do_snprintf(char *buf, size_t size, void *s,
 				      uint32_t cmd, uint32_t type,
@@ -1051,13 +1051,13 @@ int nftnl_set_fprintf(FILE *fp, struct nftnl_set *s, uint32_t type,
 	return nftnl_fprintf(fp, s, NFTNL_CMD_UNSPEC, type, flags,
 			   nftnl_set_do_snprintf);
 }
-EXPORT_SYMBOL(nftnl_set_fprintf, nft_set_fprintf);
+EXPORT_SYMBOL_ALIAS(nftnl_set_fprintf, nft_set_fprintf);
 
 void nftnl_set_elem_add(struct nftnl_set *s, struct nftnl_set_elem *elem)
 {
 	list_add_tail(&elem->head, &s->element_list);
 }
-EXPORT_SYMBOL(nftnl_set_elem_add, nft_set_elem_add);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_add, nft_set_elem_add);
 
 struct nftnl_set_list {
 	struct list_head list;
@@ -1075,7 +1075,7 @@ struct nftnl_set_list *nftnl_set_list_alloc(void)
 
 	return list;
 }
-EXPORT_SYMBOL(nftnl_set_list_alloc, nft_set_list_alloc);
+EXPORT_SYMBOL_ALIAS(nftnl_set_list_alloc, nft_set_list_alloc);
 
 void nftnl_set_list_free(struct nftnl_set_list *list)
 {
@@ -1087,31 +1087,31 @@ void nftnl_set_list_free(struct nftnl_set_list *list)
 	}
 	xfree(list);
 }
-EXPORT_SYMBOL(nftnl_set_list_free, nft_set_list_free);
+EXPORT_SYMBOL_ALIAS(nftnl_set_list_free, nft_set_list_free);
 
 int nftnl_set_list_is_empty(struct nftnl_set_list *list)
 {
 	return list_empty(&list->list);
 }
-EXPORT_SYMBOL(nftnl_set_list_is_empty, nft_set_list_is_empty);
+EXPORT_SYMBOL_ALIAS(nftnl_set_list_is_empty, nft_set_list_is_empty);
 
 void nftnl_set_list_add(struct nftnl_set *s, struct nftnl_set_list *list)
 {
 	list_add(&s->head, &list->list);
 }
-EXPORT_SYMBOL(nftnl_set_list_add, nft_set_list_add);
+EXPORT_SYMBOL_ALIAS(nftnl_set_list_add, nft_set_list_add);
 
 void nftnl_set_list_add_tail(struct nftnl_set *s, struct nftnl_set_list *list)
 {
 	list_add_tail(&s->head, &list->list);
 }
-EXPORT_SYMBOL(nftnl_set_list_add_tail, nft_set_list_add_tail);
+EXPORT_SYMBOL_ALIAS(nftnl_set_list_add_tail, nft_set_list_add_tail);
 
 void nftnl_set_list_del(struct nftnl_set *s)
 {
 	list_del(&s->head);
 }
-EXPORT_SYMBOL(nftnl_set_list_del, nft_set_list_del);
+EXPORT_SYMBOL_ALIAS(nftnl_set_list_del, nft_set_list_del);
 
 int nftnl_set_list_foreach(struct nftnl_set_list *set_list,
 			 int (*cb)(struct nftnl_set *t, void *data), void *data)
@@ -1126,7 +1126,7 @@ int nftnl_set_list_foreach(struct nftnl_set_list *set_list,
 	}
 	return 0;
 }
-EXPORT_SYMBOL(nftnl_set_list_foreach, nft_set_list_foreach);
+EXPORT_SYMBOL_ALIAS(nftnl_set_list_foreach, nft_set_list_foreach);
 
 struct nftnl_set_list_iter {
 	struct nftnl_set_list	*list;
@@ -1149,13 +1149,13 @@ struct nftnl_set_list_iter *nftnl_set_list_iter_create(struct nftnl_set_list *l)
 
 	return iter;
 }
-EXPORT_SYMBOL(nftnl_set_list_iter_create, nft_set_list_iter_create);
+EXPORT_SYMBOL_ALIAS(nftnl_set_list_iter_create, nft_set_list_iter_create);
 
 struct nftnl_set *nftnl_set_list_iter_cur(struct nftnl_set_list_iter *iter)
 {
 	return iter->cur;
 }
-EXPORT_SYMBOL(nftnl_set_list_iter_cur, nft_set_list_iter_cur);
+EXPORT_SYMBOL_ALIAS(nftnl_set_list_iter_cur, nft_set_list_iter_cur);
 
 struct nftnl_set *nftnl_set_list_iter_next(struct nftnl_set_list_iter *iter)
 {
@@ -1171,13 +1171,13 @@ struct nftnl_set *nftnl_set_list_iter_next(struct nftnl_set_list_iter *iter)
 
 	return s;
 }
-EXPORT_SYMBOL(nftnl_set_list_iter_next, nft_set_list_iter_next);
+EXPORT_SYMBOL_ALIAS(nftnl_set_list_iter_next, nft_set_list_iter_next);
 
 void nftnl_set_list_iter_destroy(struct nftnl_set_list_iter *iter)
 {
 	xfree(iter);
 }
-EXPORT_SYMBOL(nftnl_set_list_iter_destroy, nft_set_list_iter_destroy);
+EXPORT_SYMBOL_ALIAS(nftnl_set_list_iter_destroy, nft_set_list_iter_destroy);
 
 static struct nftnl_set *nftnl_set_lookup(const char *this_set_name,
 				      struct nftnl_set_list *set_list)
diff --git a/src/set_elem.c b/src/set_elem.c
index 293ce15..db367bd 100644
--- a/src/set_elem.c
+++ b/src/set_elem.c
@@ -37,7 +37,7 @@ struct nftnl_set_elem *nftnl_set_elem_alloc(void)
 
 	return s;
 }
-EXPORT_SYMBOL(nftnl_set_elem_alloc, nft_set_elem_alloc);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_alloc, nft_set_elem_alloc);
 
 void nftnl_set_elem_free(struct nftnl_set_elem *s)
 {
@@ -53,13 +53,13 @@ void nftnl_set_elem_free(struct nftnl_set_elem *s)
 
 	xfree(s);
 }
-EXPORT_SYMBOL(nftnl_set_elem_free, nft_set_elem_free);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_free, nft_set_elem_free);
 
 bool nftnl_set_elem_is_set(const struct nftnl_set_elem *s, uint16_t attr)
 {
 	return s->flags & (1 << attr);
 }
-EXPORT_SYMBOL(nftnl_set_elem_is_set, nft_set_elem_attr_is_set);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_is_set, nft_set_elem_attr_is_set);
 
 void nftnl_set_elem_unset(struct nftnl_set_elem *s, uint16_t attr)
 {
@@ -92,7 +92,7 @@ void nftnl_set_elem_unset(struct nftnl_set_elem *s, uint16_t attr)
 
 	s->flags &= ~(1 << attr);
 }
-EXPORT_SYMBOL(nftnl_set_elem_unset, nft_set_elem_attr_unset);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_unset, nft_set_elem_attr_unset);
 
 void nftnl_set_elem_set(struct nftnl_set_elem *s, uint16_t attr,
 			   const void *data, uint32_t data_len)
@@ -130,25 +130,25 @@ void nftnl_set_elem_set(struct nftnl_set_elem *s, uint16_t attr,
 	}
 	s->flags |= (1 << attr);
 }
-EXPORT_SYMBOL(nftnl_set_elem_set, nft_set_elem_attr_set);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_set, nft_set_elem_attr_set);
 
 void nftnl_set_elem_set_u32(struct nftnl_set_elem *s, uint16_t attr, uint32_t val)
 {
 	nftnl_set_elem_set(s, attr, &val, sizeof(uint32_t));
 }
-EXPORT_SYMBOL(nftnl_set_elem_set_u32, nft_set_elem_attr_set_u32);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_set_u32, nft_set_elem_attr_set_u32);
 
 void nftnl_set_elem_set_u64(struct nftnl_set_elem *s, uint16_t attr, uint64_t val)
 {
 	nftnl_set_elem_set(s, attr, &val, sizeof(uint64_t));
 }
-EXPORT_SYMBOL(nftnl_set_elem_set_u64, nft_set_elem_attr_set_u64);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_set_u64, nft_set_elem_attr_set_u64);
 
 void nftnl_set_elem_set_str(struct nftnl_set_elem *s, uint16_t attr, const char *str)
 {
 	nftnl_set_elem_set(s, attr, str, strlen(str));
 }
-EXPORT_SYMBOL(nftnl_set_elem_set_str, nft_set_elem_attr_set_str);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_set_str, nft_set_elem_attr_set_str);
 
 const void *nftnl_set_elem_get(struct nftnl_set_elem *s, uint16_t attr, uint32_t *data_len)
 {
@@ -180,7 +180,7 @@ const void *nftnl_set_elem_get(struct nftnl_set_elem *s, uint16_t attr, uint32_t
 	}
 	return NULL;
 }
-EXPORT_SYMBOL(nftnl_set_elem_get, nft_set_elem_attr_get);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_get, nft_set_elem_attr_get);
 
 const char *nftnl_set_elem_get_str(struct nftnl_set_elem *s, uint16_t attr)
 {
@@ -188,7 +188,7 @@ const char *nftnl_set_elem_get_str(struct nftnl_set_elem *s, uint16_t attr)
 
 	return nftnl_set_elem_get(s, attr, &size);
 }
-EXPORT_SYMBOL(nftnl_set_elem_get_str, nft_set_elem_attr_get_str);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_get_str, nft_set_elem_attr_get_str);
 
 uint32_t nftnl_set_elem_get_u32(struct nftnl_set_elem *s, uint16_t attr)
 {
@@ -196,7 +196,7 @@ uint32_t nftnl_set_elem_get_u32(struct nftnl_set_elem *s, uint16_t attr)
 	uint32_t val = *((uint32_t *)nftnl_set_elem_get(s, attr, &size));
 	return val;
 }
-EXPORT_SYMBOL(nftnl_set_elem_get_u32, nft_set_elem_attr_get_u32);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_get_u32, nft_set_elem_attr_get_u32);
 
 uint64_t nftnl_set_elem_get_u64(struct nftnl_set_elem *s, uint16_t attr)
 {
@@ -204,7 +204,7 @@ uint64_t nftnl_set_elem_get_u64(struct nftnl_set_elem *s, uint16_t attr)
 	uint64_t val = *((uint64_t *)nftnl_set_elem_get(s, attr, &size));
 	return val;
 }
-EXPORT_SYMBOL(nftnl_set_elem_get_u64, nft_set_elem_attr_get_u64);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_get_u64, nft_set_elem_attr_get_u64);
 
 struct nftnl_set_elem *nftnl_set_elem_clone(struct nftnl_set_elem *elem)
 {
@@ -296,7 +296,7 @@ void nftnl_set_elems_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set
 
 	mnl_attr_nest_end(nlh, nest1);
 }
-EXPORT_SYMBOL(nftnl_set_elems_nlmsg_build_payload, nft_set_elems_nlmsg_build_payload);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elems_nlmsg_build_payload, nft_set_elems_nlmsg_build_payload);
 
 static int nftnl_set_elem_parse_attr_cb(const struct nlattr *attr, void *data)
 {
@@ -485,7 +485,7 @@ int nftnl_set_elems_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_set *s)
 
 	return ret;
 }
-EXPORT_SYMBOL(nftnl_set_elems_nlmsg_parse, nft_set_elems_nlmsg_parse);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elems_nlmsg_parse, nft_set_elems_nlmsg_parse);
 
 #ifdef XML_PARSING
 int nftnl_mxml_set_elem_parse(mxml_node_t *tree, struct nftnl_set_elem *e,
@@ -589,14 +589,14 @@ int nftnl_set_elem_parse(struct nftnl_set_elem *e, enum nftnl_parse_type type,
 {
 	return nftnl_set_elem_do_parse(e, type, data, err, NFTNL_PARSE_BUFFER);
 }
-EXPORT_SYMBOL(nftnl_set_elem_parse, nft_set_elem_parse);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_parse, nft_set_elem_parse);
 
 int nftnl_set_elem_parse_file(struct nftnl_set_elem *e, enum nftnl_parse_type type,
 			    FILE *fp, struct nftnl_parse_err *err)
 {
 	return nftnl_set_elem_do_parse(e, type, fp, err, NFTNL_PARSE_FILE);
 }
-EXPORT_SYMBOL(nftnl_set_elem_parse_file, nft_set_elem_parse_file);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_parse_file, nft_set_elem_parse_file);
 
 static int nftnl_set_elem_snprintf_json(char *buf, size_t size,
 				      struct nftnl_set_elem *e, uint32_t flags)
@@ -771,7 +771,7 @@ int nftnl_set_elem_snprintf(char *buf, size_t size, struct nftnl_set_elem *e,
 	return nftnl_set_elem_cmd_snprintf(buf, size, e, nftnl_flag2cmd(flags),
 					 type, flags);
 }
-EXPORT_SYMBOL(nftnl_set_elem_snprintf, nft_set_elem_snprintf);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_snprintf, nft_set_elem_snprintf);
 
 static inline int nftnl_set_elem_do_snprintf(char *buf, size_t size, void *e,
 					   uint32_t cmd, uint32_t type,
@@ -786,7 +786,7 @@ int nftnl_set_elem_fprintf(FILE *fp, struct nftnl_set_elem *se, uint32_t type,
 	return nftnl_fprintf(fp, se, NFTNL_CMD_UNSPEC, type, flags,
 			   nftnl_set_elem_do_snprintf);
 }
-EXPORT_SYMBOL(nftnl_set_elem_fprintf, nft_set_elem_fprintf);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_fprintf, nft_set_elem_fprintf);
 
 int nftnl_set_elem_foreach(struct nftnl_set *s,
 			 int (*cb)(struct nftnl_set_elem *e, void *data),
@@ -802,7 +802,7 @@ int nftnl_set_elem_foreach(struct nftnl_set *s,
 	}
 	return 0;
 }
-EXPORT_SYMBOL(nftnl_set_elem_foreach, nft_set_elem_foreach);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elem_foreach, nft_set_elem_foreach);
 
 struct nftnl_set_elems_iter {
 	struct nftnl_set			*set;
@@ -828,13 +828,13 @@ struct nftnl_set_elems_iter *nftnl_set_elems_iter_create(struct nftnl_set *s)
 
 	return iter;
 }
-EXPORT_SYMBOL(nftnl_set_elems_iter_create, nft_set_elems_iter_create);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elems_iter_create, nft_set_elems_iter_create);
 
 struct nftnl_set_elem *nftnl_set_elems_iter_cur(struct nftnl_set_elems_iter *iter)
 {
 	return iter->cur;
 }
-EXPORT_SYMBOL(nftnl_set_elems_iter_cur, nft_set_elems_iter_cur);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elems_iter_cur, nft_set_elems_iter_cur);
 
 struct nftnl_set_elem *nftnl_set_elems_iter_next(struct nftnl_set_elems_iter *iter)
 {
@@ -849,13 +849,13 @@ struct nftnl_set_elem *nftnl_set_elems_iter_next(struct nftnl_set_elems_iter *it
 
 	return s;
 }
-EXPORT_SYMBOL(nftnl_set_elems_iter_next, nft_set_elems_iter_next);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elems_iter_next, nft_set_elems_iter_next);
 
 void nftnl_set_elems_iter_destroy(struct nftnl_set_elems_iter *iter)
 {
 	xfree(iter);
 }
-EXPORT_SYMBOL(nftnl_set_elems_iter_destroy, nft_set_elems_iter_destroy);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elems_iter_destroy, nft_set_elems_iter_destroy);
 
 static bool nftnl_attr_nest_overflow(struct nlmsghdr *nlh,
 				   const struct nlattr *from,
@@ -900,4 +900,4 @@ int nftnl_set_elems_nlmsg_build_payload_iter(struct nlmsghdr *nlh,
 
 	return ret;
 }
-EXPORT_SYMBOL(nftnl_set_elems_nlmsg_build_payload_iter, nft_set_elems_nlmsg_build_payload_iter);
+EXPORT_SYMBOL_ALIAS(nftnl_set_elems_nlmsg_build_payload_iter, nft_set_elems_nlmsg_build_payload_iter);
diff --git a/src/table.c b/src/table.c
index 28f6bd6..4dffcbc 100644
--- a/src/table.c
+++ b/src/table.c
@@ -40,7 +40,7 @@ struct nftnl_table *nftnl_table_alloc(void)
 {
 	return calloc(1, sizeof(struct nftnl_table));
 }
-EXPORT_SYMBOL(nftnl_table_alloc, nft_table_alloc);
+EXPORT_SYMBOL_ALIAS(nftnl_table_alloc, nft_table_alloc);
 
 void nftnl_table_free(struct nftnl_table *t)
 {
@@ -49,13 +49,13 @@ void nftnl_table_free(struct nftnl_table *t)
 
 	xfree(t);
 }
-EXPORT_SYMBOL(nftnl_table_free, nft_table_free);
+EXPORT_SYMBOL_ALIAS(nftnl_table_free, nft_table_free);
 
 bool nftnl_table_is_set(const struct nftnl_table *t, uint16_t attr)
 {
 	return t->flags & (1 << attr);
 }
-EXPORT_SYMBOL(nftnl_table_is_set, nft_table_attr_is_set);
+EXPORT_SYMBOL_ALIAS(nftnl_table_is_set, nft_table_attr_is_set);
 
 void nftnl_table_unset(struct nftnl_table *t, uint16_t attr)
 {
@@ -77,7 +77,7 @@ void nftnl_table_unset(struct nftnl_table *t, uint16_t attr)
 	}
 	t->flags &= ~(1 << attr);
 }
-EXPORT_SYMBOL(nftnl_table_unset, nft_table_attr_unset);
+EXPORT_SYMBOL_ALIAS(nftnl_table_unset, nft_table_attr_unset);
 
 static uint32_t nftnl_table_validate[NFTNL_TABLE_MAX + 1] = {
 	[NFTNL_TABLE_FLAGS]	= sizeof(uint32_t),
@@ -111,31 +111,31 @@ void nftnl_table_set_data(struct nftnl_table *t, uint16_t attr,
 	}
 	t->flags |= (1 << attr);
 }
-EXPORT_SYMBOL(nftnl_table_set_data, nft_table_attr_set_data);
+EXPORT_SYMBOL_ALIAS(nftnl_table_set_data, nft_table_attr_set_data);
 
 void nftnl_table_set(struct nftnl_table *t, uint16_t attr, const void *data)
 {
 	nftnl_table_set_data(t, attr, data, nftnl_table_validate[attr]);
 }
-EXPORT_SYMBOL(nftnl_table_set, nft_table_attr_set);
+EXPORT_SYMBOL_ALIAS(nftnl_table_set, nft_table_attr_set);
 
 void nftnl_table_set_u32(struct nftnl_table *t, uint16_t attr, uint32_t val)
 {
 	nftnl_table_set_data(t, attr, &val, sizeof(uint32_t));
 }
-EXPORT_SYMBOL(nftnl_table_set_u32, nft_table_attr_set_u32);
+EXPORT_SYMBOL_ALIAS(nftnl_table_set_u32, nft_table_attr_set_u32);
 
 void nftnl_table_set_u8(struct nftnl_table *t, uint16_t attr, uint8_t val)
 {
 	nftnl_table_set_data(t, attr, &val, sizeof(uint8_t));
 }
-EXPORT_SYMBOL(nftnl_table_set_u8, nft_table_attr_set_u8);
+EXPORT_SYMBOL_ALIAS(nftnl_table_set_u8, nft_table_attr_set_u8);
 
 void nftnl_table_set_str(struct nftnl_table *t, uint16_t attr, const char *str)
 {
 	nftnl_table_set_data(t, attr, str, 0);
 }
-EXPORT_SYMBOL(nftnl_table_set_str, nft_table_attr_set_str);
+EXPORT_SYMBOL_ALIAS(nftnl_table_set_str, nft_table_attr_set_str);
 
 const void *nftnl_table_get_data(struct nftnl_table *t, uint16_t attr,
 				    uint32_t *data_len)
@@ -158,34 +158,34 @@ const void *nftnl_table_get_data(struct nftnl_table *t, uint16_t attr,
 	}
 	return NULL;
 }
-EXPORT_SYMBOL(nftnl_table_get_data, nft_table_attr_get_data);
+EXPORT_SYMBOL_ALIAS(nftnl_table_get_data, nft_table_attr_get_data);
 
 const void *nftnl_table_get(struct nftnl_table *t, uint16_t attr)
 {
 	uint32_t data_len;
 	return nftnl_table_get_data(t, attr, &data_len);
 }
-EXPORT_SYMBOL(nftnl_table_get, nft_table_attr_get);
+EXPORT_SYMBOL_ALIAS(nftnl_table_get, nft_table_attr_get);
 
 uint32_t nftnl_table_get_u32(struct nftnl_table *t, uint16_t attr)
 {
 	const void *ret = nftnl_table_get(t, attr);
 	return ret == NULL ? 0 : *((uint32_t *)ret);
 }
-EXPORT_SYMBOL(nftnl_table_get_u32, nft_table_attr_get_u32);
+EXPORT_SYMBOL_ALIAS(nftnl_table_get_u32, nft_table_attr_get_u32);
 
 uint8_t nftnl_table_get_u8(struct nftnl_table *t, uint16_t attr)
 {
 	const void *ret = nftnl_table_get(t, attr);
 	return ret == NULL ? 0 : *((uint8_t *)ret);
 }
-EXPORT_SYMBOL(nftnl_table_get_u8, nft_table_attr_get_u8);
+EXPORT_SYMBOL_ALIAS(nftnl_table_get_u8, nft_table_attr_get_u8);
 
 const char *nftnl_table_get_str(struct nftnl_table *t, uint16_t attr)
 {
 	return nftnl_table_get(t, attr);
 }
-EXPORT_SYMBOL(nftnl_table_get_str, nft_table_attr_get_str);
+EXPORT_SYMBOL_ALIAS(nftnl_table_get_str, nft_table_attr_get_str);
 
 void nftnl_table_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_table *t)
 {
@@ -194,7 +194,7 @@ void nftnl_table_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_ta
 	if (t->flags & (1 << NFTNL_TABLE_FLAGS))
 		mnl_attr_put_u32(nlh, NFTA_TABLE_FLAGS, htonl(t->table_flags));
 }
-EXPORT_SYMBOL(nftnl_table_nlmsg_build_payload, nft_table_nlmsg_build_payload);
+EXPORT_SYMBOL_ALIAS(nftnl_table_nlmsg_build_payload, nft_table_nlmsg_build_payload);
 
 static int nftnl_table_parse_attr_cb(const struct nlattr *attr, void *data)
 {
@@ -247,7 +247,7 @@ int nftnl_table_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_table *t)
 
 	return 0;
 }
-EXPORT_SYMBOL(nftnl_table_nlmsg_parse, nft_table_nlmsg_parse);
+EXPORT_SYMBOL_ALIAS(nftnl_table_nlmsg_parse, nft_table_nlmsg_parse);
 
 #ifdef XML_PARSING
 int nftnl_mxml_table_parse(mxml_node_t *tree, struct nftnl_table *t,
@@ -384,14 +384,14 @@ int nftnl_table_parse(struct nftnl_table *t, enum nftnl_parse_type type,
 {
 	return nftnl_table_do_parse(t, type, data, err, NFTNL_PARSE_BUFFER);
 }
-EXPORT_SYMBOL(nftnl_table_parse, nft_table_parse);
+EXPORT_SYMBOL_ALIAS(nftnl_table_parse, nft_table_parse);
 
 int nftnl_table_parse_file(struct nftnl_table *t, enum nftnl_parse_type type,
 			 FILE *fp, struct nftnl_parse_err *err)
 {
 	return nftnl_table_do_parse(t, type, fp, err, NFTNL_PARSE_FILE);
 }
-EXPORT_SYMBOL(nftnl_table_parse_file, nft_table_parse_file);
+EXPORT_SYMBOL_ALIAS(nftnl_table_parse_file, nft_table_parse_file);
 
 static int nftnl_table_export(char *buf, size_t size, struct nftnl_table *t,
 			    int type)
@@ -453,7 +453,7 @@ int nftnl_table_snprintf(char *buf, size_t size, struct nftnl_table *t,
 	return nftnl_table_cmd_snprintf(buf, size, t, nftnl_flag2cmd(flags), type,
 				      flags);
 }
-EXPORT_SYMBOL(nftnl_table_snprintf, nft_table_snprintf);
+EXPORT_SYMBOL_ALIAS(nftnl_table_snprintf, nft_table_snprintf);
 
 static inline int nftnl_table_do_snprintf(char *buf, size_t size, void *t,
 					uint32_t cmd, uint32_t type,
@@ -468,7 +468,7 @@ int nftnl_table_fprintf(FILE *fp, struct nftnl_table *t, uint32_t type,
 	return nftnl_fprintf(fp, t, NFTNL_CMD_UNSPEC, type, flags,
 			   nftnl_table_do_snprintf);
 }
-EXPORT_SYMBOL(nftnl_table_fprintf, nft_table_fprintf);
+EXPORT_SYMBOL_ALIAS(nftnl_table_fprintf, nft_table_fprintf);
 
 struct nftnl_table_list {
 	struct list_head list;
@@ -486,7 +486,7 @@ struct nftnl_table_list *nftnl_table_list_alloc(void)
 
 	return list;
 }
-EXPORT_SYMBOL(nftnl_table_list_alloc, nft_table_list_alloc);
+EXPORT_SYMBOL_ALIAS(nftnl_table_list_alloc, nft_table_list_alloc);
 
 void nftnl_table_list_free(struct nftnl_table_list *list)
 {
@@ -498,31 +498,31 @@ void nftnl_table_list_free(struct nftnl_table_list *list)
 	}
 	xfree(list);
 }
-EXPORT_SYMBOL(nftnl_table_list_free, nft_table_list_free);
+EXPORT_SYMBOL_ALIAS(nftnl_table_list_free, nft_table_list_free);
 
 int nftnl_table_list_is_empty(struct nftnl_table_list *list)
 {
 	return list_empty(&list->list);
 }
-EXPORT_SYMBOL(nftnl_table_list_is_empty, nft_table_list_is_empty);
+EXPORT_SYMBOL_ALIAS(nftnl_table_list_is_empty, nft_table_list_is_empty);
 
 void nftnl_table_list_add(struct nftnl_table *r, struct nftnl_table_list *list)
 {
 	list_add(&r->head, &list->list);
 }
-EXPORT_SYMBOL(nftnl_table_list_add, nft_table_list_add);
+EXPORT_SYMBOL_ALIAS(nftnl_table_list_add, nft_table_list_add);
 
 void nftnl_table_list_add_tail(struct nftnl_table *r, struct nftnl_table_list *list)
 {
 	list_add_tail(&r->head, &list->list);
 }
-EXPORT_SYMBOL(nftnl_table_list_add_tail, nft_table_list_add_tail);
+EXPORT_SYMBOL_ALIAS(nftnl_table_list_add_tail, nft_table_list_add_tail);
 
 void nftnl_table_list_del(struct nftnl_table *t)
 {
 	list_del(&t->head);
 }
-EXPORT_SYMBOL(nftnl_table_list_del, nft_table_list_del);
+EXPORT_SYMBOL_ALIAS(nftnl_table_list_del, nft_table_list_del);
 
 int nftnl_table_list_foreach(struct nftnl_table_list *table_list,
 			   int (*cb)(struct nftnl_table *t, void *data),
@@ -538,7 +538,7 @@ int nftnl_table_list_foreach(struct nftnl_table_list *table_list,
 	}
 	return 0;
 }
-EXPORT_SYMBOL(nftnl_table_list_foreach, nft_table_list_foreach);
+EXPORT_SYMBOL_ALIAS(nftnl_table_list_foreach, nft_table_list_foreach);
 
 struct nftnl_table_list_iter {
 	struct nftnl_table_list	*list;
@@ -561,7 +561,7 @@ struct nftnl_table_list_iter *nftnl_table_list_iter_create(struct nftnl_table_li
 
 	return iter;
 }
-EXPORT_SYMBOL(nftnl_table_list_iter_create, nft_table_list_iter_create);
+EXPORT_SYMBOL_ALIAS(nftnl_table_list_iter_create, nft_table_list_iter_create);
 
 struct nftnl_table *nftnl_table_list_iter_next(struct nftnl_table_list_iter *iter)
 {
@@ -577,10 +577,10 @@ struct nftnl_table *nftnl_table_list_iter_next(struct nftnl_table_list_iter *ite
 
 	return r;
 }
-EXPORT_SYMBOL(nftnl_table_list_iter_next, nft_table_list_iter_next);
+EXPORT_SYMBOL_ALIAS(nftnl_table_list_iter_next, nft_table_list_iter_next);
 
 void nftnl_table_list_iter_destroy(struct nftnl_table_list_iter *iter)
 {
 	xfree(iter);
 }
-EXPORT_SYMBOL(nftnl_table_list_iter_destroy, nft_table_list_iter_destroy);
+EXPORT_SYMBOL_ALIAS(nftnl_table_list_iter_destroy, nft_table_list_iter_destroy);
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH libnftnl 5/6] src: add trace infrastructure support
  2015-11-24 10:02 [PATCH 0/6] nftables trace support Florian Westphal
                   ` (3 preceding siblings ...)
  2015-11-24 10:02 ` [PATCH libnftnl 4/6] src: rename EXPORT_SYMBOL to EXPORT_SYMBOL_ALIAS Florian Westphal
@ 2015-11-24 10:02 ` Florian Westphal
  2015-11-24 12:16   ` Patrick McHardy
  2015-11-24 10:02 ` [PATCH nftables 6/6] src: add trace support to nft monitor mode Florian Westphal
  5 siblings, 1 reply; 80+ messages in thread
From: Florian Westphal @ 2015-11-24 10:02 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Florian Westphal

parses trace monitor netlink messages from the kernel and
supports printing most of the 'important' header data such as
ether/ip/ip6 src/dst addresses and udp/tcp port numbers.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 include/libnftnl/Makefile.am        |   1 +
 include/libnftnl/trace.h            |  56 +++
 include/linux/netfilter/nf_tables.h |  32 ++
 src/Makefile.am                     |   1 +
 src/libnftnl.map                    |  17 +
 src/trace.c                         | 725 ++++++++++++++++++++++++++++++++++++
 src/utils.c                         |   4 +
 7 files changed, 836 insertions(+)
 create mode 100644 include/libnftnl/trace.h
 create mode 100644 src/trace.c

diff --git a/include/libnftnl/Makefile.am b/include/libnftnl/Makefile.am
index a20aaee..84f01b6 100644
--- a/include/libnftnl/Makefile.am
+++ b/include/libnftnl/Makefile.am
@@ -1,5 +1,6 @@
 pkginclude_HEADERS = batch.h		\
 		     table.h		\
+		     trace.h		\
 		     chain.h		\
 		     rule.h		\
 		     expr.h		\
diff --git a/include/libnftnl/trace.h b/include/libnftnl/trace.h
new file mode 100644
index 0000000..a570194
--- /dev/null
+++ b/include/libnftnl/trace.h
@@ -0,0 +1,56 @@
+#ifndef _LIBNFTNL_TRACE_H_
+#define _LIBNFTNL_TRACE_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum nftnl_trace_attr {
+	NFTNL_TRACE_CHAIN = 0,
+	NFTNL_TRACE_DEV_TYPE,
+	NFTNL_TRACE_FAMILY,
+	NFTNL_TRACE_ID,
+	NFTNL_TRACE_IIF,
+	NFTNL_TRACE_OIF,
+	NFTNL_TRACE_LL_HEADER,
+	NFTNL_TRACE_MARK,
+	NFTNL_TRACE_NETWORK_HEADER,
+	NFTNL_TRACE_TABLE,
+	NFTNL_TRACE_TRANSPORT_HEADER,
+	NFTNL_TRACE_TRANSPORT_PROTO,
+	NFTNL_TRACE_TYPE,
+	NFTNL_TRACE_RULE_HANDLE,
+	NFTNL_TRACE_VERDICT,
+	NFTNL_TRACE_VLAN_TAG,
+};
+#define NFTNL_TRACE_MAX NFTNL_TRACE_VLAN_TAG
+
+struct nftnl_trace;
+
+struct nftnl_trace *nftnl_trace_alloc(void);
+void nftnl_trace_free(struct nftnl_trace *trace);
+
+bool nftnl_trace_is_set(const struct nftnl_trace *trace, uint16_t type);
+
+const void *nftnl_trace_get_data(const struct nftnl_trace *trace,
+				 uint16_t type, uint32_t *data_len);
+
+uint8_t nftnl_trace_get_u8(const struct nftnl_trace *trace, uint16_t type);
+uint16_t nftnl_trace_get_u16(const struct nftnl_trace *trace, uint16_t type);
+uint32_t nftnl_trace_get_u32(const struct nftnl_trace *trace, uint16_t type);
+uint64_t nftnl_trace_get_u64(const struct nftnl_trace *trace, uint16_t type);
+const char *nftnl_trace_get_str(const struct nftnl_trace *trace, uint16_t type);
+
+int nftnl_trace_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_trace *t);
+int nftnl_trace_snprintf(char *buf, size_t size, const struct nftnl_trace *t, uint32_t type);
+int nftnl_trace_fprintf(FILE *fh, const struct nftnl_trace *t, uint32_t type);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* _LIBNFTNL_TRACE_H_ */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 9796d82..09ede2b 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -83,6 +83,7 @@ enum nft_verdicts {
  * @NFT_MSG_DELSETELEM: delete a set element (enum nft_set_elem_attributes)
  * @NFT_MSG_NEWGEN: announce a new generation, only for events (enum nft_gen_attributes)
  * @NFT_MSG_GETGEN: get the rule-set generation (enum nft_gen_attributes)
+ * @NFT_MSG_TRACE: trace event (enum nft_trace_attributes)
  */
 enum nf_tables_msg_types {
 	NFT_MSG_NEWTABLE,
@@ -102,6 +103,7 @@ enum nf_tables_msg_types {
 	NFT_MSG_DELSETELEM,
 	NFT_MSG_NEWGEN,
 	NFT_MSG_GETGEN,
+	NFT_MSG_TRACE,
 	NFT_MSG_MAX,
 };
 
@@ -970,4 +972,34 @@ enum nft_gen_attributes {
 };
 #define NFTA_GEN_MAX		(__NFTA_GEN_MAX - 1)
 
+enum nft_trace_attibutes {
+	NFTA_TRACE_UNSPEC,
+	NFTA_TRACE_CHAIN,
+	NFTA_TRACE_DEV_TYPE,
+	NFTA_TRACE_ID,
+	NFTA_TRACE_IIF,
+	NFTA_TRACE_OIF,
+	NFTA_TRACE_LL_HEADER,
+	NFTA_TRACE_MARK,
+	NFTA_TRACE_NETWORK_HEADER,
+	NFTA_TRACE_TABLE,
+	NFTA_TRACE_TRANSPORT_HEADER,
+	NFTA_TRACE_TRANSPORT_PROTO,
+	NFTA_TRACE_TYPE,
+	NFTA_TRACE_RULE_HANDLE,
+	NFTA_TRACE_VERDICT,
+	NFTA_TRACE_VLAN_TAG,
+	__NFTA_TRACE_MAX
+};
+#define NFTA_TRACE_MAX (__NFTA_TRACE_MAX - 1)
+
+enum nft_trace_types {
+	NFT_TRACETYPE_UNSPEC,
+	NFT_TRACETYPE_PACKET,
+	NFT_TRACETYPE_POLICY,
+	NFT_TRACETYPE_RETURN,
+	NFT_TRACETYPE_RULE,
+	__NFT_TRACETYPE_MAX
+};
+#define NFT_TRACETYPE_MAX (__NFT_TRACETYPE_MAX - 1)
 #endif /* _LINUX_NF_TABLES_H */
diff --git a/src/Makefile.am b/src/Makefile.am
index 107cae5..795307d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,6 +11,7 @@ libnftnl_la_SOURCES = utils.c		\
 		      common.c		\
 		      gen.c		\
 		      table.c		\
+		      trace.c		\
 		      chain.c		\
 		      rule.c		\
 		      set.c		\
diff --git a/src/libnftnl.map b/src/libnftnl.map
index a52b54e..7fc2eb9 100644
--- a/src/libnftnl.map
+++ b/src/libnftnl.map
@@ -498,3 +498,20 @@ global:
 
 local: *;
 };
+
+LIBNFTNL_4.1 {
+	nftnl_trace_alloc;
+	nftnl_trace_free;
+
+	nftnl_trace_is_set;
+
+	nftnl_trace_get_u8;
+	nftnl_trace_get_u16;
+	nftnl_trace_get_u32;
+	nftnl_trace_get_u64;
+	nftnl_trace_get_str;
+
+	nftnl_trace_nlmsg_parse;
+	nftnl_trace_snprintf;
+	nftnl_trace_fprintf;
+} LIBNFTNL_4;
diff --git a/src/trace.c b/src/trace.c
new file mode 100644
index 0000000..0b95d02
--- /dev/null
+++ b/src/trace.c
@@ -0,0 +1,725 @@
+/*
+ * (C) 2015 Red Hat GmbH
+ * Author: Florian Westphal <fw@strlen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include "internal.h"
+
+#include <time.h>
+#include <endian.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <netinet/in.h>
+
+#include <libmnl/libmnl.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nf_tables.h>
+
+#include <libnftnl/trace.h>
+
+/* header snprintf */
+#include <inttypes.h>
+#include <arpa/inet.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#include <net/ethernet.h>
+#include <net/if_arp.h>
+
+struct nftnl_header_data {
+	char *data;
+	unsigned int len;
+};
+
+struct nftnl_trace {
+	char *chain;
+	char *table;
+	uint64_t rule_handle;
+	struct nftnl_header_data ll;
+	struct nftnl_header_data nh;
+	struct nftnl_header_data th;
+	uint32_t family;
+	uint32_t type;
+	uint32_t id;
+	uint32_t iif;
+	uint32_t oif;
+	uint32_t mark;
+	uint32_t verdict;
+	uint16_t vlan_tag;
+	uint16_t devtype;
+	uint8_t  th_prot;
+
+	uint32_t flags;
+};
+
+static const char *type2str(int type)
+{
+	enum nft_trace_types t = type;
+
+	switch (t) {
+	case NFT_TRACETYPE_PACKET:
+		return "packet"; /* trace start */
+	case NFT_TRACETYPE_POLICY:
+		return "policy";
+	case NFT_TRACETYPE_RETURN:
+		return "return";
+	case NFT_TRACETYPE_RULE:
+		return "rule";
+	case NFT_TRACETYPE_UNSPEC: /* fallthrough */
+	case __NFT_TRACETYPE_MAX:
+		break;
+	}
+
+	return "";
+}
+
+EXPORT_SYMBOL(nftnl_trace_alloc);
+struct nftnl_trace *nftnl_trace_alloc(void)
+{
+	return calloc(1, sizeof(struct nftnl_trace));
+}
+
+EXPORT_SYMBOL(nftnl_trace_free);
+void nftnl_trace_free(struct nftnl_trace *t)
+{
+	xfree(t->chain);
+	xfree(t->table);
+	xfree(t->ll.data);
+	xfree(t->nh.data);
+	xfree(t->th.data);
+	xfree(t);
+}
+
+EXPORT_SYMBOL(nftnl_trace_is_set);
+bool nftnl_trace_is_set(const struct nftnl_trace *t, uint16_t attr)
+{
+	return t->flags & (1 << attr);
+}
+
+static int nftnl_trace_parse_attr_cb(const struct nlattr *attr, void *data)
+{
+	const struct nlattr **tb = data;
+	enum nft_trace_attibutes type = mnl_attr_get_type(attr);
+
+	if (mnl_attr_type_valid(attr, NFTA_TRACE_MAX) < 0)
+		return MNL_CB_OK;
+
+	switch (type) {
+	case NFTA_TRACE_UNSPEC:
+	case __NFTA_TRACE_MAX:
+		break;
+	case NFTA_TRACE_TRANSPORT_PROTO:
+		if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
+			abi_breakage();
+		break;
+	case NFTA_TRACE_DEV_TYPE:
+	case NFTA_TRACE_VLAN_TAG:
+		if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
+			abi_breakage();
+		break;
+	case NFTA_TRACE_ID:
+	case NFTA_TRACE_IIF:
+	case NFTA_TRACE_OIF:
+	case NFTA_TRACE_MARK:
+	case NFTA_TRACE_TYPE:
+	case NFTA_TRACE_VERDICT:
+		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+			abi_breakage();
+		break;
+	case NFTA_TRACE_CHAIN:
+	case NFTA_TRACE_TABLE:
+		if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
+			abi_breakage();
+		break;
+	case NFTA_TRACE_RULE_HANDLE:
+		if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
+			abi_breakage();
+		break;
+	case NFTA_TRACE_LL_HEADER:
+		if (mnl_attr_get_payload_len(attr) == 0)
+			abi_breakage();
+		break;
+	case NFTA_TRACE_NETWORK_HEADER:
+		if (mnl_attr_get_payload_len(attr) < sizeof(struct iphdr))
+			abi_breakage();
+		break;
+	case NFTA_TRACE_TRANSPORT_HEADER:
+		if (mnl_attr_get_payload_len(attr) < sizeof(uint32_t))
+			abi_breakage();
+		break;
+	};
+
+	tb[type] = attr;
+	return MNL_CB_OK;
+}
+
+EXPORT_SYMBOL(nftnl_trace_get_data);
+const void *nftnl_trace_get_data(const struct nftnl_trace *trace,
+				 uint16_t type, uint32_t *data_len)
+{
+	enum nftnl_trace_attr attr = type;
+
+	if (!(trace->flags & (1 << type)))
+		return NULL;
+
+	switch (attr) {
+	case NFTNL_TRACE_FAMILY:
+		*data_len = sizeof(uint32_t);
+		return &trace->family;
+	case NFTNL_TRACE_ID:
+		*data_len = sizeof(uint32_t);
+		return &trace->id;
+	case NFTNL_TRACE_IIF:
+		*data_len = sizeof(uint32_t);
+		return &trace->iif;
+	case NFTNL_TRACE_OIF:
+		*data_len = sizeof(uint32_t);
+		return &trace->oif;
+	case NFTNL_TRACE_LL_HEADER:
+		*data_len = trace->ll.len;
+		return trace->ll.data;
+	case NFTNL_TRACE_MARK:
+		*data_len = sizeof(uint32_t);
+		return &trace->mark;
+	case NFTNL_TRACE_NETWORK_HEADER:
+		*data_len = trace->nh.len;
+		return trace->nh.data;
+	case NFTNL_TRACE_TYPE:
+		*data_len = sizeof(uint32_t);
+		return &trace->type;
+	case NFTNL_TRACE_CHAIN:
+		*data_len = strlen(trace->chain);
+		return trace->chain;
+	case NFTNL_TRACE_TABLE:
+		*data_len = strlen(trace->table);
+		return trace->table;
+	case NFTNL_TRACE_TRANSPORT_HEADER:
+		*data_len = trace->th.len;
+		return trace->th.data;
+	case NFTNL_TRACE_TRANSPORT_PROTO:
+		*data_len = sizeof(uint8_t);
+		return &trace->th_prot;
+	case NFTNL_TRACE_RULE_HANDLE:
+		*data_len = sizeof(uint64_t);
+		return &trace->rule_handle;
+	case NFTNL_TRACE_VERDICT:
+		*data_len = sizeof(uint32_t);
+		return &trace->verdict;
+	case NFTNL_TRACE_VLAN_TAG:
+		*data_len = sizeof(uint16_t);
+		return &trace->vlan_tag;
+	case NFTNL_TRACE_DEV_TYPE:
+		*data_len = sizeof(uint16_t);
+		return &trace->devtype;
+	}
+
+	return NULL;
+}
+
+EXPORT_SYMBOL(nftnl_trace_get_str);
+const char *nftnl_trace_get_str(const struct nftnl_trace *trace, uint16_t type)
+{
+	if (!nftnl_trace_is_set(trace, type))
+		return NULL;
+
+	switch (type) {
+	case NFTNL_TRACE_CHAIN: return trace->chain;
+	case NFTNL_TRACE_TABLE: return trace->table;
+	default: break;
+	}
+	return NULL;
+}
+
+EXPORT_SYMBOL(nftnl_trace_get_u8);
+uint8_t nftnl_trace_get_u8(const struct nftnl_trace *trace, uint16_t type)
+{
+	const uint8_t *d;
+	uint32_t dlen;
+
+	d = nftnl_trace_get_data(trace, type, &dlen);
+	if (d && dlen == sizeof(*d))
+		return *d;
+
+	return 0;
+}
+
+EXPORT_SYMBOL(nftnl_trace_get_u16);
+uint16_t nftnl_trace_get_u16(const struct nftnl_trace *trace, uint16_t type)
+{
+	const uint16_t *d;
+	uint32_t dlen;
+
+	d = nftnl_trace_get_data(trace, type, &dlen);
+	if (d && dlen == sizeof(*d))
+		return *d;
+
+	return 0;
+}
+
+EXPORT_SYMBOL(nftnl_trace_get_u32);
+uint32_t nftnl_trace_get_u32(const struct nftnl_trace *trace, uint16_t type)
+{
+	const uint32_t *d;
+	uint32_t dlen;
+
+	d = nftnl_trace_get_data(trace, type, &dlen);
+	if (d && dlen == sizeof(*d))
+		return *d;
+
+	return 0;
+}
+
+EXPORT_SYMBOL(nftnl_trace_get_u64);
+uint64_t nftnl_trace_get_u64(const struct nftnl_trace *trace, uint16_t type)
+{
+	const uint64_t *d;
+	uint32_t dlen;
+
+	d = nftnl_trace_get_data(trace, type, &dlen);
+	if (d && dlen == sizeof(*d))
+		return *d;
+
+	return 0;
+}
+
+static bool nftnl_trace_nlmsg_parse_hdrdata(struct nlattr *attr,
+					    struct nftnl_header_data *header)
+{
+	uint32_t len;
+
+	if (!attr)
+		return false;
+
+	len = mnl_attr_get_payload_len(attr);
+
+	header->data = malloc(len);
+	if (header->data) {
+		memcpy(header->data, mnl_attr_get_payload(attr), len);
+		header->len = len;
+		return true;
+	}
+
+	return false;
+}
+
+EXPORT_SYMBOL(nftnl_trace_nlmsg_parse);
+int nftnl_trace_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_trace *t)
+{
+	struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
+	struct nlattr *tb[NFTA_TRACE_MAX+1] = {};
+
+	if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_trace_parse_attr_cb, tb) < 0)
+		return -1;
+
+	if (!tb[NFTA_TRACE_ID])
+		abi_breakage();
+
+	if (!tb[NFTA_TRACE_TYPE])
+		abi_breakage();
+
+	if (tb[NFTA_TRACE_TABLE])
+		t->table = strdup(mnl_attr_get_str(tb[NFTA_TRACE_TABLE]));
+	if (tb[NFTA_TRACE_CHAIN])
+		t->chain = strdup(mnl_attr_get_str(tb[NFTA_TRACE_CHAIN]));
+
+	t->family = nfg->nfgen_family;
+	t->flags |= (1 << NFTNL_TRACE_FAMILY);
+
+	t->type = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_TYPE]));
+	t->flags |= (1 << NFTNL_TRACE_TYPE);
+
+	t->id = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_ID]));
+	t->flags |= (1 << NFTNL_TRACE_ID);
+
+	if (tb[NFTA_TRACE_IIF]) {
+		t->iif = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_IIF]));
+		t->flags |= (1 << NFTNL_TRACE_IIF);
+	}
+
+	if (tb[NFTA_TRACE_OIF]) {
+		t->oif = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_OIF]));
+		t->flags |= (1 << NFTNL_TRACE_OIF);
+	}
+
+	if (tb[NFTA_TRACE_MARK]) {
+		t->mark = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_MARK]));
+		t->flags |= (1 << NFTNL_TRACE_MARK);
+	}
+
+	if (tb[NFTA_TRACE_RULE_HANDLE]) {
+		t->rule_handle = be64toh(mnl_attr_get_u64(tb[NFTA_TRACE_RULE_HANDLE]));
+		t->flags |= (1 << NFTNL_TRACE_RULE_HANDLE);
+	}
+
+	if (tb[NFTA_TRACE_VERDICT]) {
+		t->verdict = ntohl(mnl_attr_get_u32(tb[NFTA_TRACE_VERDICT]));
+		t->flags |= (1 << NFTNL_TRACE_VERDICT);
+	}
+
+	if (tb[NFTA_TRACE_VLAN_TAG]) {
+		t->vlan_tag = ntohs(mnl_attr_get_u16(tb[NFTA_TRACE_VLAN_TAG]));
+		t->flags |= (1 << NFTNL_TRACE_VLAN_TAG);
+	}
+
+	if (tb[NFTA_TRACE_DEV_TYPE]) {
+		t->devtype = ntohs(mnl_attr_get_u16(tb[NFTA_TRACE_DEV_TYPE]));
+		t->flags |= (1 << NFTNL_TRACE_DEV_TYPE);
+	}
+
+	if (nftnl_trace_nlmsg_parse_hdrdata(tb[NFTA_TRACE_LL_HEADER], &t->ll))
+		t->flags |= (1 << NFTNL_TRACE_LL_HEADER);
+
+	if (nftnl_trace_nlmsg_parse_hdrdata(tb[NFTA_TRACE_NETWORK_HEADER], &t->nh))
+		t->flags |= (1 << NFTNL_TRACE_NETWORK_HEADER);
+
+	if (nftnl_trace_nlmsg_parse_hdrdata(tb[NFTA_TRACE_TRANSPORT_HEADER], &t->th))
+		t->flags |= (1 << NFTNL_TRACE_TRANSPORT_HEADER);
+
+	if (tb[NFTA_TRACE_TRANSPORT_PROTO]) {
+		t->th_prot = mnl_attr_get_u8(tb[NFTA_TRACE_TRANSPORT_PROTO]);
+		t->flags |= (1 << NFTNL_TRACE_TRANSPORT_PROTO);
+	}
+
+	if (t->chain)
+		t->flags |= (1 << NFTNL_TRACE_CHAIN);
+	if (t->table)
+		t->flags |= (1 << NFTNL_TRACE_TABLE);
+
+	return 0;
+}
+
+static int print_ether_addr(char *buf, size_t size, const void *addr)
+{
+	const uint8_t *mac = addr;
+
+	return snprintf(buf, size, "%02x:%02x:%02x:%02x:%02x:%02x",
+			mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
+static int print_ip4(char *buf, size_t size, uint32_t addr)
+{
+	char addrs[INET_ADDRSTRLEN];
+
+	inet_ntop(AF_INET, &addr, addrs, sizeof(addrs));
+	return snprintf(buf, size, "%s", addrs);
+}
+
+static int print_ip6(char *buf, size_t size, const void *addr)
+{
+	char addrs[INET6_ADDRSTRLEN];
+
+	inet_ntop(AF_INET6, addr, addrs, sizeof(addrs));
+	return snprintf(buf, size, "%s", addrs);
+}
+
+static int
+print_th(const struct nftnl_trace *t, char *buf, size_t size)
+{
+	uint8_t proto = nftnl_trace_get_u8(t, NFTNL_TRACE_TRANSPORT_PROTO);
+	int ret, len = size, offset = 0;
+	const struct udphdr *uh;
+	uint32_t plen;
+
+	ret = snprintf(buf+offset, len, " protocol %u", proto);
+
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	switch (proto) {
+	case IPPROTO_DCCP:
+	case IPPROTO_SCTP:
+	case IPPROTO_TCP:
+	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE:
+		break;
+	default:
+		return 0;
+	}
+
+	/* warning: only sport/dport are valid */
+	uh = nftnl_trace_get_data(t, NFTNL_TRACE_TRANSPORT_HEADER, &plen);
+	if (!uh)
+		return 0;
+
+	ret = snprintf(buf+offset, len, " sport %"PRIu16 " dport %"PRIu16,
+			ntohs(uh->uh_sport), ntohs(uh->uh_dport));
+
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	return offset;
+}
+
+static int log_packet6(const struct nftnl_trace *t, char *buf, size_t size)
+{
+	int ret, len = size, offset = 0;
+	const struct ip6_hdr *iph;
+	uint32_t plen;
+
+	iph = nftnl_trace_get_data(t, NFTNL_TRACE_NETWORK_HEADER, &plen);
+	if (!iph || plen < sizeof(iph))
+		return 0;
+
+	ret = snprintf(buf+offset, len, " src ");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = print_ip6(buf+offset, len, &iph->ip6_src);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, " dst ");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = print_ip6(buf+offset, len, &iph->ip6_dst);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, " len %u hoplimit %u",
+		       ntohs(iph->ip6_plen), iph->ip6_hlim);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = print_th(t, buf+offset, len);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	return offset;
+}
+
+static int log_packet4(const struct nftnl_trace *t, char *buf, size_t size)
+{
+	int ret, len = size, offset = 0;
+	const struct iphdr *iph;
+	uint32_t plen;
+
+	iph = nftnl_trace_get_data(t, NFTNL_TRACE_NETWORK_HEADER, &plen);
+	if (!iph || plen < sizeof(iph))
+		return 0;
+
+	ret = snprintf(buf+offset, len, " src ");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = print_ip4(buf+offset, len, iph->saddr);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, " dst ");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = print_ip4(buf+offset, len, iph->daddr);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, " len %u ttl %u id %u",
+			ntohs(iph->tot_len), iph->ttl, ntohs(iph->id));
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	if (iph->frag_off & htons(IP_OFFMASK)) {
+		ret = snprintf(buf+offset, len, " frag %u protocol %u",
+				ntohs(iph->frag_off) & IP_OFFMASK, iph->protocol);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	} else {
+		ret = print_th(t, buf+offset, len);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	return offset;
+}
+
+static bool log_packet_inet(const struct nftnl_trace *t, char *buf, size_t size)
+{
+	const struct iphdr *iph;
+	uint32_t plen;
+
+	iph = nftnl_trace_get_data(t, NFTNL_TRACE_NETWORK_HEADER, &plen);
+	if (!iph)
+		return 0;
+
+	switch (iph->version) {
+	case 4: return log_packet4(t, buf, size);
+	case 6: return log_packet6(t, buf, size);
+	default: break;
+	}
+	return true;
+}
+
+static bool log_packet_arp(const struct nftnl_trace *t, char *buf, size_t size)
+{
+	int ret, len = size, offset = 0;
+	const struct arphdr *arph;
+	uint32_t plen;
+
+	arph = nftnl_trace_get_data(t, NFTNL_TRACE_NETWORK_HEADER, &plen);
+	if (!arph || plen < sizeof(arph))
+		return 0;
+
+	ret = snprintf(buf+offset, len, " arpop 0x%x", ntohs(arph->ar_op));
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	return ret;
+}
+
+static int log_packet_bridge(const struct nftnl_trace *t, char *buf, size_t size)
+{
+	const struct ether_header *ethh;
+	int ret, len = size, offset = 0;
+	uint32_t hlen;
+
+	ethh = nftnl_trace_get_data(t, NFTNL_TRACE_LL_HEADER, &hlen);
+	if (!ethh || hlen < sizeof(ethh))
+		return log_packet_inet(t, buf+offset, len);
+
+	ret = snprintf(buf+offset, len, " src ");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = print_ether_addr(buf+offset, len, ethh->ether_shost);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, " dst ");
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = print_ether_addr(buf+offset, len, ethh->ether_dhost);
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	switch (ntohs(ethh->ether_type)) {
+	case ETHERTYPE_ARP:
+		return log_packet_arp(t, buf+offset, len);
+	case ETHERTYPE_IP:
+		return log_packet4(t, buf+offset, len);
+	case ETHERTYPE_IPV6:
+		return log_packet6(t, buf+offset, len);
+	default:
+		ret = snprintf(buf+offset, len, " ethertype 0x%x", ntohs(ethh->ether_type));
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+		break;
+	}
+
+	return offset;
+
+}
+
+static int log_packet_netdev(const struct nftnl_trace *t, char *buf, size_t size)
+{
+	int ret, len = size, offset = 0;
+
+	switch (t->devtype) {
+	case ARPHRD_ETHER:
+		return log_packet_bridge(t, buf+offset, len);
+	default:
+		ret = snprintf(buf+offset, len, "devtype 0x%04x", t->devtype);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+		return log_packet_inet(t, buf+offset, len);
+	}
+
+	return 0;
+}
+
+static int log_packet(const struct nftnl_trace *t, char *buf, size_t size)
+{
+	int ret, len = size, offset = 0;
+	switch (t->family) {
+	case NFPROTO_IPV4:
+		ret = log_packet4(t, buf+offset, len);
+		break;
+	case NFPROTO_IPV6:
+		ret = log_packet6(t, buf+offset, len);
+		break;
+	case NFPROTO_INET:
+		ret = log_packet_inet(t, buf+offset, len);
+		break;
+	case NFPROTO_ARP: /* fallthrough */
+	case NFPROTO_BRIDGE:
+		ret = log_packet_bridge(t, buf+offset, len);
+		break;
+	case NFPROTO_NETDEV:
+		ret = log_packet_netdev(t, buf+offset, len);
+		break;
+	default:
+		ret = snprintf(buf+offset, len, " family %d", t->family);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+		break;
+	}
+
+	return offset;
+}
+
+static int nftnl_trace_snprintf_default(char *buf, size_t size,
+				        const struct nftnl_trace *t)
+{
+	int ret, len = size, offset = 0;
+
+	ret = snprintf(buf+offset, len, "id %08x", nftnl_trace_get_u32(t, NFTNL_TRACE_ID));
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	ret = snprintf(buf+offset, len, " %s", nftnl_family2str(t->family));
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	if (nftnl_trace_is_set(t, NFTNL_TRACE_TABLE)) {
+		ret = snprintf(buf+offset, len, " %s", t->table);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	if (nftnl_trace_is_set(t, NFTNL_TRACE_CHAIN)) {
+		ret = snprintf(buf+offset, len, " %s", t->chain);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	ret = snprintf(buf+offset, len, " %s", type2str(t->type));
+	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+	if (nftnl_trace_is_set(t, NFTNL_TRACE_VERDICT)) {
+		ret = snprintf(buf+offset, len, " verdict %s",
+				nftnl_verdict2str(nftnl_trace_get_u32(t, NFTNL_TRACE_VERDICT)));
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	if (nftnl_trace_is_set(t, NFTNL_TRACE_MARK)) {
+		ret = snprintf(buf+offset, len,
+			       " mark 0x%x", nftnl_trace_get_u32(t, NFTNL_TRACE_MARK));
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	if (nftnl_trace_is_set(t, NFTNL_TRACE_VLAN_TAG)) {
+		ret = snprintf(buf+offset, len,
+			       " vlan id %d", nftnl_trace_get_u16(t, NFTNL_TRACE_VLAN_TAG));
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	if (nftnl_trace_is_set(t, NFTNL_TRACE_LL_HEADER) ||
+	    nftnl_trace_is_set(t, NFTNL_TRACE_NETWORK_HEADER)) {
+		ret = log_packet(t, buf+offset, len);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
+	return offset;
+}
+
+
+EXPORT_SYMBOL(nftnl_trace_snprintf);
+int nftnl_trace_snprintf(char *buf, size_t size, const struct nftnl_trace *t, uint32_t type)
+{
+	int ret = 0;
+
+	switch (type) {
+	case NFTNL_OUTPUT_DEFAULT:
+		ret = nftnl_trace_snprintf_default(buf, size, t);
+		break;
+	default:
+		return -1;
+	}
+
+	return ret;
+}
+
+static int nftnl_trace_do_snprintf(char *buf, size_t size, void *r,
+				   uint32_t cmd, uint32_t type,
+				   uint32_t flags)
+{
+	return nftnl_trace_snprintf(buf, size, r, type);
+}
+
+
+EXPORT_SYMBOL(nftnl_trace_fprintf);
+int nftnl_trace_fprintf(FILE *fp, const struct nftnl_trace *t, uint32_t type)
+{
+	return nftnl_fprintf(fp, (void *) t, NFTNL_CMD_UNSPEC, type, 0,
+			   nftnl_trace_do_snprintf);
+}
diff --git a/src/utils.c b/src/utils.c
index 84fbe94..fb68b1a 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -152,6 +152,10 @@ const char *nftnl_verdict2str(uint32_t verdict)
 		return "jump";
 	case NFT_GOTO:
 		return "goto";
+	case NFT_CONTINUE:
+		return "continue";
+	case NFT_BREAK:
+		return "break";
 	default:
 		return "unknown";
 	}
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH nftables 6/6] src: add trace support to nft monitor mode
  2015-11-24 10:02 [PATCH 0/6] nftables trace support Florian Westphal
                   ` (4 preceding siblings ...)
  2015-11-24 10:02 ` [PATCH libnftnl 5/6] src: add trace infrastructure support Florian Westphal
@ 2015-11-24 10:02 ` Florian Westphal
  2015-11-24 10:25   ` Patrick McHardy
  5 siblings, 1 reply; 80+ messages in thread
From: Florian Westphal @ 2015-11-24 10:02 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Florian Westphal

nft monitor [ trace ]

... can now display nftables nftrace debug information.

$ nft rule bridge raw prerouting add tcp dport 22 limit rate 1/second meta nftrace set 1
$ nft monitor trace
trace id 834dd100 bridge packet src 5e:95:99:72:ea:c5 dst 52:54:40:a2:3f:a6 src 192.168.7.1 dst 192.168.7.11 len 88 ttl 64 id 2719 protocol 6 sport 3628 dport 22 iif eth0
trace id 834dd100 bridge raw prerouting rule verdict continue iif eth0
trace id 834dd100 rule tcp dport ssh limit rate 1/second nftrace set 1
trace id 834dd100 bridge raw prerouting policy verdict accept iif eth0
trace id 834dd100 ip filter input rule verdict jump iif br0
trace id 834dd100 rule ip saddr . tcp dport vmap { }
trace id 834dd100 ip filter test rule verdict accept iif br0
trace id 834dd100 rule accept

based on an initial patch from Markus Kötter.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 include/linux/netfilter/nf_tables.h | 30 +++++++++++++
 src/evaluate.c                      | 18 ++++++++
 src/netlink.c                       | 84 +++++++++++++++++++++++++++++++++++++
 src/rule.c                          | 47 +++++++++++++++++----
 4 files changed, 170 insertions(+), 9 deletions(-)

diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 5ebe3d8..85d739b 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -101,6 +101,7 @@ enum nf_tables_msg_types {
 	NFT_MSG_DELSETELEM,
 	NFT_MSG_NEWGEN,
 	NFT_MSG_GETGEN,
+	NFT_MSG_TRACE,
 	NFT_MSG_MAX,
 };
 
@@ -961,4 +962,33 @@ enum nft_gen_attributes {
 };
 #define NFTA_GEN_MAX		(__NFTA_GEN_MAX - 1)
 
+enum nft_trace_attibutes {
+	NFTA_TRACE_UNSPEC,
+	NFTA_TRACE_CHAIN,
+	NFTA_TRACE_ID,
+	NFTA_TRACE_IIF,
+	NFTA_TRACE_OIF,
+	NFTA_TRACE_LL_HEADER,
+	NFTA_TRACE_LL_TYPE,
+	NFTA_TRACE_MARK,
+	NFTA_TRACE_PAYLOAD,
+	NFTA_TRACE_TABLE,
+	NFTA_TRACE_TYPE,
+	NFTA_TRACE_RULE_HANDLE,
+	NFTA_TRACE_VERDICT,
+	NFTA_TRACE_VLAN_TAG,
+	NFTA_TRACE_DEVTYPE,
+	__NFTA_TRACE_MAX
+};
+#define NFTA_TRACE_MAX (__NFTA_TRACE_MAX - 1)
+
+enum nft_trace_types {
+	NFT_TRACETYPE_UNSPEC,
+	NFT_TRACETYPE_PACKET,
+	NFT_TRACETYPE_POLICY,
+	NFT_TRACETYPE_RETURN,
+	NFT_TRACETYPE_RULE,
+	__NFT_TRACETYPE_MAX
+};
+#define NFT_TRACETYPE_MAX (__NFT_TRACETYPE_MAX - 1)
 #endif /* _LINUX_NF_TABLES_H */
diff --git a/src/evaluate.c b/src/evaluate.c
index 48f071f..b1ab8e9 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2279,6 +2279,7 @@ enum {
 	CMD_MONITOR_EVENT_ANY,
 	CMD_MONITOR_EVENT_NEW,
 	CMD_MONITOR_EVENT_DEL,
+	CMD_MONITOR_EVENT_TRACE,
 	CMD_MONITOR_EVENT_MAX
 };
 
@@ -2320,6 +2321,21 @@ static uint32_t monitor_flags[CMD_MONITOR_EVENT_MAX][CMD_MONITOR_OBJ_MAX] = {
 		[CMD_MONITOR_OBJ_SETS]		= (1 << NFT_MSG_DELSET),
 		[CMD_MONITOR_OBJ_ELEMS]		= (1 << NFT_MSG_DELSETELEM),
 	},
+	[CMD_MONITOR_EVENT_TRACE] = {
+		[CMD_MONITOR_OBJ_ANY]		= (1 << NFT_MSG_NEWTABLE) |
+						  (1 << NFT_MSG_NEWCHAIN) |
+						  (1 << NFT_MSG_NEWRULE)  |
+						  (1 << NFT_MSG_DELTABLE) |
+						  (1 << NFT_MSG_DELCHAIN) |
+						  (1 << NFT_MSG_DELRULE)  |
+						  (1 << NFT_MSG_TRACE),
+		[CMD_MONITOR_OBJ_TABLES]	= (1 << NFT_MSG_NEWTABLE) |
+						  (1 << NFT_MSG_DELTABLE),
+		[CMD_MONITOR_OBJ_CHAINS]	= (1 << NFT_MSG_NEWCHAIN) |
+						  (1 << NFT_MSG_DELCHAIN),
+		[CMD_MONITOR_OBJ_RULES]		= (1 << NFT_MSG_NEWRULE) |
+						  (1 << NFT_MSG_DELRULE),
+	},
 };
 
 static int cmd_evaluate_monitor(struct eval_ctx *ctx, struct cmd *cmd)
@@ -2332,6 +2348,8 @@ static int cmd_evaluate_monitor(struct eval_ctx *ctx, struct cmd *cmd)
 		event = CMD_MONITOR_EVENT_NEW;
 	else if (strcmp(cmd->monitor->event, "destroy") == 0)
 		event = CMD_MONITOR_EVENT_DEL;
+	else if (strcmp(cmd->monitor->event, "trace") == 0)
+		event = CMD_MONITOR_EVENT_TRACE;
 	else {
 		return monitor_error(ctx, cmd->monitor, "invalid event %s",
 				     cmd->monitor->event);
diff --git a/src/netlink.c b/src/netlink.c
index 974afb1..8ab7bbe 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -18,6 +18,7 @@
 #include <stdlib.h>
 
 #include <libnftnl/table.h>
+#include <libnftnl/trace.h>
 #include <libnftnl/chain.h>
 #include <libnftnl/expr.h>
 #include <libnftnl/set.h>
@@ -33,6 +34,7 @@
 #include <gmputil.h>
 #include <utils.h>
 #include <erec.h>
+#include <iface.h>
 
 static struct mnl_socket *nf_sock;
 static struct mnl_socket *nf_mon_sock;
@@ -2125,6 +2127,85 @@ static void netlink_events_cache_update(struct netlink_mon_handler *monh,
 	}
 }
 
+static void trace_print_rule(const struct nftnl_trace *nlt)
+{
+	const struct table *table;
+	uint64_t rule_handle;
+	struct chain *chain;
+	struct handle h;
+
+	h.table  = nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE);
+	h.chain  = nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN);
+	h.family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY);
+
+	if (!h.table)
+		return;
+
+	table = table_lookup(&h);
+	if (!table)
+		return;
+
+	chain = chain_lookup(table, &h);
+	if (!chain)
+		return;
+
+	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_RULE_HANDLE)) {
+		struct rule *rule;
+
+		rule_handle = nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE);
+
+		list_for_each_entry(rule, &chain->rules, list) {
+			if (rule->handle.handle != rule_handle)
+				continue;
+
+			printf("\ntrace id %08x rule ", nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID));
+			rule_print(rule);
+			return;
+		}
+	}
+}
+
+static void trace_print_if(const struct nftnl_trace *nlt, uint16_t attr, const char *str)
+{
+	char __name[IFNAMSIZ];
+	const char *ifname;
+
+        if (!nftnl_trace_is_set(nlt, attr))
+		return;
+
+	ifname = nft_if_indextoname(nftnl_trace_get_u32(nlt, attr), __name);
+	if (ifname)
+		printf(" %s %s", str, ifname);
+	else
+		printf(" %s %d", str, nftnl_trace_get_u32(nlt, attr));
+}
+
+static int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type,
+				   struct netlink_mon_handler *monh)
+{
+	struct nftnl_trace *nlt;
+
+	assert(type == NFT_MSG_TRACE);
+
+	nlt = nftnl_trace_alloc();
+	if (!nlt)
+		memory_allocation_error();
+
+	if (nftnl_trace_nlmsg_parse(nlh, nlt) < 0)
+		netlink_abi_error();
+
+	printf("trace ");
+	nftnl_trace_fprintf(stdout, nlt, monh->format);
+
+	trace_print_if(nlt, NFTNL_TRACE_IIF, "iif");
+	trace_print_if(nlt, NFTNL_TRACE_OIF, "oif");
+
+	trace_print_rule(nlt);
+	printf("\n");
+	nftnl_trace_free(nlt);
+	return MNL_CB_OK;
+}
+
 static int netlink_events_cb(const struct nlmsghdr *nlh, void *data)
 {
 	int ret = MNL_CB_OK;
@@ -2157,6 +2238,9 @@ static int netlink_events_cb(const struct nlmsghdr *nlh, void *data)
 	case NFT_MSG_DELRULE:
 		ret = netlink_events_rule_cb(nlh, type, monh);
 		break;
+	case NFT_MSG_TRACE:
+		ret = netlink_events_trace_cb(nlh, type, monh);
+		break;
 	}
 	fflush(stdout);
 
diff --git a/src/rule.c b/src/rule.c
index 5d3cd84..553990d 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -1192,27 +1192,56 @@ static int do_command_rename(struct netlink_ctx *ctx, struct cmd *cmd)
 	return 0;
 }
 
-static int do_command_monitor(struct netlink_ctx *ctx, struct cmd *cmd)
+static bool need_cache(const struct cmd *cmd)
 {
-	struct table *t;
-	struct set *s;
-	struct netlink_mon_handler monhandler;
-
-	/* cache only needed if monitoring:
+	/*
 	 *  - new rules in default format
 	 *  - new elements
 	 */
 	if (((cmd->monitor->flags & (1 << NFT_MSG_NEWRULE)) &&
 	    (cmd->monitor->format == NFTNL_OUTPUT_DEFAULT)) ||
 	    (cmd->monitor->flags & (1 << NFT_MSG_NEWSETELEM)))
-		monhandler.cache_needed = true;
-	else
-		monhandler.cache_needed = false;
+		return true;
 
+	if (cmd->monitor->flags & (1 << NFT_MSG_TRACE))
+		return true;
+
+	return false;
+}
+
+static int do_command_monitor(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+	struct table *t;
+	struct set *s;
+	struct netlink_mon_handler monhandler;
+
+	monhandler.cache_needed = need_cache(cmd);
 	if (monhandler.cache_needed) {
+		struct rule *rule, *nrule;
+		struct chain *chain;
+		int ret;
+
 		list_for_each_entry(t, &table_list, list) {
 			list_for_each_entry(s, &t->sets, list)
 				s->init = set_expr_alloc(&cmd->location);
+
+			if (!(cmd->monitor->flags & (1 << NFT_MSG_TRACE)))
+				continue;
+
+			/* When tracing we'd like to translate the rule handle
+			 * we receive in the trace messages to the actual rule
+			 * struct to print that out.  Populate rule cache now.
+			 */
+			ret = netlink_list_table(ctx, &t->handle,
+						 &internal_location);
+
+			if (ret != 0) /* shouldn't happen && doesn't break things too badly */
+				continue;
+
+			list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
+				chain = chain_lookup(t, &rule->handle);
+				list_move_tail(&rule->list, &chain->rules);
+			}
 		}
 	}
 
-- 
2.4.10

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

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* Re: [PATCH libnftnl 4/6] src: rename EXPORT_SYMBOL to EXPORT_SYMBOL_ALIAS
  2015-11-24 10:02 ` [PATCH libnftnl 4/6] src: rename EXPORT_SYMBOL to EXPORT_SYMBOL_ALIAS Florian Westphal
@ 2015-11-24 10:11   ` Pablo Neira Ayuso
  0 siblings, 0 replies; 80+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-24 10:11 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On Tue, Nov 24, 2015 at 11:02:09AM +0100, Florian Westphal wrote:
> Future symbols don't need backwards-compat aliases.

Florian, good point.

I have just pushed out this to make sure ongoing work uses the right
macro and avoid rebases.

Thanks.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 2/6] netfilter: nf_tables: wrap tracing with a static key
  2015-11-24 10:02 ` [PATCH nf-next 2/6] netfilter: nf_tables: wrap tracing with a static key Florian Westphal
@ 2015-11-24 10:13   ` Patrick McHardy
  2015-11-24 10:21     ` Florian Westphal
  2015-11-24 10:19   ` Pablo Neira Ayuso
  1 sibling, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 10:13 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On 24.11, Florian Westphal wrote:
> diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
> index 29a6ca9..dabf5ed 100644
> --- a/net/netfilter/nf_tables_core.c
> +++ b/net/netfilter/nf_tables_core.c
> @@ -138,7 +144,8 @@ next_rule:
>  		if (unlikely(rule->genmask & (1 << gencursor)))
>  			continue;
>  
> -		rulenum++;
> +		if (static_key_false(&nft_trace_enabled))
> +			rulenum++;

This API is deprecated, see Documentation/static-keys.txt.

I'm also wondering if this introduces a race condition on architectures
that don't support jump labels. static_key_slow_inc() simply increases
the ->enabled counter without further synchronization, so this might
happen while we're executing this function and some of the increments
might be skipped.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-24 10:02 ` [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present Florian Westphal
@ 2015-11-24 10:16   ` Patrick McHardy
  2015-11-24 10:24   ` Pablo Neira Ayuso
  2015-11-25  0:57   ` Patrick McHardy
  2 siblings, 0 replies; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 10:16 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On 24.11, Florian Westphal wrote:
> No need to clutter nflog/dmesg ring buffer with the old tracing output
> when the 'native' nfnetlink interface is used.
> 
> Signed-off-by: Florian Westphal <fw@strlen.de>
> ---
>  net/netfilter/nf_tables_core.c | 9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)
> 
> diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
> index dabf5ed..69bdd9a 100644
> --- a/net/netfilter/nf_tables_core.c
> +++ b/net/netfilter/nf_tables_core.c
> @@ -55,6 +55,7 @@ static void __nft_trace_packet(const struct nft_pktinfo *pkt,
>  		     rulenum);
>  }
>  
> +static bool prefer_native_trace __read_mostly;
>  struct static_key nft_trace_enabled __read_mostly;
>  EXPORT_SYMBOL_GPL(nft_trace_enabled);
>  
> @@ -69,7 +70,13 @@ static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
>  		if (!pkt->skb->nf_trace)
>  			return;
>  		nf_tables_trace_notify(pkt, chain, rule, verdict, type);
> -		__nft_trace_packet(pkt, chain, rulenum, type);
> +		if (prefer_native_trace)
> +			return;
> +
> +		if (nfnetlink_has_listeners(pkt->net, NFNLGRP_NFTABLES))
> +			prefer_native_trace = true;

This seems to be better placed in a netlink bind callback.

> +		else
> +			__nft_trace_packet(pkt, chain, rulenum, type);
>  	}
>  }

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-24 10:02 ` [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure Florian Westphal
@ 2015-11-24 10:17   ` Pablo Neira Ayuso
  2015-11-24 10:27     ` Florian Westphal
  2015-11-24 10:22   ` Pablo Neira Ayuso
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 80+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-24 10:17 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On Tue, Nov 24, 2015 at 11:02:06AM +0100, Florian Westphal wrote:
> nft monitor mode can then decode and display this trace data.
> 
> Parts of LL/Network/Transport headers are provided as separate
> attributes.
> 
> Otherwise, printing IP address data becomes virtually impossible
> for userspace since in the case of the netdev family we really don't
> want userspace to have to know all the possible link layer types
> and/or sizes just to display/print an ip address.
> 
> We also don't want userspace to have to follow ipv6 header chains
> to get the s/dport info, the kernel already did this work so just
> follow suit.
> 
> Signed-off-by: Florian Westphal <fw@strlen.de>
> ---
>  include/net/netfilter/nf_tables.h        |   6 +
>  include/uapi/linux/netfilter/nf_tables.h |  32 ++++++
>  net/netfilter/nf_tables_api.c            | 190 +++++++++++++++++++++++++++++++
>  net/netfilter/nf_tables_core.c           |  28 +++--
>  net/netfilter/nft_meta.c                 |   3 +
>  5 files changed, 252 insertions(+), 7 deletions(-)
> 
> diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
> index 4bd7508..5131ad4 100644
> --- a/include/net/netfilter/nf_tables.h
> +++ b/include/net/netfilter/nf_tables.h
> @@ -890,6 +890,12 @@ void nft_unregister_chain_type(const struct nf_chain_type *);
>  int nft_register_expr(struct nft_expr_type *);
>  void nft_unregister_expr(struct nft_expr_type *);
>  
> +void nf_tables_trace_notify(const struct nft_pktinfo *pkt,
> +			    const struct nft_chain *chain,
> +			    const struct nft_rule *rule,
> +			    u32 verdict,
> +			    enum nft_trace_types type);
> +
>  #define nft_dereference(p)					\
>  	nfnl_dereference(p, NFNL_SUBSYS_NFTABLES)
>  
> diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
> index d8c8a7c..88bcd00 100644
> --- a/include/uapi/linux/netfilter/nf_tables.h
> +++ b/include/uapi/linux/netfilter/nf_tables.h
> @@ -83,6 +83,7 @@ enum nft_verdicts {
>   * @NFT_MSG_DELSETELEM: delete a set element (enum nft_set_elem_attributes)
>   * @NFT_MSG_NEWGEN: announce a new generation, only for events (enum nft_gen_attributes)
>   * @NFT_MSG_GETGEN: get the rule-set generation (enum nft_gen_attributes)
> + * @NFT_MSG_TRACE: trace event (enum nft_trace_attributes)
>   */
>  enum nf_tables_msg_types {
>  	NFT_MSG_NEWTABLE,
> @@ -102,6 +103,7 @@ enum nf_tables_msg_types {
>  	NFT_MSG_DELSETELEM,
>  	NFT_MSG_NEWGEN,
>  	NFT_MSG_GETGEN,
> +	NFT_MSG_TRACE,
>  	NFT_MSG_MAX,
>  };
>  
> @@ -970,4 +972,34 @@ enum nft_gen_attributes {
>  };
>  #define NFTA_GEN_MAX		(__NFTA_GEN_MAX - 1)
>  
> +enum nft_trace_attibutes {
> +	NFTA_TRACE_UNSPEC,
> +	NFTA_TRACE_CHAIN,
> +	NFTA_TRACE_DEV_TYPE,
> +	NFTA_TRACE_ID,
> +	NFTA_TRACE_IIF,
> +	NFTA_TRACE_OIF,
> +	NFTA_TRACE_LL_HEADER,
> +	NFTA_TRACE_MARK,
> +	NFTA_TRACE_NETWORK_HEADER,
> +	NFTA_TRACE_TABLE,
> +	NFTA_TRACE_TRANSPORT_HEADER,
> +	NFTA_TRACE_TRANSPORT_PROTO,
> +	NFTA_TRACE_TYPE,
> +	NFTA_TRACE_RULE_HANDLE,
> +	NFTA_TRACE_VERDICT,
> +	NFTA_TRACE_VLAN_TAG,
> +	__NFTA_TRACE_MAX
> +};
> +#define NFTA_TRACE_MAX (__NFTA_TRACE_MAX - 1)
> +
> +enum nft_trace_types {
> +	NFT_TRACETYPE_UNSPEC,
> +	NFT_TRACETYPE_PACKET,
> +	NFT_TRACETYPE_POLICY,
> +	NFT_TRACETYPE_RETURN,
> +	NFT_TRACETYPE_RULE,
> +	__NFT_TRACETYPE_MAX
> +};
> +#define NFT_TRACETYPE_MAX (__NFT_TRACETYPE_MAX - 1)
>  #endif /* _LINUX_NF_TABLES_H */
> diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
> index 93cc473..25d8168 100644
> --- a/net/netfilter/nf_tables_api.c
> +++ b/net/netfilter/nf_tables_api.c
> @@ -9,6 +9,8 @@
>   */
>  
>  #include <linux/module.h>
> +#include <linux/hash.h>
> +#include <linux/if_vlan.h>
>  #include <linux/init.h>
>  #include <linux/list.h>
>  #include <linux/skbuff.h>
> @@ -21,6 +23,10 @@
>  #include <net/net_namespace.h>
>  #include <net/sock.h>
>  
> +#define NFT_TRACETYPE_LL_HSIZE		20
> +#define NFT_TRACETYPE_NETWORK_HSIZE	32
> +#define NFT_TRACETYPE_TRANSPORT_HSIZE	 4
> +
>  static LIST_HEAD(nf_tables_expressions);
>  
>  /**
> @@ -468,6 +474,84 @@ nla_put_failure:
>  	return -1;
>  }
>  
> +static bool trace_notify_put_data(struct sk_buff *nlskb, u16 type,
> +				  const struct sk_buff *skb,
> +				  int off, unsigned int plen)

Minor nitpick: Probably you can rename this to _fill_*_info for
consistency with other nf_tables netlink code.

> +{
> +	struct nlattr *nla;
> +
> +	if (skb_tailroom(nlskb) < nla_total_size(plen))
> +		return false;
> +
> +	nla = (struct nlattr *)skb_put(nlskb, nla_total_size(plen));
> +	nla->nla_type = type;
> +	nla->nla_len = nla_attr_size(plen);
> +
> +	if (skb_copy_bits(skb, off, nla_data(nla), plen))
> +		return false;
> +
> +	return true;
> +}
> +
> +static bool
> +trace_notify_put_packet(struct sk_buff *nlskb, const struct nft_pktinfo *pkt)
> +{
> +	const struct sk_buff *skb = pkt->skb;
> +	unsigned int plen = min_t(unsigned int,
> +				  pkt->xt.thoff - skb_network_offset(skb),
> +				  NFT_TRACETYPE_NETWORK_HSIZE);
> +	int mac_off;
> +
> +	if (plen >= 20u && /* minimum iphdr size */
> +	    !trace_notify_put_data(nlskb, NFTA_TRACE_NETWORK_HEADER,
> +				   skb, skb_network_offset(skb), plen))
> +		return false;
> +
> +	if (nla_put_u8(nlskb, NFTA_TRACE_TRANSPORT_PROTO, pkt->tprot))
> +		return false;
> +
> +	plen = min_t(unsigned int, skb->len - pkt->xt.thoff,
> +		     NFT_TRACETYPE_TRANSPORT_HSIZE);
> +
> +	if (plen >= sizeof(u32) &&
> +	    !trace_notify_put_data(nlskb, NFTA_TRACE_TRANSPORT_HEADER,
> +				   skb, pkt->xt.thoff, plen))
> +		return false;
> +
> +	switch (pkt->pf) {
> +	case NFPROTO_ARP: /* fallthrough */
> +	case NFPROTO_BRIDGE:
> +		break;
> +	case NFPROTO_NETDEV:
> +		if (WARN_ON_ONCE(!skb->dev))
> +			break;
> +		if (nla_put_be16(nlskb, NFTA_TRACE_DEV_TYPE,
> +				 htons(skb->dev->type)))
> +			return false;
> +		break;
> +	default:
> +		return true;
> +	}
> +
> +	if (skb_vlan_tag_get(skb) &&
> +	    !nla_put_be16(nlskb, NFTA_TRACE_VLAN_TAG,
> +			  htons(skb_vlan_tag_get(skb))))
> +		return false;
> +
> +	if (!skb_mac_header_was_set(skb))
> +		return true;
> +
> +	plen = min_t(unsigned int,
> +		     skb->data - skb_mac_header(skb), NFT_TRACETYPE_LL_HSIZE);
> +	mac_off = skb_mac_header(skb) - skb->data;
> +
> +	if (plen && !trace_notify_put_data(nlskb, NFTA_TRACE_LL_HEADER,
> +					   skb, mac_off, plen))
> +		return false;
> +
> +	return true;
> +}

Do you think we can place all this new netlink code in
net/netfilter/nf_tables_trace.c ? So we leave in the core file only
our classifier engine.

I like the attribute definition rename in nf_tables.h, but this code
we can probably place it away from here.

>  static int nf_tables_table_notify(const struct nft_ctx *ctx, int event)
>  {
>  	struct sk_buff *skb;
> @@ -499,6 +583,112 @@ err:
>  	return err;
>  }
>  
> +void nf_tables_trace_notify(const struct nft_pktinfo *pkt,
> +			    const struct nft_chain *chain,
> +			    const struct nft_rule *rule,
> +			    u32 verdict,
> +			    enum nft_trace_types type)
> +{
> +	struct nfgenmsg *nfmsg;
> +	struct nlmsghdr *nlh;
> +	struct sk_buff *skb;
> +	unsigned int size;
> +	int event = (NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_TRACE;
> +
> +	if (!nfnetlink_has_listeners(pkt->net, NFNLGRP_NFTABLES))
> +		return;
> +
> +	/* Unlike other notifiers we need GFP_ATOMIC so use actual size
> +	 * needed instead of NLMSG_GOODSIZE.
> +	 */
> +	size = nlmsg_total_size(sizeof(struct nfgenmsg))
> +		+ nla_total_size(sizeof(__be32))	/* trace type */
> +		+ nla_total_size(NFT_TABLE_MAXNAMELEN)
> +		+ nla_total_size(NFT_CHAIN_MAXNAMELEN)
> +		+ nla_total_size(sizeof(u32))	/* iif */
> +		+ nla_total_size(sizeof(u32))	/* oif */
> +		+ nla_total_size(sizeof(u32))	/* id */
> +		+ nla_total_size(sizeof(u32))	/* mark */
> +		+ nla_total_size(sizeof(u32))	/* verdict */
> +		+ nla_total_size(sizeof(__be64)); /* rule handle */
> +
> +	switch (type) {
> +	case NFT_TRACETYPE_PACKET:
> +		size += nla_total_size(NFT_TRACETYPE_NETWORK_HSIZE)
> +			+ nla_total_size(NFT_TRACETYPE_TRANSPORT_HSIZE)
> +			+ nla_total_size(NFT_TRACETYPE_LL_HSIZE)
> +			+ nla_total_size(sizeof(__be16)) /* vlan tag */
> +			+ nla_total_size(sizeof(__be16)) /* device type */
> +			+ nla_total_size(sizeof(__u8));  /* transport prot */
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	skb = nlmsg_new(size, GFP_ATOMIC);
> +	if (!skb)
> +		return;
> +
> +	nlh = nlmsg_put(skb, 0, 0, event, sizeof(struct nfgenmsg), 0);
> +	if (!nlh)
> +		goto nla_put_failure;
> +
> +	nfmsg = nlmsg_data(nlh);
> +	nfmsg->nfgen_family	= pkt->pf;
> +	nfmsg->version		= NFNETLINK_V0;
> +	nfmsg->res_id		= htons(pkt->net->nft.base_seq & 0xffff);
> +
> +	if (nla_put_be32(skb, NFTA_TRACE_TYPE, htonl(type)))
> +		goto nla_put_failure;
> +
> +	if (nla_put_be32(skb, NFTA_TRACE_ID, htonl(hash32_ptr(pkt->skb))))
> +		goto nla_put_failure;
> +
> +	if (chain) {
> +		if (nla_put_string(skb, NFTA_TRACE_TABLE, chain->table->name))
> +			goto nla_put_failure;
> +		if (nla_put_string(skb, NFTA_TRACE_CHAIN, chain->name))
> +			goto nla_put_failure;
> +	}
> +
> +	if (rule && nla_put_be64(skb, NFTA_TRACE_RULE_HANDLE,
> +				 cpu_to_be64(rule->handle)))
> +		goto nla_put_failure;
> +
> +	if (pkt->in &&
> +	    nla_put_be32(skb, NFTA_TRACE_IIF, htonl(pkt->in->ifindex)))
> +		goto nla_put_failure;
> +	if (pkt->out &&
> +	    nla_put_be32(skb, NFTA_TRACE_OIF, htonl(pkt->out->ifindex)))
> +		goto nla_put_failure;
> +	if (pkt->skb->mark &&
> +	    nla_put_be32(skb, NFTA_TRACE_MARK, htonl(pkt->skb->mark)))
> +		goto nla_put_failure;
> +
> +	switch (type) {
> +	case NFT_TRACETYPE_POLICY:
> +	case NFT_TRACETYPE_RETURN:
> +	case NFT_TRACETYPE_RULE:
> +		if (nla_put_be32(skb, NFTA_TRACE_VERDICT, htonl(verdict)))
> +			goto nla_put_failure;
> +		break;
> +	case NFT_TRACETYPE_PACKET:
> +		if (!trace_notify_put_packet(skb, pkt))
> +			goto nla_put_failure;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	nlmsg_end(skb, nlh);
> +	nfnetlink_send(skb, pkt->net, 0, NFNLGRP_NFTABLES, 0, GFP_ATOMIC);
> +	return;
> +
> + nla_put_failure:
> +	WARN_ON_ONCE(1);
> +	kfree_skb(skb);
> +}
> +
>  static int nf_tables_dump_tables(struct sk_buff *skb,
>  				 struct netlink_callback *cb)
>  {
> diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
> index f3695a4..29a6ca9 100644
> --- a/net/netfilter/nf_tables_core.c
> +++ b/net/netfilter/nf_tables_core.c
> @@ -56,10 +56,15 @@ static void __nft_trace_packet(const struct nft_pktinfo *pkt,
>  
>  static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
>  				    const struct nft_chain *chain,
> -				    int rulenum, enum nft_trace type)
> +				    const struct nft_rule *rule,
> +				    int rulenum,
> +				    u32 verdict,
> +				    enum nft_trace_types type)
>  {
> -	if (unlikely(pkt->skb->nf_trace))
> +	if (unlikely(pkt->skb->nf_trace)) {
> +		nf_tables_trace_notify(pkt, chain, rule, verdict, type);
>  		__nft_trace_packet(pkt, chain, rulenum, type);
> +	}
>  }
>  
>  static void nft_cmp_fast_eval(const struct nft_expr *expr,
> @@ -151,7 +156,8 @@ next_rule:
>  			regs.verdict.code = NFT_CONTINUE;
>  			continue;
>  		case NFT_CONTINUE:
> -			nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
> +			nft_trace_packet(pkt, chain, rule, rulenum,
> +					 regs.verdict.code, NFT_TRACETYPE_RULE);
>  			continue;
>  		}
>  		break;
> @@ -161,7 +167,9 @@ next_rule:
>  	case NF_ACCEPT:
>  	case NF_DROP:
>  	case NF_QUEUE:
> -		nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
> +		nft_trace_packet(pkt, chain, rule, rulenum,
> +				 regs.verdict.code & NF_VERDICT_MASK,
> +				 NFT_TRACETYPE_RULE);
>  		return regs.verdict.code;
>  	}
>  
> @@ -174,7 +182,8 @@ next_rule:
>  		stackptr++;
>  		/* fall through */
>  	case NFT_GOTO:
> -		nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
> +		nft_trace_packet(pkt, chain, rule, rulenum,
> +				 regs.verdict.code, NFT_TRACETYPE_RULE);
>  
>  		chain = regs.verdict.chain;
>  		goto do_chain;
> @@ -182,7 +191,10 @@ next_rule:
>  		rulenum++;
>  		/* fall through */
>  	case NFT_RETURN:
> -		nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RETURN);
> +		if (stackptr)

Why this new branch?

> +			nft_trace_packet(pkt, chain, rule, rulenum,
> +					 regs.verdict.code,
> +					 NFT_TRACETYPE_RETURN);
>  		break;
>  	default:
>  		WARN_ON(1);


^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 2/6] netfilter: nf_tables: wrap tracing with a static key
  2015-11-24 10:02 ` [PATCH nf-next 2/6] netfilter: nf_tables: wrap tracing with a static key Florian Westphal
  2015-11-24 10:13   ` Patrick McHardy
@ 2015-11-24 10:19   ` Pablo Neira Ayuso
  1 sibling, 0 replies; 80+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-24 10:19 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On Tue, Nov 24, 2015 at 11:02:07AM +0100, Florian Westphal wrote:
> Only needed when meta nftrace rule(s) were added.
> 
> Signed-off-by: Florian Westphal <fw@strlen.de>
> ---
>  include/net/netfilter/nf_tables_core.h |  1 +
>  include/net/netfilter/nft_meta.h       |  3 +++
>  net/bridge/netfilter/nft_meta_bridge.c |  1 +
>  net/netfilter/nf_tables_core.c         | 20 +++++++++++++++-----
>  net/netfilter/nft_meta.c               | 15 +++++++++++++++
>  5 files changed, 35 insertions(+), 5 deletions(-)
> 
> diff --git a/include/net/netfilter/nf_tables_core.h b/include/net/netfilter/nf_tables_core.h
> index c6f400c..8ad6240 100644
> --- a/include/net/netfilter/nf_tables_core.h
> +++ b/include/net/netfilter/nf_tables_core.h
> @@ -48,6 +48,7 @@ struct nft_payload {
>  };
>  
>  extern const struct nft_expr_ops nft_payload_fast_ops;
> +extern struct static_key nft_trace_enabled;
>  
>  int nft_payload_module_init(void);
>  void nft_payload_module_exit(void);
> diff --git a/include/net/netfilter/nft_meta.h b/include/net/netfilter/nft_meta.h
> index 711887a..d27588c 100644
> --- a/include/net/netfilter/nft_meta.h
> +++ b/include/net/netfilter/nft_meta.h
> @@ -33,4 +33,7 @@ void nft_meta_set_eval(const struct nft_expr *expr,
>  		       struct nft_regs *regs,
>  		       const struct nft_pktinfo *pkt);
>  
> +void nft_meta_set_destroy(const struct nft_ctx *ctx,
> +			  const struct nft_expr *expr);
> +
>  #endif
> diff --git a/net/bridge/netfilter/nft_meta_bridge.c b/net/bridge/netfilter/nft_meta_bridge.c
> index a21269b..4b901d9 100644
> --- a/net/bridge/netfilter/nft_meta_bridge.c
> +++ b/net/bridge/netfilter/nft_meta_bridge.c
> @@ -84,6 +84,7 @@ static const struct nft_expr_ops nft_meta_bridge_set_ops = {
>  	.size		= NFT_EXPR_SIZE(sizeof(struct nft_meta)),
>  	.eval		= nft_meta_set_eval,
>  	.init		= nft_meta_set_init,
> +	.destroy	= nft_meta_set_destroy,
>  	.dump		= nft_meta_set_dump,
>  };
>  
> diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
> index 29a6ca9..dabf5ed 100644
> --- a/net/netfilter/nf_tables_core.c
> +++ b/net/netfilter/nf_tables_core.c
> @@ -16,6 +16,7 @@
>  #include <linux/skbuff.h>
>  #include <linux/netlink.h>
>  #include <linux/netfilter.h>
> +#include <linux/static_key.h>
>  #include <linux/netfilter/nfnetlink.h>
>  #include <linux/netfilter/nf_tables.h>
>  #include <net/netfilter/nf_tables_core.h>
> @@ -54,6 +55,9 @@ static void __nft_trace_packet(const struct nft_pktinfo *pkt,
>  		     rulenum);
>  }
>  
> +struct static_key nft_trace_enabled __read_mostly;
> +EXPORT_SYMBOL_GPL(nft_trace_enabled);
> +
>  static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
>  				    const struct nft_chain *chain,
>  				    const struct nft_rule *rule,
> @@ -61,7 +65,9 @@ static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
>  				    u32 verdict,
>  				    enum nft_trace_types type)
>  {
> -	if (unlikely(pkt->skb->nf_trace)) {
> +	if (static_key_false(&nft_trace_enabled)) {
> +		if (!pkt->skb->nf_trace)
> +			return;
>  		nf_tables_trace_notify(pkt, chain, rule, verdict, type);
>  		__nft_trace_packet(pkt, chain, rulenum, type);
>  	}
> @@ -138,7 +144,8 @@ next_rule:
>  		if (unlikely(rule->genmask & (1 << gencursor)))
>  			continue;
>  
> -		rulenum++;
> +		if (static_key_false(&nft_trace_enabled))
> +			rulenum++;

We can probably wrap this code to annotate rule number in a function?

>  
>  		nft_rule_for_each_expr(expr, last, rule) {
>  			if (expr->ops == &nft_cmp_fast_ops)
> @@ -178,7 +185,8 @@ next_rule:
>  		BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE);
>  		jumpstack[stackptr].chain = chain;
>  		jumpstack[stackptr].rule  = rule;
> -		jumpstack[stackptr].rulenum = rulenum;
> +		if (static_key_false(&nft_trace_enabled))
> +			jumpstack[stackptr].rulenum = rulenum;
>  		stackptr++;
>  		/* fall through */
>  	case NFT_GOTO:
> @@ -188,7 +196,8 @@ next_rule:
>  		chain = regs.verdict.chain;
>  		goto do_chain;
>  	case NFT_CONTINUE:
> -		rulenum++;
> +		if (static_key_false(&nft_trace_enabled))
> +			rulenum++;

This happens again here.

>  		/* fall through */
>  	case NFT_RETURN:
>  		if (stackptr)
> @@ -204,7 +213,8 @@ next_rule:
>  		stackptr--;
>  		chain = jumpstack[stackptr].chain;
>  		rule  = jumpstack[stackptr].rule;
> -		rulenum = jumpstack[stackptr].rulenum;
> +		if (static_key_false(&nft_trace_enabled))
> +			rulenum = jumpstack[stackptr].rulenum;

This one is very similar to the one above.

>  		goto next_rule;
>  	}
>  
> diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
> index e94526a..c2a60ac 100644
> --- a/net/netfilter/nft_meta.c
> +++ b/net/netfilter/nft_meta.c
> @@ -18,10 +18,12 @@
>  #include <linux/ip.h>
>  #include <linux/ipv6.h>
>  #include <linux/smp.h>
> +#include <linux/static_key.h>
>  #include <net/dst.h>
>  #include <net/sock.h>
>  #include <net/tcp_states.h> /* for TCP_TIME_WAIT */
>  #include <net/netfilter/nf_tables.h>
> +#include <net/netfilter/nf_tables_core.h>
>  #include <net/netfilter/nft_meta.h>
>  
>  void nft_meta_get_eval(const struct nft_expr *expr,
> @@ -300,6 +302,9 @@ int nft_meta_set_init(const struct nft_ctx *ctx,
>  	if (err < 0)
>  		return err;
>  
> +	if (priv->key == NFT_META_NFTRACE)
> +		static_key_slow_inc(&nft_trace_enabled);
> +
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(nft_meta_set_init);
> @@ -337,6 +342,15 @@ nla_put_failure:
>  }
>  EXPORT_SYMBOL_GPL(nft_meta_set_dump);
>  
> +void nft_meta_set_destroy(const struct nft_ctx *ctx,
> +			  const struct nft_expr *expr)
> +{
> +	const struct nft_meta *priv = nft_expr_priv(expr);
> +
> +	if (priv->key == NFT_META_NFTRACE)
> +		static_key_slow_dec(&nft_trace_enabled);
> +}
> +
>  static struct nft_expr_type nft_meta_type;
>  static const struct nft_expr_ops nft_meta_get_ops = {
>  	.type		= &nft_meta_type,
> @@ -351,6 +365,7 @@ static const struct nft_expr_ops nft_meta_set_ops = {
>  	.size		= NFT_EXPR_SIZE(sizeof(struct nft_meta)),
>  	.eval		= nft_meta_set_eval,
>  	.init		= nft_meta_set_init,
> +	.destroy	= nft_meta_set_destroy,
>  	.dump		= nft_meta_set_dump,
>  };
>  
> -- 
> 2.4.10
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 2/6] netfilter: nf_tables: wrap tracing with a static key
  2015-11-24 10:13   ` Patrick McHardy
@ 2015-11-24 10:21     ` Florian Westphal
  2015-11-24 10:28       ` Patrick McHardy
  0 siblings, 1 reply; 80+ messages in thread
From: Florian Westphal @ 2015-11-24 10:21 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, netfilter-devel

Patrick McHardy <kaber@trash.net> wrote:
> On 24.11, Florian Westphal wrote:
> > diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
> > index 29a6ca9..dabf5ed 100644
> > --- a/net/netfilter/nf_tables_core.c
> > +++ b/net/netfilter/nf_tables_core.c
> > @@ -138,7 +144,8 @@ next_rule:
> >  		if (unlikely(rule->genmask & (1 << gencursor)))
> >  			continue;
> >  
> > -		rulenum++;
> > +		if (static_key_false(&nft_trace_enabled))
> > +			rulenum++;
> 
> This API is deprecated, see Documentation/static-keys.txt.

Oh, thats great.  static_branch_unlikely() is a much better name.

I'll update this locally and send a v2 later (I want to give others
time to provide feedback as well).

> I'm also wondering if this introduces a race condition on architectures
> that don't support jump labels. static_key_slow_inc() simply increases
> the ->enabled counter without further synchronization, so this might
> happen while we're executing this function and some of the increments
> might be skipped.

Hmm, adding synchronization for this is braindead.
The new trace infrastructure doesn't need this rulenum, I only kept it
since thats what Pablo asked me to do.

So we have 3 choices:
- ignore this
- don't use static key here
- kill the old nf_log_packet trace part after all

I find it sad that we have to keep this rule counting around :-/

If there are no further comments I'll remove the static key and do
the rule counting unconditinally.

Thanks Patrick.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-24 10:02 ` [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure Florian Westphal
  2015-11-24 10:17   ` Pablo Neira Ayuso
@ 2015-11-24 10:22   ` Pablo Neira Ayuso
  2015-11-24 10:28     ` Florian Westphal
  2015-11-24 10:44   ` Patrick McHardy
  2015-11-25  0:55   ` Patrick McHardy
  3 siblings, 1 reply; 80+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-24 10:22 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On Tue, Nov 24, 2015 at 11:02:06AM +0100, Florian Westphal wrote:
> +void nf_tables_trace_notify(const struct nft_pktinfo *pkt,
> +			    const struct nft_chain *chain,
> +			    const struct nft_rule *rule,
> +			    u32 verdict,
> +			    enum nft_trace_types type)
> +{
> +	struct nfgenmsg *nfmsg;
> +	struct nlmsghdr *nlh;
> +	struct sk_buff *skb;
> +	unsigned int size;
> +	int event = (NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_TRACE;
> +
> +	if (!nfnetlink_has_listeners(pkt->net, NFNLGRP_NFTABLES))
> +		return;
> +
> +	/* Unlike other notifiers we need GFP_ATOMIC so use actual size
> +	 * needed instead of NLMSG_GOODSIZE.
> +	 */
> +	size = nlmsg_total_size(sizeof(struct nfgenmsg))
> +		+ nla_total_size(sizeof(__be32))	/* trace type */
> +		+ nla_total_size(NFT_TABLE_MAXNAMELEN)
> +		+ nla_total_size(NFT_CHAIN_MAXNAMELEN)
> +		+ nla_total_size(sizeof(u32))	/* iif */
> +		+ nla_total_size(sizeof(u32))	/* oif */
> +		+ nla_total_size(sizeof(u32))	/* id */
> +		+ nla_total_size(sizeof(u32))	/* mark */
> +		+ nla_total_size(sizeof(u32))	/* verdict */
> +		+ nla_total_size(sizeof(__be64)); /* rule handle */
> +
> +	switch (type) {
> +	case NFT_TRACETYPE_PACKET:
> +		size += nla_total_size(NFT_TRACETYPE_NETWORK_HSIZE)
> +			+ nla_total_size(NFT_TRACETYPE_TRANSPORT_HSIZE)
> +			+ nla_total_size(NFT_TRACETYPE_LL_HSIZE)
> +			+ nla_total_size(sizeof(__be16)) /* vlan tag */
> +			+ nla_total_size(sizeof(__be16)) /* device type */
> +			+ nla_total_size(sizeof(__u8));  /* transport prot */
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	skb = nlmsg_new(size, GFP_ATOMIC);
> +	if (!skb)
> +		return;
> +
> +	nlh = nlmsg_put(skb, 0, 0, event, sizeof(struct nfgenmsg), 0);
> +	if (!nlh)
> +		goto nla_put_failure;
> +
> +	nfmsg = nlmsg_data(nlh);
> +	nfmsg->nfgen_family	= pkt->pf;
> +	nfmsg->version		= NFNETLINK_V0;
> +	nfmsg->res_id		= htons(pkt->net->nft.base_seq & 0xffff);
> +
> +	if (nla_put_be32(skb, NFTA_TRACE_TYPE, htonl(type)))
> +		goto nla_put_failure;
> +
> +	if (nla_put_be32(skb, NFTA_TRACE_ID, htonl(hash32_ptr(pkt->skb))))
> +		goto nla_put_failure;
> +
> +	if (chain) {
> +		if (nla_put_string(skb, NFTA_TRACE_TABLE, chain->table->name))
> +			goto nla_put_failure;
> +		if (nla_put_string(skb, NFTA_TRACE_CHAIN, chain->name))
> +			goto nla_put_failure;
> +	}
> +
> +	if (rule && nla_put_be64(skb, NFTA_TRACE_RULE_HANDLE,
> +				 cpu_to_be64(rule->handle)))
> +		goto nla_put_failure;
> +
> +	if (pkt->in &&
> +	    nla_put_be32(skb, NFTA_TRACE_IIF, htonl(pkt->in->ifindex)))
> +		goto nla_put_failure;
> +	if (pkt->out &&
> +	    nla_put_be32(skb, NFTA_TRACE_OIF, htonl(pkt->out->ifindex)))
> +		goto nla_put_failure;
> +	if (pkt->skb->mark &&
> +	    nla_put_be32(skb, NFTA_TRACE_MARK, htonl(pkt->skb->mark)))
> +		goto nla_put_failure;
> +
> +	switch (type) {
> +	case NFT_TRACETYPE_POLICY:
> +	case NFT_TRACETYPE_RETURN:
> +	case NFT_TRACETYPE_RULE:
> +		if (nla_put_be32(skb, NFTA_TRACE_VERDICT, htonl(verdict)))
> +			goto nla_put_failure;
> +		break;
> +	case NFT_TRACETYPE_PACKET:
> +		if (!trace_notify_put_packet(skb, pkt))
> +			goto nla_put_failure;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	nlmsg_end(skb, nlh);
> +	nfnetlink_send(skb, pkt->net, 0, NFNLGRP_NFTABLES, 0, GFP_ATOMIC);

BTW, do we really want to use the default NFNLGRP_NFTABLES group?

multicast group provide a simple way for filtering out what you don't
need from kernelspace. And you can still subscribe both groups
NFNLGRP_NFTABLES and NFNLGRP_NFTABLES_TRACE.

I'm telling this when thinking of nft-sync. Why should it be receiving
this spamming tracing events when it only cares about ruleset updates?

And specifically netlink bandwidth is limited from packet context.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-24 10:02 ` [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present Florian Westphal
  2015-11-24 10:16   ` Patrick McHardy
@ 2015-11-24 10:24   ` Pablo Neira Ayuso
  2015-11-24 10:31     ` Florian Westphal
  2015-11-25  0:57   ` Patrick McHardy
  2 siblings, 1 reply; 80+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-24 10:24 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On Tue, Nov 24, 2015 at 11:02:08AM +0100, Florian Westphal wrote:
> No need to clutter nflog/dmesg ring buffer with the old tracing output
> when the 'native' nfnetlink interface is used.
> 
> Signed-off-by: Florian Westphal <fw@strlen.de>
> ---
>  net/netfilter/nf_tables_core.c | 9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)
> 
> diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
> index dabf5ed..69bdd9a 100644
> --- a/net/netfilter/nf_tables_core.c
> +++ b/net/netfilter/nf_tables_core.c
> @@ -55,6 +55,7 @@ static void __nft_trace_packet(const struct nft_pktinfo *pkt,
>  		     rulenum);
>  }
>  
> +static bool prefer_native_trace __read_mostly;
>  struct static_key nft_trace_enabled __read_mostly;
>  EXPORT_SYMBOL_GPL(nft_trace_enabled);
>  
> @@ -69,7 +70,13 @@ static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
>  		if (!pkt->skb->nf_trace)
>  			return;
>  		nf_tables_trace_notify(pkt, chain, rule, verdict, type);
> -		__nft_trace_packet(pkt, chain, rulenum, type);
> +		if (prefer_native_trace)
> +			return;
> +
> +		if (nfnetlink_has_listeners(pkt->net, NFNLGRP_NFTABLES))
> +			prefer_native_trace = true;
> +		else
> +			__nft_trace_packet(pkt, chain, rulenum, type);

For this very specific case I prefer a sysctl that we can remove
moving forward, then remove this code and default to the new tracing
infrastructure once we have indications that adoption of this new
tracing infrastructure has been massively adopted instead of the
existing one.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nftables 6/6] src: add trace support to nft monitor mode
  2015-11-24 10:02 ` [PATCH nftables 6/6] src: add trace support to nft monitor mode Florian Westphal
@ 2015-11-24 10:25   ` Patrick McHardy
  2015-11-24 10:48     ` Florian Westphal
  2015-11-24 10:53     ` Pablo Neira Ayuso
  0 siblings, 2 replies; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 10:25 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On 24.11, Florian Westphal wrote:
> nft monitor [ trace ]
> 
> ... can now display nftables nftrace debug information.
> 
> $ nft rule bridge raw prerouting add tcp dport 22 limit rate 1/second meta nftrace set 1
> $ nft monitor trace
> trace id 834dd100 bridge packet src 5e:95:99:72:ea:c5 dst 52:54:40:a2:3f:a6 src 192.168.7.1 dst 192.168.7.11 len 88 ttl 64 id 2719 protocol 6 sport 3628 dport 22 iif eth0
> trace id 834dd100 bridge raw prerouting rule verdict continue iif eth0
> trace id 834dd100 rule tcp dport ssh limit rate 1/second nftrace set 1
> trace id 834dd100 bridge raw prerouting policy verdict accept iif eth0
> trace id 834dd100 ip filter input rule verdict jump iif br0
> trace id 834dd100 rule ip saddr . tcp dport vmap { }
> trace id 834dd100 ip filter test rule verdict accept iif br0
> trace id 834dd100 rule accept

I like this *a lot*. No need for external tools and a much more readable
output than using any of the other logging mechanisms. Nice work!

> +static void trace_print_if(const struct nftnl_trace *nlt, uint16_t attr, const char *str)
> +{
> +	char __name[IFNAMSIZ];
> +	const char *ifname;
> +
> +        if (!nftnl_trace_is_set(nlt, attr))
> +		return;
> +
> +	ifname = nft_if_indextoname(nftnl_trace_get_u32(nlt, attr), __name);
> +	if (ifname)
> +		printf(" %s %s", str, ifname);
> +	else
> +		printf(" %s %d", str, nftnl_trace_get_u32(nlt, attr));
> +}

A lot of the other trace attributes are not used so far. I'm wondering if
you intend to add special print functions for them as well.

An alternative would be to use our internal datatypes, IOW parse the
attributes, associate the values with an internal type and use the regular
printing functions. The benefit would be fully consistent output, also
with respect to output options like numerical output.

> +static int do_command_monitor(struct netlink_ctx *ctx, struct cmd *cmd)
> +{
> +	struct table *t;
> +	struct set *s;
> +	struct netlink_mon_handler monhandler;
> +
> +	monhandler.cache_needed = need_cache(cmd);
>  	if (monhandler.cache_needed) {
> +		struct rule *rule, *nrule;
> +		struct chain *chain;
> +		int ret;
> +
>  		list_for_each_entry(t, &table_list, list) {
>  			list_for_each_entry(s, &t->sets, list)
>  				s->init = set_expr_alloc(&cmd->location);
> +
> +			if (!(cmd->monitor->flags & (1 << NFT_MSG_TRACE)))
> +				continue;
> +
> +			/* When tracing we'd like to translate the rule handle
> +			 * we receive in the trace messages to the actual rule
> +			 * struct to print that out.  Populate rule cache now.
> +			 */

Tracing might be a long running operation. The cache can go out of sync, might
be better to do a lookup on demand.

Right now the caching infrastrucure has quite a lot of problems and I'd prefer
to get them fixed before we base new things on it.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-24 10:17   ` Pablo Neira Ayuso
@ 2015-11-24 10:27     ` Florian Westphal
  2015-11-24 10:30       ` Pablo Neira Ayuso
  0 siblings, 1 reply; 80+ messages in thread
From: Florian Westphal @ 2015-11-24 10:27 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: Florian Westphal, netfilter-devel

Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> On Tue, Nov 24, 2015 at 11:02:06AM +0100, Florian Westphal wrote:
> > nft monitor mode can then decode and display this trace data.
> > 
> > Parts of LL/Network/Transport headers are provided as separate
> > attributes.
> > 
> > Otherwise, printing IP address data becomes virtually impossible
> > for userspace since in the case of the netdev family we really don't
> > want userspace to have to know all the possible link layer types
> > and/or sizes just to display/print an ip address.
> > 
> > We also don't want userspace to have to follow ipv6 header chains
> > to get the s/dport info, the kernel already did this work so just
> > follow suit.
> > 
> > Signed-off-by: Florian Westphal <fw@strlen.de>
> > ---
> >  include/net/netfilter/nf_tables.h        |   6 +
> > +static bool trace_notify_put_data(struct sk_buff *nlskb, u16 type,
> > +				  const struct sk_buff *skb,
> > +				  int off, unsigned int plen)
> 
> Minor nitpick: Probably you can rename this to _fill_*_info for
> consistency with other nf_tables netlink code.

Sure, will do.

> Do you think we can place all this new netlink code in
> net/netfilter/nf_tables_trace.c ? So we leave in the core file only
> our classifier engine.
> 
> I like the attribute definition rename in nf_tables.h, but this code
> we can probably place it away from here.

Ok, I'll see if this is doable without exporting half a dozen of
symbols.

> >  static int nf_tables_table_notify(const struct nft_ctx *ctx, int event)
> >  	case NFT_RETURN:
> > -		nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RETURN);
> > +		if (stackptr)
> 
> Why this new branch?

Right, I should move it to extra patch.  I think its buggy without the
extra if (stackptr) test.

If stackptr is 0, then we're returning from a base chain, i.e.
the policy is evaluated and we have another trace for that.

For old code its not really imporant if rulenum counter is wrong/off,
but for the new infra its important that the *rule ptr is valid.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-24 10:22   ` Pablo Neira Ayuso
@ 2015-11-24 10:28     ` Florian Westphal
  2015-11-24 10:33       ` Patrick McHardy
  2015-11-24 10:36       ` Pablo Neira Ayuso
  0 siblings, 2 replies; 80+ messages in thread
From: Florian Westphal @ 2015-11-24 10:28 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: Florian Westphal, netfilter-devel

Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> BTW, do we really want to use the default NFNLGRP_NFTABLES group?
> 
> multicast group provide a simple way for filtering out what you don't
> need from kernelspace. And you can still subscribe both groups
> NFNLGRP_NFTABLES and NFNLGRP_NFTABLES_TRACE.
> 
> I'm telling this when thinking of nft-sync. Why should it be receiving
> this spamming tracing events when it only cares about ruleset updates?

I can add a new group but nftables will need to subscribe to both
in trace mode since we need to see new rules...

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 2/6] netfilter: nf_tables: wrap tracing with a static key
  2015-11-24 10:21     ` Florian Westphal
@ 2015-11-24 10:28       ` Patrick McHardy
  0 siblings, 0 replies; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 10:28 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On 24.11, Florian Westphal wrote:
> Patrick McHardy <kaber@trash.net> wrote:
> 
> > I'm also wondering if this introduces a race condition on architectures
> > that don't support jump labels. static_key_slow_inc() simply increases
> > the ->enabled counter without further synchronization, so this might
> > happen while we're executing this function and some of the increments
> > might be skipped.
> 
> Hmm, adding synchronization for this is braindead.
> The new trace infrastructure doesn't need this rulenum, I only kept it
> since thats what Pablo asked me to do.
> 
> So we have 3 choices:
> - ignore this
> - don't use static key here
> - kill the old nf_log_packet trace part after all
> 
> I find it sad that we have to keep this rule counting around :-/
> 
> If there are no further comments I'll remove the static key and do
> the rule counting unconditinally.

I wouldn't mind killing the old tracing off, but I think the main reason why
we added it was for ipt compat. So probably not possible at this point.

I agree that having the rule counting is not particulary nice, but I don't
see any other way right now than to do it unconditionally.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-24 10:27     ` Florian Westphal
@ 2015-11-24 10:30       ` Pablo Neira Ayuso
  2015-11-24 10:35         ` Patrick McHardy
  2015-11-24 11:11         ` Florian Westphal
  0 siblings, 2 replies; 80+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-24 10:30 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On Tue, Nov 24, 2015 at 11:27:07AM +0100, Florian Westphal wrote:
> Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > Do you think we can place all this new netlink code in
> > net/netfilter/nf_tables_trace.c ? So we leave in the core file only
> > our classifier engine.
> > 
> > I like the attribute definition rename in nf_tables.h, but this code
> > we can probably place it away from here.
> 
> Ok, I'll see if this is doable without exporting half a dozen of
> symbols.

If you place this in this core, we should need to export any symbol.

nf_tables-objs += nf_tables_core.o nf_tables_api.o nf_tables_trace.o

And I would expect probably only functions to enable/disabling tracing
and to notify the trace via netlink.

Let me know, thanks.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-24 10:24   ` Pablo Neira Ayuso
@ 2015-11-24 10:31     ` Florian Westphal
  2015-11-24 10:39       ` Pablo Neira Ayuso
  0 siblings, 1 reply; 80+ messages in thread
From: Florian Westphal @ 2015-11-24 10:31 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: Florian Westphal, netfilter-devel

Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
> > index dabf5ed..69bdd9a 100644
> > --- a/net/netfilter/nf_tables_core.c
> > +++ b/net/netfilter/nf_tables_core.c
> > @@ -55,6 +55,7 @@ static void __nft_trace_packet(const struct nft_pktinfo *pkt,
> >  		     rulenum);
> >  }
> >  
> > +static bool prefer_native_trace __read_mostly;
> >  struct static_key nft_trace_enabled __read_mostly;
> >  EXPORT_SYMBOL_GPL(nft_trace_enabled);
> >  
> > @@ -69,7 +70,13 @@ static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
> >  		if (!pkt->skb->nf_trace)
> >  			return;
> >  		nf_tables_trace_notify(pkt, chain, rule, verdict, type);
> > -		__nft_trace_packet(pkt, chain, rulenum, type);
> > +		if (prefer_native_trace)
> > +			return;
> > +
> > +		if (nfnetlink_has_listeners(pkt->net, NFNLGRP_NFTABLES))
> > +			prefer_native_trace = true;
> > +		else
> > +			__nft_trace_packet(pkt, chain, rulenum, type);
> 
> For this very specific case I prefer a sysctl that we can remove
> moving forward, then remove this code and default to the new tracing
> infrastructure once we have indications that adoption of this new
> tracing infrastructure has been massively adopted instead of the
> existing one.

So you're saying

sysctl nft_old_trace = 1;

and then do

nf_tables_trace_notify(..)
if (nft_old_trace)
	__nft_trace_packet();

?

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-24 10:28     ` Florian Westphal
@ 2015-11-24 10:33       ` Patrick McHardy
  2015-11-24 10:44         ` Pablo Neira Ayuso
  2015-11-24 10:36       ` Pablo Neira Ayuso
  1 sibling, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 10:33 UTC (permalink / raw)
  To: Florian Westphal; +Cc: Pablo Neira Ayuso, netfilter-devel

On 24.11, Florian Westphal wrote:
> Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > BTW, do we really want to use the default NFNLGRP_NFTABLES group?
> > 
> > multicast group provide a simple way for filtering out what you don't
> > need from kernelspace. And you can still subscribe both groups
> > NFNLGRP_NFTABLES and NFNLGRP_NFTABLES_TRACE.
> > 
> > I'm telling this when thinking of nft-sync. Why should it be receiving
> > this spamming tracing events when it only cares about ruleset updates?
> 
> I can add a new group but nftables will need to subscribe to both
> in trace mode since we need to see new rules...

I agree with Pablo. Under high load this has the potential to decrease
reliability of rule notifications a lot for any interested listener. Since
tracing is a debugging tool I don't think we should do that.

BTW and completely unrelated to the netlink group: I think it would be
nicer to have a "trace" keyword instead of "nftrace set 1" in the nft
frontend.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-24 10:30       ` Pablo Neira Ayuso
@ 2015-11-24 10:35         ` Patrick McHardy
  2015-11-24 11:11         ` Florian Westphal
  1 sibling, 0 replies; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 10:35 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: Florian Westphal, netfilter-devel

On 24.11, Pablo Neira Ayuso wrote:
> On Tue, Nov 24, 2015 at 11:27:07AM +0100, Florian Westphal wrote:
> > Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > > Do you think we can place all this new netlink code in
> > > net/netfilter/nf_tables_trace.c ? So we leave in the core file only
> > > our classifier engine.
> > > 
> > > I like the attribute definition rename in nf_tables.h, but this code
> > > we can probably place it away from here.
> > 
> > Ok, I'll see if this is doable without exporting half a dozen of
> > symbols.
> 
> If you place this in this core, we should need to export any symbol.
> 
> nf_tables-objs += nf_tables_core.o nf_tables_api.o nf_tables_trace.o
> 
> And I would expect probably only functions to enable/disabling tracing
> and to notify the trace via netlink.

I think we can also avoid the enable/disable exports. Having meta optional
doesn't make too much sense to me, it provides very fundamental features
like interface matching which I don't think anyone can reasonably disable.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-24 10:28     ` Florian Westphal
  2015-11-24 10:33       ` Patrick McHardy
@ 2015-11-24 10:36       ` Pablo Neira Ayuso
  1 sibling, 0 replies; 80+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-24 10:36 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On Tue, Nov 24, 2015 at 11:28:41AM +0100, Florian Westphal wrote:
> Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > BTW, do we really want to use the default NFNLGRP_NFTABLES group?
> > 
> > multicast group provide a simple way for filtering out what you don't
> > need from kernelspace. And you can still subscribe both groups
> > NFNLGRP_NFTABLES and NFNLGRP_NFTABLES_TRACE.
> > 
> > I'm telling this when thinking of nft-sync. Why should it be receiving
> > this spamming tracing events when it only cares about ruleset updates?
> 
> I can add a new group but nftables will need to subscribe to both
> in trace mode since we need to see new rules...

I'm talking about applications that may not need to subscribe both,
eg. nft-sync will only need to subscribe to rule updates, he doesn't
care about traces.

I think nft should have the ability to subscribe only rule updates
only as well.

You can subscribe as many groups at the same time in netlink as you want.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-24 10:31     ` Florian Westphal
@ 2015-11-24 10:39       ` Pablo Neira Ayuso
  2015-11-24 10:53         ` Patrick McHardy
  0 siblings, 1 reply; 80+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-24 10:39 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On Tue, Nov 24, 2015 at 11:31:05AM +0100, Florian Westphal wrote:
> Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > > diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
> > > index dabf5ed..69bdd9a 100644
> > > --- a/net/netfilter/nf_tables_core.c
> > > +++ b/net/netfilter/nf_tables_core.c
> > > @@ -55,6 +55,7 @@ static void __nft_trace_packet(const struct nft_pktinfo *pkt,
> > >  		     rulenum);
> > >  }
> > >  
> > > +static bool prefer_native_trace __read_mostly;
> > >  struct static_key nft_trace_enabled __read_mostly;
> > >  EXPORT_SYMBOL_GPL(nft_trace_enabled);
> > >  
> > > @@ -69,7 +70,13 @@ static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
> > >  		if (!pkt->skb->nf_trace)
> > >  			return;
> > >  		nf_tables_trace_notify(pkt, chain, rule, verdict, type);
> > > -		__nft_trace_packet(pkt, chain, rulenum, type);
> > > +		if (prefer_native_trace)
> > > +			return;
> > > +
> > > +		if (nfnetlink_has_listeners(pkt->net, NFNLGRP_NFTABLES))
> > > +			prefer_native_trace = true;
> > > +		else
> > > +			__nft_trace_packet(pkt, chain, rulenum, type);
> > 
> > For this very specific case I prefer a sysctl that we can remove
> > moving forward, then remove this code and default to the new tracing
> > infrastructure once we have indications that adoption of this new
> > tracing infrastructure has been massively adopted instead of the
> > existing one.
> 
> So you're saying
> 
> sysctl nft_old_trace = 1;
> 
> and then do
> 
> nf_tables_trace_notify(..)
> if (nft_old_trace)
> 	__nft_trace_packet();
> 
> ?

What I'm trying to avoid is the initial race that we'll have.

I mean, with this approach the user will likely enable the tracing
from the rule, then will launch nft trace. In that case, he will be
getting traces from the old way for a little while until you get one
process subscribed to this.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-24 10:33       ` Patrick McHardy
@ 2015-11-24 10:44         ` Pablo Neira Ayuso
  2015-11-24 10:45           ` Pablo Neira Ayuso
  0 siblings, 1 reply; 80+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-24 10:44 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, netfilter-devel

On Tue, Nov 24, 2015 at 10:33:49AM +0000, Patrick McHardy wrote:
> BTW and completely unrelated to the netlink group: I think it would be
> nicer to have a "trace" keyword instead of "nftrace set 1" in the nft
> frontend.

I like the idea of having this "trace" statement.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-24 10:02 ` [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure Florian Westphal
  2015-11-24 10:17   ` Pablo Neira Ayuso
  2015-11-24 10:22   ` Pablo Neira Ayuso
@ 2015-11-24 10:44   ` Patrick McHardy
  2015-11-25  0:55   ` Patrick McHardy
  3 siblings, 0 replies; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 10:44 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On 24.11, Florian Westphal wrote:
> +void nf_tables_trace_notify(const struct nft_pktinfo *pkt,
> +			    const struct nft_chain *chain,
> +			    const struct nft_rule *rule,
> +			    u32 verdict,
> +			    enum nft_trace_types type)
> +{
> +	struct nfgenmsg *nfmsg;
> +	struct nlmsghdr *nlh;
> +	struct sk_buff *skb;
> +	unsigned int size;
> +	int event = (NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_TRACE;
> +
> +	if (!nfnetlink_has_listeners(pkt->net, NFNLGRP_NFTABLES))
> +		return;
> +
> +	/* Unlike other notifiers we need GFP_ATOMIC so use actual size
> +	 * needed instead of NLMSG_GOODSIZE.
> +	 */
> +	size = nlmsg_total_size(sizeof(struct nfgenmsg))
> +		+ nla_total_size(sizeof(__be32))	/* trace type */
> +		+ nla_total_size(NFT_TABLE_MAXNAMELEN)
> +		+ nla_total_size(NFT_CHAIN_MAXNAMELEN)
> +		+ nla_total_size(sizeof(u32))	/* iif */
> +		+ nla_total_size(sizeof(u32))	/* oif */
> +		+ nla_total_size(sizeof(u32))	/* id */
> +		+ nla_total_size(sizeof(u32))	/* mark */
> +		+ nla_total_size(sizeof(u32))	/* verdict */
> +		+ nla_total_size(sizeof(__be64)); /* rule handle */

Minor style issue: we got rid of putting the operator on the next line
everywhere. Let's keep this consistent.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-24 10:44         ` Pablo Neira Ayuso
@ 2015-11-24 10:45           ` Pablo Neira Ayuso
  2015-11-24 10:47             ` Patrick McHardy
  0 siblings, 1 reply; 80+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-24 10:45 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, netfilter-devel

On Tue, Nov 24, 2015 at 11:44:04AM +0100, Pablo Neira Ayuso wrote:
> On Tue, Nov 24, 2015 at 10:33:49AM +0000, Patrick McHardy wrote:
> > BTW and completely unrelated to the netlink group: I think it would be
> > nicer to have a "trace" keyword instead of "nftrace set 1" in the nft
> > frontend.
> 
> I like the idea of having this "trace" statement.

Or you mean only "trace" keyword from the parser, not a statement,
right?

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-24 10:45           ` Pablo Neira Ayuso
@ 2015-11-24 10:47             ` Patrick McHardy
  0 siblings, 0 replies; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 10:47 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: Florian Westphal, netfilter-devel

On 24.11, Pablo Neira Ayuso wrote:
> On Tue, Nov 24, 2015 at 11:44:04AM +0100, Pablo Neira Ayuso wrote:
> > On Tue, Nov 24, 2015 at 10:33:49AM +0000, Patrick McHardy wrote:
> > > BTW and completely unrelated to the netlink group: I think it would be
> > > nicer to have a "trace" keyword instead of "nftrace set 1" in the nft
> > > frontend.
> > 
> > I like the idea of having this "trace" statement.
> 
> Or you mean only "trace" keyword from the parser, not a statement,
> right?

Probably, we can internally translate it to "meta set trace = 1" in the
parser and translate it back during output.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nftables 6/6] src: add trace support to nft monitor mode
  2015-11-24 10:25   ` Patrick McHardy
@ 2015-11-24 10:48     ` Florian Westphal
  2015-11-24 10:58       ` Patrick McHardy
  2015-11-24 10:53     ` Pablo Neira Ayuso
  1 sibling, 1 reply; 80+ messages in thread
From: Florian Westphal @ 2015-11-24 10:48 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, netfilter-devel

Patrick McHardy <kaber@trash.net> wrote:
> > +static void trace_print_if(const struct nftnl_trace *nlt, uint16_t attr, const char *str)
> > +{
> > +	char __name[IFNAMSIZ];
> > +	const char *ifname;
> > +
> > +        if (!nftnl_trace_is_set(nlt, attr))
> > +		return;
> > +
> > +	ifname = nft_if_indextoname(nftnl_trace_get_u32(nlt, attr), __name);
> > +	if (ifname)
> > +		printf(" %s %s", str, ifname);
> > +	else
> > +		printf(" %s %d", str, nftnl_trace_get_u32(nlt, attr));
> > +}
> 
> A lot of the other trace attributes are not used so far. I'm wondering if
> you intend to add special print functions for them as well.

All of the trace attributes are used, most of the use is limited to
libnftnl though.

Wrt. to iif/oif, I do the printing for it in nftables to take advantage
of the iif/oif idx<->name cache.

I would have preferred to just stick it into libnftnl like most of the
other rest BUT then you either have the additional name translation overhead
or just the index number...

> An alternative would be to use our internal datatypes, IOW parse the
> attributes, associate the values with an internal type and use the regular
> printing functions. The benefit would be fully consistent output, also
> with respect to output options like numerical output.

Yes, right now virtually all of the printing is in libnftnl
(called from nftables via nftnl_trace_fprintf() ).

> > +static int do_command_monitor(struct netlink_ctx *ctx, struct cmd *cmd)
> > +{
> > +	struct table *t;
> > +	struct set *s;
> > +	struct netlink_mon_handler monhandler;
> > +
> > +	monhandler.cache_needed = need_cache(cmd);
> >  	if (monhandler.cache_needed) {
> > +		struct rule *rule, *nrule;
> > +		struct chain *chain;
> > +		int ret;
> > +
> >  		list_for_each_entry(t, &table_list, list) {
> >  			list_for_each_entry(s, &t->sets, list)
> >  				s->init = set_expr_alloc(&cmd->location);
> > +
> > +			if (!(cmd->monitor->flags & (1 << NFT_MSG_TRACE)))
> > +				continue;
> > +
> > +			/* When tracing we'd like to translate the rule handle
> > +			 * we receive in the trace messages to the actual rule
> > +			 * struct to print that out.  Populate rule cache now.
> > +			 */
> 
> Tracing might be a long running operation. The cache can go out of sync, might
> be better to do a lookup on demand.

Hmm, okay.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-24 10:39       ` Pablo Neira Ayuso
@ 2015-11-24 10:53         ` Patrick McHardy
  2015-11-24 11:10           ` Florian Westphal
  0 siblings, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 10:53 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: Florian Westphal, netfilter-devel

On 24.11, Pablo Neira Ayuso wrote:
> On Tue, Nov 24, 2015 at 11:31:05AM +0100, Florian Westphal wrote:
> > > > +		if (nfnetlink_has_listeners(pkt->net, NFNLGRP_NFTABLES))
> > > > +			prefer_native_trace = true;
> > > > +		else
> > > > +			__nft_trace_packet(pkt, chain, rulenum, type);
> > > 
> > > For this very specific case I prefer a sysctl that we can remove
> > > moving forward, then remove this code and default to the new tracing
> > > infrastructure once we have indications that adoption of this new
> > > tracing infrastructure has been massively adopted instead of the
> > > existing one.
> > 
> > So you're saying
> > 
> > sysctl nft_old_trace = 1;
> > 
> > and then do
> > 
> > nf_tables_trace_notify(..)
> > if (nft_old_trace)
> > 	__nft_trace_packet();
> > 
> > ?
> 
> What I'm trying to avoid is the initial race that we'll have.
> 
> I mean, with this approach the user will likely enable the tracing
> from the rule, then will launch nft trace. In that case, he will be
> getting traces from the old way for a little while until you get one
> process subscribed to this.

On more thing to consider it interaction with other netfilter subsystems.

F.i. I think it would be very useful to have per connection tracing, so
we'd store a flag in the nfct and transfer it to every packet. This would
make them show up in the nft ruleset, but what about tracing in specific
points of conntrack/NAT itself? Can we send them to the same group and
make them integrate with ruleset tracing?

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nftables 6/6] src: add trace support to nft monitor mode
  2015-11-24 10:25   ` Patrick McHardy
  2015-11-24 10:48     ` Florian Westphal
@ 2015-11-24 10:53     ` Pablo Neira Ayuso
  2015-11-24 11:04       ` Patrick McHardy
  1 sibling, 1 reply; 80+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-24 10:53 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, netfilter-devel

On Tue, Nov 24, 2015 at 10:25:54AM +0000, Patrick McHardy wrote:
> Tracing might be a long running operation. The cache can go out of sync, might
> be better to do a lookup on demand.

We'll need to handle generations in that approach. The kernel lookup
per trace will be expensive.

Why not just keep the cache in userspace and update it only when
needed? We can easily detect when we get out of sync via ENOBUFS.

> Right now the caching infrastrucure has quite a lot of problems and I'd prefer
> to get them fixed before we base new things on it.

The caching infrastructure only needs to have a mode to be populated
via set information, then infer existing tables from handles as you
indicated.

What other problems you see with it?

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nftables 6/6] src: add trace support to nft monitor mode
  2015-11-24 10:48     ` Florian Westphal
@ 2015-11-24 10:58       ` Patrick McHardy
  2015-11-24 11:01         ` Pablo Neira Ayuso
  2015-11-24 11:14         ` Florian Westphal
  0 siblings, 2 replies; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 10:58 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On 24.11, Florian Westphal wrote:
> Patrick McHardy <kaber@trash.net> wrote:
> > > +static void trace_print_if(const struct nftnl_trace *nlt, uint16_t attr, const char *str)
> > > +{
> > > +	char __name[IFNAMSIZ];
> > > +	const char *ifname;
> > > +
> > > +        if (!nftnl_trace_is_set(nlt, attr))
> > > +		return;
> > > +
> > > +	ifname = nft_if_indextoname(nftnl_trace_get_u32(nlt, attr), __name);
> > > +	if (ifname)
> > > +		printf(" %s %s", str, ifname);
> > > +	else
> > > +		printf(" %s %d", str, nftnl_trace_get_u32(nlt, attr));
> > > +}
> > 
> > A lot of the other trace attributes are not used so far. I'm wondering if
> > you intend to add special print functions for them as well.
> 
> All of the trace attributes are used, most of the use is limited to
> libnftnl though.
> 
> Wrt. to iif/oif, I do the printing for it in nftables to take advantage
> of the iif/oif idx<->name cache.
> 
> I would have preferred to just stick it into libnftnl like most of the
> other rest BUT then you either have the additional name translation overhead
> or just the index number...

I see. In that case this seems fine, no need to make it more complicated just
for this single attribute.

> > An alternative would be to use our internal datatypes, IOW parse the
> > attributes, associate the values with an internal type and use the regular
> > printing functions. The benefit would be fully consistent output, also
> > with respect to output options like numerical output.
> 
> Yes, right now virtually all of the printing is in libnftnl
> (called from nftables via nftnl_trace_fprintf() ).

The downside is that we're stuck to fprintf. I'm working on moving nft to
printing to buffers for pretty printing, intending set contents, sorting
flow tables in different dimensions etc. If we have external printing we'll
be missing some flexibilty in handling it, also regarding logging to other
outputs than stdout.

> > > +			if (!(cmd->monitor->flags & (1 << NFT_MSG_TRACE)))
> > > +				continue;
> > > +
> > > +			/* When tracing we'd like to translate the rule handle
> > > +			 * we receive in the trace messages to the actual rule
> > > +			 * struct to print that out.  Populate rule cache now.
> > > +			 */
> > 
> > Tracing might be a long running operation. The cache can go out of sync, might
> > be better to do a lookup on demand.
> 
> Hmm, okay.

We can certainly also update it when we receive notifications. Not sure what
we do about those currently.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nftables 6/6] src: add trace support to nft monitor mode
  2015-11-24 10:58       ` Patrick McHardy
@ 2015-11-24 11:01         ` Pablo Neira Ayuso
  2015-11-24 11:07           ` Patrick McHardy
  2015-11-24 11:14         ` Florian Westphal
  1 sibling, 1 reply; 80+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-24 11:01 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, netfilter-devel

On Tue, Nov 24, 2015 at 10:58:16AM +0000, Patrick McHardy wrote:
> On 24.11, Florian Westphal wrote:
> > > An alternative would be to use our internal datatypes, IOW parse the
> > > attributes, associate the values with an internal type and use the regular
> > > printing functions. The benefit would be fully consistent output, also
> > > with respect to output options like numerical output.
> > 
> > Yes, right now virtually all of the printing is in libnftnl
> > (called from nftables via nftnl_trace_fprintf() ).
> 
> The downside is that we're stuck to fprintf. I'm working on moving nft to
> printing to buffers for pretty printing, intending set contents, sorting
> flow tables in different dimensions etc. If we have external printing we'll
> be missing some flexibilty in handling it, also regarding logging to other
> outputs than stdout.

What we did do far is to have the fprintf variant for quick printing,
but this should be based on the printing to buffers. Both approaches
would be exported.

Does this sound good to you?

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nftables 6/6] src: add trace support to nft monitor mode
  2015-11-24 10:53     ` Pablo Neira Ayuso
@ 2015-11-24 11:04       ` Patrick McHardy
  2015-11-24 11:12         ` Pablo Neira Ayuso
  0 siblings, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 11:04 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: Florian Westphal, netfilter-devel

On 24.11, Pablo Neira Ayuso wrote:
> On Tue, Nov 24, 2015 at 10:25:54AM +0000, Patrick McHardy wrote:
> > Tracing might be a long running operation. The cache can go out of sync, might
> > be better to do a lookup on demand.
> 
> We'll need to handle generations in that approach. The kernel lookup
> per trace will be expensive.
> 
> Why not just keep the cache in userspace and update it only when
> needed? We can easily detect when we get out of sync via ENOBUFS.
> 
> > Right now the caching infrastrucure has quite a lot of problems and I'd prefer
> > to get them fixed before we base new things on it.
> 
> The caching infrastructure only needs to have a mode to be populated
> via set information, then infer existing tables from handles as you
> indicated.
> 
> What other problems you see with it?

Well I keep running into problems with it. We already discussed a few, we're
dumping way to much information that we don't need and we're making nft
require root even for unpriviledged operations and just testing ruleset
syntax.

We're basing errors on a cache that might not be up to date.

When I list the bridge table, for some reason it lists *all* tables of all
families. We're basically doing full dumps of everything in many cases.
This will be absolutely killing performance with a big ruleset.

AFAIK (did not test) we're only listing sets for the family of the first
command, then set cache_initializer to true and skip further updates. When
the ruleset refers to multiple families, the contents will not be present
but expected.

It basically seems like the big hammer approach + some bugs instead of
selectively getting what we need when we need it and making sure its
up to date, at least before generating errors based on it.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nftables 6/6] src: add trace support to nft monitor mode
  2015-11-24 11:01         ` Pablo Neira Ayuso
@ 2015-11-24 11:07           ` Patrick McHardy
  2015-11-24 11:14             ` Pablo Neira Ayuso
  0 siblings, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 11:07 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: Florian Westphal, netfilter-devel

On 24.11, Pablo Neira Ayuso wrote:
> On Tue, Nov 24, 2015 at 10:58:16AM +0000, Patrick McHardy wrote:
> > On 24.11, Florian Westphal wrote:
> > > > An alternative would be to use our internal datatypes, IOW parse the
> > > > attributes, associate the values with an internal type and use the regular
> > > > printing functions. The benefit would be fully consistent output, also
> > > > with respect to output options like numerical output.
> > > 
> > > Yes, right now virtually all of the printing is in libnftnl
> > > (called from nftables via nftnl_trace_fprintf() ).
> > 
> > The downside is that we're stuck to fprintf. I'm working on moving nft to
> > printing to buffers for pretty printing, intending set contents, sorting
> > flow tables in different dimensions etc. If we have external printing we'll
> > be missing some flexibilty in handling it, also regarding logging to other
> > outputs than stdout.
> 
> What we did do far is to have the fprintf variant for quick printing,
> but this should be based on the printing to buffers. Both approaches
> would be exported.
> 
> Does this sound good to you?

I'm completely fine with the fprintf printing *for libnfntnl*, but I'm
questing whether nft should make use of it for its own output asides from
debugging netlink operations. I also wouldn't consider the libnftnl output
stable in any form, the fprintf variant it basically something for debugging,
at least I've always seen it that way.

So yeah, I'm not opposed to having it, just to using it for this particular
purpose.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-24 10:53         ` Patrick McHardy
@ 2015-11-24 11:10           ` Florian Westphal
  2015-11-24 11:33             ` Patrick McHardy
  0 siblings, 1 reply; 80+ messages in thread
From: Florian Westphal @ 2015-11-24 11:10 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Pablo Neira Ayuso, Florian Westphal, netfilter-devel

Patrick McHardy <kaber@trash.net> wrote:
> On 24.11, Pablo Neira Ayuso wrote:
> > What I'm trying to avoid is the initial race that we'll have.
> > 
> > I mean, with this approach the user will likely enable the tracing
> > from the rule, then will launch nft trace. In that case, he will be
> > getting traces from the old way for a little while until you get one
> > process subscribed to this.

Right, not nice.

> On more thing to consider it interaction with other netfilter subsystems.
> 
> F.i. I think it would be very useful to have per connection tracing, so
> we'd store a flag in the nfct and transfer it to every packet. This would
> make them show up in the nft ruleset,

I'd prefer to complete set support for labels for this, so we can do
something like
 chain ct_trace {
	 type filter hook prerouting priority 0;
	 tcp dport 22 ct state new label set trace
	 ct label trace meta set nftrace 1
 }

 chain ct_trace_out {
	 type filter hook output priority 0;
	 ct label trace meta set nftrace 1
 }

Which would do in/out tracing without any additional code
(except the label set support, of course).

> but what about tracing in specific
> points of conntrack/NAT itself? Can we send them to the same group and
> make them integrate with ruleset tracing?

Good point.

I think we would first have to identify possible interesting tracing points.
Did you have anything specific in mind?

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-24 10:30       ` Pablo Neira Ayuso
  2015-11-24 10:35         ` Patrick McHardy
@ 2015-11-24 11:11         ` Florian Westphal
  1 sibling, 0 replies; 80+ messages in thread
From: Florian Westphal @ 2015-11-24 11:11 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: Florian Westphal, netfilter-devel

Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> If you place this in this core, we should need to export any symbol.
> 
> nf_tables-objs += nf_tables_core.o nf_tables_api.o nf_tables_trace.o

Argh, I'm a moron, I misunderstood what you meant.  Sure, that makes
sense.  Will do it this way.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nftables 6/6] src: add trace support to nft monitor mode
  2015-11-24 11:04       ` Patrick McHardy
@ 2015-11-24 11:12         ` Pablo Neira Ayuso
  2015-11-24 11:36           ` Patrick McHardy
  0 siblings, 1 reply; 80+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-24 11:12 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, netfilter-devel

On Tue, Nov 24, 2015 at 11:04:29AM +0000, Patrick McHardy wrote:
> On 24.11, Pablo Neira Ayuso wrote:
> > On Tue, Nov 24, 2015 at 10:25:54AM +0000, Patrick McHardy wrote:
> > > Tracing might be a long running operation. The cache can go out of sync, might
> > > be better to do a lookup on demand.
> > 
> > We'll need to handle generations in that approach. The kernel lookup
> > per trace will be expensive.
> > 
> > Why not just keep the cache in userspace and update it only when
> > needed? We can easily detect when we get out of sync via ENOBUFS.
> > 
> > > Right now the caching infrastrucure has quite a lot of problems and I'd prefer
> > > to get them fixed before we base new things on it.
> > 
> > The caching infrastructure only needs to have a mode to be populated
> > via set information, then infer existing tables from handles as you
> > indicated.
> > 
> > What other problems you see with it?
> 
> Well I keep running into problems with it. We already discussed a few, we're
> dumping way to much information that we don't need and we're making nft
> require root even for unpriviledged operations and just testing ruleset
> syntax.
> 
> We're basing errors on a cache that might not be up to date.
> 
> When I list the bridge table, for some reason it lists *all* tables of all
> families. We're basically doing full dumps of everything in many cases.
> This will be absolutely killing performance with a big ruleset.

OK, I'll be refining this to allow selective dumps.

> AFAIK (did not test) we're only listing sets for the family of the first
> command, then set cache_initializer to true and skip further updates. When
> the ruleset refers to multiple families, the contents will not be present
> but expected.

This may be related to the kernel patches I have to send to use
generations from the dump path.

> It basically seems like the big hammer approach + some bugs instead of
> selectively getting what we need when we need it and making sure its
> up to date, at least before generating errors based on it.

Selective dumping is good to have indeed, I'm willing to refine this.

But regarding event tracing, I think it's good to keep a cache in
userspace that we update based on the events that we receive, then
resync if we hit ENOBUFS, instead of inquiring the kernel for every
trace.

So I think Florian can get this in. I'll be resolving the existing
caching issues after him as this is not related to his work.

Fine with this approach?

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nftables 6/6] src: add trace support to nft monitor mode
  2015-11-24 11:07           ` Patrick McHardy
@ 2015-11-24 11:14             ` Pablo Neira Ayuso
  0 siblings, 0 replies; 80+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-24 11:14 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, netfilter-devel

On Tue, Nov 24, 2015 at 11:07:41AM +0000, Patrick McHardy wrote:
> On 24.11, Pablo Neira Ayuso wrote:
> > On Tue, Nov 24, 2015 at 10:58:16AM +0000, Patrick McHardy wrote:
> > > On 24.11, Florian Westphal wrote:
> > > > > An alternative would be to use our internal datatypes, IOW parse the
> > > > > attributes, associate the values with an internal type and use the regular
> > > > > printing functions. The benefit would be fully consistent output, also
> > > > > with respect to output options like numerical output.
> > > > 
> > > > Yes, right now virtually all of the printing is in libnftnl
> > > > (called from nftables via nftnl_trace_fprintf() ).
> > > 
> > > The downside is that we're stuck to fprintf. I'm working on moving nft to
> > > printing to buffers for pretty printing, intending set contents, sorting
> > > flow tables in different dimensions etc. If we have external printing we'll
> > > be missing some flexibilty in handling it, also regarding logging to other
> > > outputs than stdout.
> > 
> > What we did do far is to have the fprintf variant for quick printing,
> > but this should be based on the printing to buffers. Both approaches
> > would be exported.
> > 
> > Does this sound good to you?
> 
> I'm completely fine with the fprintf printing *for libnfntnl*, but I'm
> questing whether nft should make use of it for its own output asides from
> debugging netlink operations. I also wouldn't consider the libnftnl output
> stable in any form, the fprintf variant it basically something for debugging,
> at least I've always seen it that way.

Oh I see, you were refering to nft, that makes sense to me.

> So yeah, I'm not opposed to having it, just to using it for this particular
> purpose.

Thanks for your feedback, sorry if I'm insisting much, I just want to
make sure we get all the same picture in our heads :)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nftables 6/6] src: add trace support to nft monitor mode
  2015-11-24 10:58       ` Patrick McHardy
  2015-11-24 11:01         ` Pablo Neira Ayuso
@ 2015-11-24 11:14         ` Florian Westphal
  2015-11-24 11:41           ` Patrick McHardy
  1 sibling, 1 reply; 80+ messages in thread
From: Florian Westphal @ 2015-11-24 11:14 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, netfilter-devel

Patrick McHardy <kaber@trash.net> wrote:
> > Yes, right now virtually all of the printing is in libnftnl
> > (called from nftables via nftnl_trace_fprintf() ).
> 
> The downside is that we're stuck to fprintf. I'm working on moving nft to
> printing to buffers for pretty printing, intending set contents, sorting
> flow tables in different dimensions etc. If we have external printing we'll
> be missing some flexibilty in handling it, also regarding logging to other
> outputs than stdout.

The _fprint variant is a convenience wrapper for nftnl_trace_snprintf.
Would that work for you?


^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-24 11:10           ` Florian Westphal
@ 2015-11-24 11:33             ` Patrick McHardy
  2015-11-24 15:15               ` Florian Westphal
  0 siblings, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 11:33 UTC (permalink / raw)
  To: Florian Westphal; +Cc: Pablo Neira Ayuso, netfilter-devel

On 24.11, Florian Westphal wrote:
> Patrick McHardy <kaber@trash.net> wrote:
> > On more thing to consider it interaction with other netfilter subsystems.
> > 
> > F.i. I think it would be very useful to have per connection tracing, so
> > we'd store a flag in the nfct and transfer it to every packet. This would
> > make them show up in the nft ruleset,
> 
> I'd prefer to complete set support for labels for this, so we can do
> something like
>  chain ct_trace {
> 	 type filter hook prerouting priority 0;
> 	 tcp dport 22 ct state new label set trace
> 	 ct label trace meta set nftrace 1
>  }
> 
>  chain ct_trace_out {
> 	 type filter hook output priority 0;
> 	 ct label trace meta set nftrace 1
>  }
> 
> Which would do in/out tracing without any additional code
> (except the label set support, of course).

That's of course one possibilty but it lacks one important point, we could
not trace the first packet going through conntrack.

> > but what about tracing in specific
> > points of conntrack/NAT itself? Can we send them to the same group and
> > make them integrate with ruleset tracing?
> 
> Good point.
> 
> I think we would first have to identify possible interesting tracing points.
> Did you have anything specific in mind?

I guess the hooks themselves, probably helper invocation and/or results,
possibly interesting points within helpers, errors in protocol tracking,
basically I think a good starting point would be what we now have as global
tracing points.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nftables 6/6] src: add trace support to nft monitor mode
  2015-11-24 11:12         ` Pablo Neira Ayuso
@ 2015-11-24 11:36           ` Patrick McHardy
  0 siblings, 0 replies; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 11:36 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: Florian Westphal, netfilter-devel

On 24.11, Pablo Neira Ayuso wrote:
> On Tue, Nov 24, 2015 at 11:04:29AM +0000, Patrick McHardy wrote:
> > On 24.11, Pablo Neira Ayuso wrote:
> > Well I keep running into problems with it. We already discussed a few, we're
> > dumping way to much information that we don't need and we're making nft
> > require root even for unpriviledged operations and just testing ruleset
> > syntax.
> > 
> > We're basing errors on a cache that might not be up to date.
> > 
> > When I list the bridge table, for some reason it lists *all* tables of all
> > families. We're basically doing full dumps of everything in many cases.
> > This will be absolutely killing performance with a big ruleset.
> 
> OK, I'll be refining this to allow selective dumps.
> 
> > AFAIK (did not test) we're only listing sets for the family of the first
> > command, then set cache_initializer to true and skip further updates. When
> > the ruleset refers to multiple families, the contents will not be present
> > but expected.
> 
> This may be related to the kernel patches I have to send to use
> generations from the dump path.

As mentioned, I did not actually test this so far, but its the caching
code, it initializes for the first rule and only for that rule and bases
its queries on that handle. OTOH the dumping of all tables indicates that
it *does* dump more than that. Not sure, would have to test to be sure,
but the code looks like it.

> > It basically seems like the big hammer approach + some bugs instead of
> > selectively getting what we need when we need it and making sure its
> > up to date, at least before generating errors based on it.
> 
> Selective dumping is good to have indeed, I'm willing to refine this.
> 
> But regarding event tracing, I think it's good to keep a cache in
> userspace that we update based on the events that we receive, then
> resync if we hit ENOBUFS, instead of inquiring the kernel for every
> trace.

Generally I agree.

> So I think Florian can get this in. I'll be resolving the existing
> caching issues after him as this is not related to his work.
> 
> Fine with this approach?

Sure, it we fix this, no question :)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nftables 6/6] src: add trace support to nft monitor mode
  2015-11-24 11:14         ` Florian Westphal
@ 2015-11-24 11:41           ` Patrick McHardy
  0 siblings, 0 replies; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 11:41 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On 24.11, Florian Westphal wrote:
> Patrick McHardy <kaber@trash.net> wrote:
> > > Yes, right now virtually all of the printing is in libnftnl
> > > (called from nftables via nftnl_trace_fprintf() ).
> > 
> > The downside is that we're stuck to fprintf. I'm working on moving nft to
> > printing to buffers for pretty printing, intending set contents, sorting
> > flow tables in different dimensions etc. If we have external printing we'll
> > be missing some flexibilty in handling it, also regarding logging to other
> > outputs than stdout.
> 
> The _fprint variant is a convenience wrapper for nftnl_trace_snprintf.
> Would that work for you?

Probably, but with downsides. The nft internal buffer printing will
encapsulate every printed element so we can reorder them based on an
abstract meaning, f.i. for pretty printing, where we want to keep
related things together and reindent other parts.

We can also do filters, sorting on individual parts both numerically
and lexically, structured output etc etc, but all that requires to
have the invidual parts of the output available seperately.

So yeah it would work, and at least the sorting part doesn't make sense
for tracing anyways, but it would be a special case with some limitations.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH libnftnl 5/6] src: add trace infrastructure support
  2015-11-24 10:02 ` [PATCH libnftnl 5/6] src: add trace infrastructure support Florian Westphal
@ 2015-11-24 12:16   ` Patrick McHardy
  2015-11-24 14:53     ` Patrick McHardy
  0 siblings, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 12:16 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On 24.11, Florian Westphal wrote:
> +static int
> +print_th(const struct nftnl_trace *t, char *buf, size_t size)
> +{
> +	uint8_t proto = nftnl_trace_get_u8(t, NFTNL_TRACE_TRANSPORT_PROTO);
> +	int ret, len = size, offset = 0;
> +	const struct udphdr *uh;
> +	uint32_t plen;
> +
> +	ret = snprintf(buf+offset, len, " protocol %u", proto);
> +
> +	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
> +
> +	switch (proto) {
> +	case IPPROTO_DCCP:
> +	case IPPROTO_SCTP:
> +	case IPPROTO_TCP:
> +	case IPPROTO_UDP:
> +	case IPPROTO_UDPLITE:
> +		break;
> +	default:
> +		return 0;
> +	}
> +
> +	/* warning: only sport/dport are valid */
> +	uh = nftnl_trace_get_data(t, NFTNL_TRACE_TRANSPORT_HEADER, &plen);
> +	if (!uh)
> +		return 0;
> +
> +	ret = snprintf(buf+offset, len, " sport %"PRIu16 " dport %"PRIu16,
> +			ntohs(uh->uh_sport), ntohs(uh->uh_dport));
> +
> +	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
> +	return offset;
> +}
> + ...

Regarding this header decoding, a further upside of using nft would be that
we can already fully decode all known headers based on our protocol descriptions
in a generic fashion.

Basically we just splice off data from the beginning and feed it to payload
expression decoding. That should result in a full decode of every protocol
we support. Every improvement we will make there will automatically apply to
decoding, like (I talked to Pablo about this for a couple of times) supporing
encapsulated headers, like GRE/IPIP/... + inner headers.

Hope I can convince you of the upsides :)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH libnftnl 5/6] src: add trace infrastructure support
  2015-11-24 12:16   ` Patrick McHardy
@ 2015-11-24 14:53     ` Patrick McHardy
  0 siblings, 0 replies; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 14:53 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On 24.11, Patrick McHardy wrote:
> On 24.11, Florian Westphal wrote:
> > +static int
> > +print_th(const struct nftnl_trace *t, char *buf, size_t size)
> > +{
> > +	uint8_t proto = nftnl_trace_get_u8(t, NFTNL_TRACE_TRANSPORT_PROTO);
> > +	int ret, len = size, offset = 0;
> > +	const struct udphdr *uh;
> > +	uint32_t plen;
> > +
> > +	ret = snprintf(buf+offset, len, " protocol %u", proto);
> > +
> > +	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
> > +
> > +	switch (proto) {
> > +	case IPPROTO_DCCP:
> > +	case IPPROTO_SCTP:
> > +	case IPPROTO_TCP:
> > +	case IPPROTO_UDP:
> > +	case IPPROTO_UDPLITE:
> > +		break;
> > +	default:
> > +		return 0;
> > +	}
> > +
> > +	/* warning: only sport/dport are valid */
> > +	uh = nftnl_trace_get_data(t, NFTNL_TRACE_TRANSPORT_HEADER, &plen);
> > +	if (!uh)
> > +		return 0;
> > +
> > +	ret = snprintf(buf+offset, len, " sport %"PRIu16 " dport %"PRIu16,
> > +			ntohs(uh->uh_sport), ntohs(uh->uh_dport));
> > +
> > +	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
> > +	return offset;
> > +}
> > + ...
> 
> Regarding this header decoding, a further upside of using nft would be that
> we can already fully decode all known headers based on our protocol descriptions
> in a generic fashion.
> 
> Basically we just splice off data from the beginning and feed it to payload
> expression decoding. That should result in a full decode of every protocol
> we support. Every improvement we will make there will automatically apply to
> decoding, like (I talked to Pablo about this for a couple of times) supporing
> encapsulated headers, like GRE/IPIP/... + inner headers.
> 
> Hope I can convince you of the upsides :)

I'm giving this a shot right now. Will let you know the result.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-24 11:33             ` Patrick McHardy
@ 2015-11-24 15:15               ` Florian Westphal
  2015-11-24 15:26                 ` Patrick McHardy
  0 siblings, 1 reply; 80+ messages in thread
From: Florian Westphal @ 2015-11-24 15:15 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, Pablo Neira Ayuso, netfilter-devel

Patrick McHardy <kaber@trash.net> wrote:

Sorry for late reply.

> >  chain ct_trace {
> > 	 type filter hook prerouting priority 0;
> > 	 tcp dport 22 ct state new label set trace
> > 	 ct label trace meta set nftrace 1
> >  }
> > 
> >  chain ct_trace_out {
> > 	 type filter hook output priority 0;
> > 	 ct label trace meta set nftrace 1
> >  }
> > 
> > Which would do in/out tracing without any additional code
> > (except the label set support, of course).
> 
> That's of course one possibilty but it lacks one important point, we could
> not trace the first packet going through conntrack.

Right, hooks that run 'earlier' than conntrack would not be able to
use ct state matching.

I'm not sure if thats a real issue, we could just use stateless matching
based on ip addresses and ports.

Lastly, I do think that we'll eventually have a ct expression to
actually do tracking for us rather than the implicit hooking we have
right now (my plan was to add this for nft bridge family conntrack
support).

> > I think we would first have to identify possible interesting tracing points.
> > Did you have anything specific in mind?
> 
> I guess the hooks themselves, probably helper invocation and/or results,
> possibly interesting points within helpers, errors in protocol tracking,
> basically I think a good starting point would be what we now have as global
> tracing points.

Ok, I see.  I'll think about this some more.

But I don't see why we could not build it upon the proposed
infrastructure; we do not have a rule handle and we might need to add
further attributes to identify where exactly we are at the moment.

In the patchset proposed here, 'where we are' is defined like this:

NFT_TRACETYPE_PACKET -> in a nft meta rule
(this trace type is followed by NFT_TRACETYPE_RULE one and only exists
 so we don't include packet data all the time.)
Alternative would be to remove NFT_TRACETYPE_PACKET and
always include payload info instead.

NFT_TRACETYPE_RULE   -> contains rule handle to figure out where we are
NFT_TRACETYPE_RETURN -> also contains rule handle
NFT_TRACETYPE_POLICY -> no rule handle, 'only' chain and table name

IOW, the current types are very much bolted to rule evaulation.

To support ct/helper etc. events  we would need to add new types, e.g.
NFT_TRACETYPE_CT, NFT_TRACETYPE_CT_L3PROTO, ... or whatever.

Main problem I see is how the 'where we are' info should be provided
and how to include what is happening.

We already have an attribute for verdicts, but that won't be enough.
Adding NFTA_TRACE_FILENAME/LINENO seems wrong to me since that would
be a pure development thing and we already have tools like perf probe
for that.

I don't see anything in the current proposal that would not allow to use
it for further netfilter trace events, however, at least for conntrack
i suspect it might make more sense to extend ctnetlink instead.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-24 15:15               ` Florian Westphal
@ 2015-11-24 15:26                 ` Patrick McHardy
  2015-11-24 15:35                   ` Florian Westphal
  0 siblings, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 15:26 UTC (permalink / raw)
  To: Florian Westphal; +Cc: Pablo Neira Ayuso, netfilter-devel

On 24.11, Florian Westphal wrote:
> Patrick McHardy <kaber@trash.net> wrote:
> 
> Sorry for late reply.
> 
> > >  chain ct_trace {
> > > 	 type filter hook prerouting priority 0;
> > > 	 tcp dport 22 ct state new label set trace
> > > 	 ct label trace meta set nftrace 1
> > >  }
> > > 
> > >  chain ct_trace_out {
> > > 	 type filter hook output priority 0;
> > > 	 ct label trace meta set nftrace 1
> > >  }
> > > 
> > > Which would do in/out tracing without any additional code
> > > (except the label set support, of course).
> > 
> > That's of course one possibilty but it lacks one important point, we could
> > not trace the first packet going through conntrack.
> 
> Right, hooks that run 'earlier' than conntrack would not be able to
> use ct state matching.
> 
> I'm not sure if thats a real issue, we could just use stateless matching
> based on ip addresses and ports.
> 
> Lastly, I do think that we'll eventually have a ct expression to
> actually do tracking for us rather than the implicit hooking we have
> right now (my plan was to add this for nft bridge family conntrack
> support).

I'm thinking mainly of expected connections, which would be a pretty
interesting case for automatic tracing and which are impossible to handle
without conntrack interaction. Even with manual tracking we'd still have
to do a lookup for every packet to detect those and to detect replies.

> > > I think we would first have to identify possible interesting tracing points.
> > > Did you have anything specific in mind?
> > 
> > I guess the hooks themselves, probably helper invocation and/or results,
> > possibly interesting points within helpers, errors in protocol tracking,
> > basically I think a good starting point would be what we now have as global
> > tracing points.
> 
> Ok, I see.  I'll think about this some more.
> 
> But I don't see why we could not build it upon the proposed
> infrastructure; we do not have a rule handle and we might need to add
> further attributes to identify where exactly we are at the moment.
> 
> In the patchset proposed here, 'where we are' is defined like this:
> 
> NFT_TRACETYPE_PACKET -> in a nft meta rule
> (this trace type is followed by NFT_TRACETYPE_RULE one and only exists
>  so we don't include packet data all the time.)
> Alternative would be to remove NFT_TRACETYPE_PACKET and
> always include payload info instead.
> 
> NFT_TRACETYPE_RULE   -> contains rule handle to figure out where we are
> NFT_TRACETYPE_RETURN -> also contains rule handle
> NFT_TRACETYPE_POLICY -> no rule handle, 'only' chain and table name
> 
> IOW, the current types are very much bolted to rule evaulation.
> 
> To support ct/helper etc. events  we would need to add new types, e.g.
> NFT_TRACETYPE_CT, NFT_TRACETYPE_CT_L3PROTO, ... or whatever.
> 
> Main problem I see is how the 'where we are' info should be provided
> and how to include what is happening.
> 
> We already have an attribute for verdicts, but that won't be enough.
> Adding NFTA_TRACE_FILENAME/LINENO seems wrong to me since that would
> be a pure development thing and we already have tools like perf probe
> for that.

Yes absolutely. We have a few things that provide stable identifiers, f.i.
hooks, helper names, protocol names, subsystems (conntrack/NAT/TCP names
will not change), ...

If we need more granularity we need to define some stable sub-identifiers.

> I don't see anything in the current proposal that would not allow to use
> it for further netfilter trace events, however, at least for conntrack
> i suspect it might make more sense to extend ctnetlink instead.

Sure, I'm just saying we should consider this. ctnetlink is more about
ct events, not really about the packets. I just think it makes sense to
have a unified view of tracing because you run into ordering issues if you
send events using multiple subsystems. There's also a big advantage in
being able to use a simple tool like nft for all your tracing needs compared
to combining nft, nfnetlink_log and ctnetlink data to get the full picture.

I'm all for including all the data we need to get a good picture like you
have now, I just want to make sure we don't make decisions that prevent us
from extending it to other subsystems later on.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-24 15:26                 ` Patrick McHardy
@ 2015-11-24 15:35                   ` Florian Westphal
  2015-11-24 15:42                     ` Patrick McHardy
  0 siblings, 1 reply; 80+ messages in thread
From: Florian Westphal @ 2015-11-24 15:35 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, Pablo Neira Ayuso, netfilter-devel

Patrick McHardy <kaber@trash.net> wrote:
> On 24.11, Florian Westphal wrote:
> > We already have an attribute for verdicts, but that won't be enough.
> > Adding NFTA_TRACE_FILENAME/LINENO seems wrong to me since that would
> > be a pure development thing and we already have tools like perf probe
> > for that.
> 
> Yes absolutely. We have a few things that provide stable identifiers, f.i.
> hooks, helper names, protocol names, subsystems (conntrack/NAT/TCP names
> will not change), ...

Ok, so that should work within this proposed set, we would need to add
new attributes and types:

e.g. NFT_TRACETYPE_CT which then can set NFTA_TRACE_HELPER_NAME or any other
new attr we want/need.

> If we need more granularity we need to define some stable sub-identifiers.
> 
> > I don't see anything in the current proposal that would not allow to use
> > it for further netfilter trace events, however, at least for conntrack
> > i suspect it might make more sense to extend ctnetlink instead.
> 
> Sure, I'm just saying we should consider this. ctnetlink is more about
> ct events, not really about the packets.

Right.

> I just think it makes sense to
> have a unified view of tracing because you run into ordering issues if you
> send events using multiple subsystems. There's also a big advantage in
> being able to use a simple tool like nft for all your tracing needs compared
> to combining nft, nfnetlink_log and ctnetlink data to get the full picture.

Yes, I see.  This makes sense.  I'm withdrawing the ctnetlink comment.
We have extensions for nflog and nfqueue to serialize the CT object
entirely withing nfnetlink_log/queue, might also add
NFTA_TRACE_CT as a nested attribute that contains the entire ct object.

> I'm all for including all the data we need to get a good picture like you
> have now, I just want to make sure we don't make decisions that prevent us
> from extending it to other subsystems later on.

Ok.  Basically I'm going to ignore all of your comments here, since I
would first like to get the v1 'right' before extending it to more
subsystems.

IFF you see anything that prevents us from doing such extension, please
yell.  But AFAICS the proposed attributes and types should be fine wrt.
extensibility.

I'm going to add new netlink group for the trace events and will address
all the other comments.

Thanks for reviewing!

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-24 15:35                   ` Florian Westphal
@ 2015-11-24 15:42                     ` Patrick McHardy
  2015-11-25 15:06                       ` Patrick McHardy
  0 siblings, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-24 15:42 UTC (permalink / raw)
  To: Florian Westphal; +Cc: Pablo Neira Ayuso, netfilter-devel

On 24.11, Florian Westphal wrote:
> Patrick McHardy <kaber@trash.net> wrote:
> > On 24.11, Florian Westphal wrote:
> > > We already have an attribute for verdicts, but that won't be enough.
> > > Adding NFTA_TRACE_FILENAME/LINENO seems wrong to me since that would
> > > be a pure development thing and we already have tools like perf probe
> > > for that.
> > 
> > Yes absolutely. We have a few things that provide stable identifiers, f.i.
> > hooks, helper names, protocol names, subsystems (conntrack/NAT/TCP names
> > will not change), ...
> 
> Ok, so that should work within this proposed set, we would need to add
> new attributes and types:
> 
> e.g. NFT_TRACETYPE_CT which then can set NFTA_TRACE_HELPER_NAME or any other
> new attr we want/need.
> 
> > If we need more granularity we need to define some stable sub-identifiers.
> > 
> > > I don't see anything in the current proposal that would not allow to use
> > > it for further netfilter trace events, however, at least for conntrack
> > > i suspect it might make more sense to extend ctnetlink instead.
> > 
> > Sure, I'm just saying we should consider this. ctnetlink is more about
> > ct events, not really about the packets.
> 
> Right.
> 
> > I just think it makes sense to
> > have a unified view of tracing because you run into ordering issues if you
> > send events using multiple subsystems. There's also a big advantage in
> > being able to use a simple tool like nft for all your tracing needs compared
> > to combining nft, nfnetlink_log and ctnetlink data to get the full picture.
> 
> Yes, I see.  This makes sense.  I'm withdrawing the ctnetlink comment.
> We have extensions for nflog and nfqueue to serialize the CT object
> entirely withing nfnetlink_log/queue, might also add
> NFTA_TRACE_CT as a nested attribute that contains the entire ct object.
> 
> > I'm all for including all the data we need to get a good picture like you
> > have now, I just want to make sure we don't make decisions that prevent us
> > from extending it to other subsystems later on.
> 
> Ok.  Basically I'm going to ignore all of your comments here, since I
> would first like to get the v1 'right' before extending it to more
> subsystems.

Absolutely :)

> IFF you see anything that prevents us from doing such extension, please
> yell.  But AFAICS the proposed attributes and types should be fine wrt.
> extensibility.
> 
> I'm going to add new netlink group for the trace events and will address
> all the other comments.

Sounds good. I'm having first success decoding headers using the nft internal
protocol structure.

Sounds good. I'm having first success decoding headers using the nft internal
protocol structure. Needs more refinement but I expect to have a RFC later
today.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-24 10:02 ` [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure Florian Westphal
                     ` (2 preceding siblings ...)
  2015-11-24 10:44   ` Patrick McHardy
@ 2015-11-25  0:55   ` Patrick McHardy
  2015-11-25  8:39     ` Florian Westphal
  3 siblings, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-25  0:55 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

Some more comments below:

> diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
> index d8c8a7c..88bcd00 100644
> --- a/include/uapi/linux/netfilter/nf_tables.h
> +++ b/include/uapi/linux/netfilter/nf_tables.h
> @@ -970,4 +972,34 @@ enum nft_gen_attributes {
>  };
>  #define NFTA_GEN_MAX		(__NFTA_GEN_MAX - 1)
>  
> +enum nft_trace_attibutes {
> +	NFTA_TRACE_UNSPEC,
> +	NFTA_TRACE_CHAIN,
> +	NFTA_TRACE_DEV_TYPE,
> +	NFTA_TRACE_ID,
> +	NFTA_TRACE_IIF,
> +	NFTA_TRACE_OIF,
> +	NFTA_TRACE_LL_HEADER,
> +	NFTA_TRACE_MARK,
> +	NFTA_TRACE_NETWORK_HEADER,
> +	NFTA_TRACE_TABLE,
> +	NFTA_TRACE_TRANSPORT_HEADER,
> +	NFTA_TRACE_TRANSPORT_PROTO,
> +	NFTA_TRACE_TYPE,
> +	NFTA_TRACE_RULE_HANDLE,
> +	NFTA_TRACE_VERDICT,
> +	NFTA_TRACE_VLAN_TAG,
> +	__NFTA_TRACE_MAX
> +};
> +#define NFTA_TRACE_MAX (__NFTA_TRACE_MAX - 1)

The ordering appears to be a bit random (or I'm missing something), I'd
expect basic information like TABLE/CHAIN/RULE_HANDLE to be at the beginning
(in that order), similar for TYPE, VERDICT etc.

> diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
> index 93cc473..25d8168 100644
> --- a/net/netfilter/nf_tables_api.c
> +++ b/net/netfilter/nf_tables_api.c
> @@ -21,6 +23,10 @@
>  #include <net/net_namespace.h>
>  #include <net/sock.h>
>  
> +#define NFT_TRACETYPE_LL_HSIZE		20
> +#define NFT_TRACETYPE_NETWORK_HSIZE	32
> +#define NFT_TRACETYPE_TRANSPORT_HSIZE	 4

4 seems to be too small for some header types like GRE. If the key is present
it seems like information we'd want to log.

Also since people probably want to use this to determine why or why not rules
match, I think it would be good to have the entire transport header present.

> +static bool
> +trace_notify_put_packet(struct sk_buff *nlskb, const struct nft_pktinfo *pkt)
> +{
> +	const struct sk_buff *skb = pkt->skb;
> +	unsigned int plen = min_t(unsigned int,
> +				  pkt->xt.thoff - skb_network_offset(skb),
> +				  NFT_TRACETYPE_NETWORK_HSIZE);
> +	int mac_off;
> +
> +	if (plen >= 20u && /* minimum iphdr size */
> +	    !trace_notify_put_data(nlskb, NFTA_TRACE_NETWORK_HEADER,
> +				   skb, skb_network_offset(skb), plen))
> +		return false;

Does that check for 20u have any deeper meaning? It seems this will always
be true for all currently supported protocols and if we were to add support
for one that has a smaller size it won't work.

> +	plen = min_t(unsigned int, skb->len - pkt->xt.thoff,
> +		     NFT_TRACETYPE_TRANSPORT_HSIZE);
> +
> +	if (plen >= sizeof(u32) &&
> +	    !trace_notify_put_data(nlskb, NFTA_TRACE_TRANSPORT_HEADER,
> +				   skb, pkt->xt.thoff, plen))
> +		return false;

Same question here, is there anything wrong with including a smaller sized
header? Especially since we're talking about a debugging tool.

> +void nf_tables_trace_notify(const struct nft_pktinfo *pkt,
> +			    const struct nft_chain *chain,
> +			    const struct nft_rule *rule,
> +			    u32 verdict,
> +			    enum nft_trace_types type)
> +{
> + [...]
> +	if (nla_put_be32(skb, NFTA_TRACE_ID, htonl(hash32_ptr(pkt->skb))))
> +		goto nla_put_failure;

This could lead to duplicate IDs quite quickly. I can't think of any other
values where we know for sure they will stay constant while the skb is within
netfilter. How about combining this with a per CPU counter or something
similar?

> +	if (chain) {
> +		if (nla_put_string(skb, NFTA_TRACE_TABLE, chain->table->name))
> +			goto nla_put_failure;
> +		if (nla_put_string(skb, NFTA_TRACE_CHAIN, chain->name))
> +			goto nla_put_failure;
> +	}
> +
> +	if (rule && nla_put_be64(skb, NFTA_TRACE_RULE_HANDLE,
> +				 cpu_to_be64(rule->handle)))

Minor nitpick: below you use

	if (condition &&
	    nla_put_...

which I think is more readable.

> +		goto nla_put_failure;
> +
> +	if (pkt->in &&
> +	    nla_put_be32(skb, NFTA_TRACE_IIF, htonl(pkt->in->ifindex)))
> +		goto nla_put_failure;
> +	if (pkt->out &&
> +	    nla_put_be32(skb, NFTA_TRACE_OIF, htonl(pkt->out->ifindex)))
> +		goto nla_put_failure;
> +	if (pkt->skb->mark &&
> +	    nla_put_be32(skb, NFTA_TRACE_MARK, htonl(pkt->skb->mark)))
> +		goto nla_put_failure;
> +
> +	switch (type) {
> +	case NFT_TRACETYPE_POLICY:
> +	case NFT_TRACETYPE_RETURN:
> +	case NFT_TRACETYPE_RULE:
> +		if (nla_put_be32(skb, NFTA_TRACE_VERDICT, htonl(verdict)))
> +			goto nla_put_failure;

It would be nice to have the full verdict available, IOW also the jump target.

You could simply pass struct nft_verdict to this function and adapt
nft_verdict_dump() to take the attribute value as parameter.

> diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
> index f3695a4..29a6ca9 100644
> --- a/net/netfilter/nf_tables_core.c
> +++ b/net/netfilter/nf_tables_core.c
> @@ -56,10 +56,15 @@ static void __nft_trace_packet(const struct nft_pktinfo *pkt,
> @@ -161,7 +167,9 @@ next_rule:
>  	case NF_ACCEPT:
>  	case NF_DROP:
>  	case NF_QUEUE:
> -		nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
> +		nft_trace_packet(pkt, chain, rule, rulenum,
> +				 regs.verdict.code & NF_VERDICT_MASK,

I'd suggest to include the full verdict code. Embedded errno codes or queue
numbers are certainly also of interest.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-24 10:02 ` [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present Florian Westphal
  2015-11-24 10:16   ` Patrick McHardy
  2015-11-24 10:24   ` Pablo Neira Ayuso
@ 2015-11-25  0:57   ` Patrick McHardy
  2 siblings, 0 replies; 80+ messages in thread
From: Patrick McHardy @ 2015-11-25  0:57 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On 24.11, Florian Westphal wrote:
> No need to clutter nflog/dmesg ring buffer with the old tracing output
> when the 'native' nfnetlink interface is used.
> 
> Signed-off-by: Florian Westphal <fw@strlen.de>
> ---
>  net/netfilter/nf_tables_core.c | 9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)
> 
> diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
> index dabf5ed..69bdd9a 100644
> --- a/net/netfilter/nf_tables_core.c
> +++ b/net/netfilter/nf_tables_core.c
> @@ -69,7 +70,13 @@ static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
>  		if (!pkt->skb->nf_trace)
>  			return;
>  		nf_tables_trace_notify(pkt, chain, rule, verdict, type);
> -		__nft_trace_packet(pkt, chain, rulenum, type);
> +		if (prefer_native_trace)
> +			return;
> +
> +		if (nfnetlink_has_listeners(pkt->net, NFNLGRP_NFTABLES))
> +			prefer_native_trace = true;
> +		else
> +			__nft_trace_packet(pkt, chain, rulenum, type);

Not sure how the final solution is going to look, but this inline function was
meant to *only* get rid of the repeated nf_trace checks. Anything else should
be done out of line IMO since its inlined into the most performance critical
function of nftables.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-25  0:55   ` Patrick McHardy
@ 2015-11-25  8:39     ` Florian Westphal
  2015-11-25  8:48       ` Florian Westphal
  2015-11-25  9:35       ` Patrick McHardy
  0 siblings, 2 replies; 80+ messages in thread
From: Florian Westphal @ 2015-11-25  8:39 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, netfilter-devel

Patrick McHardy <kaber@trash.net> wrote:
> > diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
> > index d8c8a7c..88bcd00 100644
> > --- a/include/uapi/linux/netfilter/nf_tables.h
> > +++ b/include/uapi/linux/netfilter/nf_tables.h
> > @@ -970,4 +972,34 @@ enum nft_gen_attributes {
> >  };
> >  #define NFTA_GEN_MAX		(__NFTA_GEN_MAX - 1)
> >  
> > +enum nft_trace_attibutes {
> > +	NFTA_TRACE_UNSPEC,
> > +	NFTA_TRACE_CHAIN,
> > +	NFTA_TRACE_DEV_TYPE,
> > +	NFTA_TRACE_ID,
> > +	NFTA_TRACE_IIF,
> > +	NFTA_TRACE_OIF,
> > +	NFTA_TRACE_LL_HEADER,
> > +	NFTA_TRACE_MARK,
> > +	NFTA_TRACE_NETWORK_HEADER,
> > +	NFTA_TRACE_TABLE,
> > +	NFTA_TRACE_TRANSPORT_HEADER,
> > +	NFTA_TRACE_TRANSPORT_PROTO,
> > +	NFTA_TRACE_TYPE,
> > +	NFTA_TRACE_RULE_HANDLE,
> > +	NFTA_TRACE_VERDICT,
> > +	NFTA_TRACE_VLAN_TAG,
> > +	__NFTA_TRACE_MAX
> > +};
> > +#define NFTA_TRACE_MAX (__NFTA_TRACE_MAX - 1)
> 
> The ordering appears to be a bit random (or I'm missing something), I'd
> expect basic information like TABLE/CHAIN/RULE_HANDLE to be at the beginning
> (in that order), similar for TYPE, VERDICT etc.

NFTA_TRACE_UNSPEC,
NFTA_TRACE_TABLE,
NFTA_TRACE_CHAIN,
NFTA_TRACE_RULE_HANDLE,
NFTA_TRACE_TYPE,
NFTA_TRACE_VERDICT,
NFTA_TRACE_DEV_TYPE,
NFTA_TRACE_ID,
NFTA_TRACE_LL_HEADER,
NFTA_TRACE_NETWORK_HEADER,
NFTA_TRACE_TRANSPORT_HEADER,
NFTA_TRACE_TRANSPORT_PROTO,
NFTA_TRACE_IIF,
NFTA_TRACE_OIF,
NFTA_TRACE_MARK,
NFTA_TRACE_VLAN_TAG,

better?  If not, please just tell me what ordering you'd prefer and
thats what I'll use.

> > diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
> > index 93cc473..25d8168 100644
> > --- a/net/netfilter/nf_tables_api.c
> > +++ b/net/netfilter/nf_tables_api.c
> > @@ -21,6 +23,10 @@
> >  #include <net/net_namespace.h>
> >  #include <net/sock.h>
> >  
> > +#define NFT_TRACETYPE_LL_HSIZE		20
> > +#define NFT_TRACETYPE_NETWORK_HSIZE	32
> > +#define NFT_TRACETYPE_TRANSPORT_HSIZE	 4
> 
> 4 seems to be too small for some header types like GRE. If the key is present
> it seems like information we'd want to log.
> 
> Also since people probably want to use this to determine why or why not rules
> match, I think it would be good to have the entire transport header present.
> 
> > +static bool
> > +trace_notify_put_packet(struct sk_buff *nlskb, const struct nft_pktinfo *pkt)
> > +{
> > +	const struct sk_buff *skb = pkt->skb;
> > +	unsigned int plen = min_t(unsigned int,
> > +				  pkt->xt.thoff - skb_network_offset(skb),
> > +				  NFT_TRACETYPE_NETWORK_HSIZE);
> > +	int mac_off;
> > +
> > +	if (plen >= 20u && /* minimum iphdr size */
> > +	    !trace_notify_put_data(nlskb, NFTA_TRACE_NETWORK_HEADER,
> > +				   skb, skb_network_offset(skb), plen))
> > +		return false;
> 
> Does that check for 20u have any deeper meaning? It seems this will always
> be true for all currently supported protocols and if we were to add support
> for one that has a smaller size it won't work.

OK, I'll change all checks to 'len &&'.

> > +     if (nla_put_be32(skb, NFTA_TRACE_ID, htonl(hash32_ptr(pkt->skb)))) 

> This could lead to duplicate IDs quite quickly. I can't think of any other
> values where we know for sure they will stay constant while the skb is within
> netfilter. How about combining this with a per CPU counter or something
> similar?

I would not mind, it would result in ID change though for nfqueue case.
If thats ok I'll use a pcpu counter that gets incremented when nft_meta
sets skb->nftrace=1 and use __this_cpu_read(trace_id) instead (if we
have pcpu id counter, is there any point in also using skb address...?)

> > +	if (chain) {
> > +		if (nla_put_string(skb, NFTA_TRACE_TABLE, chain->table->name))
> > +			goto nla_put_failure;
> > +		if (nla_put_string(skb, NFTA_TRACE_CHAIN, chain->name))
> > +			goto nla_put_failure;
> > +	}
> > +
> > +	if (rule && nla_put_be64(skb, NFTA_TRACE_RULE_HANDLE,
> > +				 cpu_to_be64(rule->handle)))
> 
> Minor nitpick: below you use
> 
> 	if (condition &&
> 	    nla_put_...
> 
> which I think is more readable.

ok.  I only used the former if line would go over 80, but i can convert
this too of course.

> > +	if (pkt->in &&
> > +	    nla_put_be32(skb, NFTA_TRACE_IIF, htonl(pkt->in->ifindex)))
> > +		goto nla_put_failure;
> > +	if (pkt->out &&
> > +	    nla_put_be32(skb, NFTA_TRACE_OIF, htonl(pkt->out->ifindex)))
> > +		goto nla_put_failure;
> > +	if (pkt->skb->mark &&
> > +	    nla_put_be32(skb, NFTA_TRACE_MARK, htonl(pkt->skb->mark)))
> > +		goto nla_put_failure;
> > +
> > +	switch (type) {
> > +	case NFT_TRACETYPE_POLICY:
> > +	case NFT_TRACETYPE_RETURN:
> > +	case NFT_TRACETYPE_RULE:
> > +		if (nla_put_be32(skb, NFTA_TRACE_VERDICT, htonl(verdict)))
> > +			goto nla_put_failure;
> 
> It would be nice to have the full verdict available, IOW also the jump target.
> 
> You could simply pass struct nft_verdict to this function and adapt
> nft_verdict_dump() to take the attribute value as parameter.

Will add NFTA_TRACE_JUMP/NFTA_TRACE_GOTO for that, ok?

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-25  8:39     ` Florian Westphal
@ 2015-11-25  8:48       ` Florian Westphal
  2015-11-25  9:35       ` Patrick McHardy
  1 sibling, 0 replies; 80+ messages in thread
From: Florian Westphal @ 2015-11-25  8:48 UTC (permalink / raw)
  To: Florian Westphal; +Cc: Patrick McHardy, netfilter-devel

Florian Westphal <fw@strlen.de> wrote:
> Patrick McHardy <kaber@trash.net> wrote:
> > It would be nice to have the full verdict available, IOW also the jump target.
> > 
> > You could simply pass struct nft_verdict to this function and adapt
> > nft_verdict_dump() to take the attribute value as parameter.
> 
> Will add NFTA_TRACE_JUMP/NFTA_TRACE_GOTO for that, ok?

Scratch that, I'll add NFTA_TRACE_JUMP_TARGET (NLA_STRING) containing
name of the jump target (if any).

GOTO case can be inferred from the verdict attribute.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-25  8:39     ` Florian Westphal
  2015-11-25  8:48       ` Florian Westphal
@ 2015-11-25  9:35       ` Patrick McHardy
  2015-11-25 10:13         ` Florian Westphal
  1 sibling, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-25  9:35 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On 25.11, Florian Westphal wrote:
> Patrick McHardy <kaber@trash.net> wrote:
> > 
> > The ordering appears to be a bit random (or I'm missing something), I'd
> > expect basic information like TABLE/CHAIN/RULE_HANDLE to be at the beginning
> > (in that order), similar for TYPE, VERDICT etc.
> 
> NFTA_TRACE_UNSPEC,
> NFTA_TRACE_TABLE,
> NFTA_TRACE_CHAIN,
> NFTA_TRACE_RULE_HANDLE,
> NFTA_TRACE_TYPE,
> NFTA_TRACE_VERDICT,
> NFTA_TRACE_DEV_TYPE,
> NFTA_TRACE_ID,
> NFTA_TRACE_LL_HEADER,
> NFTA_TRACE_NETWORK_HEADER,
> NFTA_TRACE_TRANSPORT_HEADER,
> NFTA_TRACE_TRANSPORT_PROTO,
> NFTA_TRACE_IIF,
> NFTA_TRACE_OIF,
> NFTA_TRACE_MARK,
> NFTA_TRACE_VLAN_TAG,
> 
> better?  If not, please just tell me what ordering you'd prefer and
> thats what I'll use.

Yep looks good.

> > > +     if (nla_put_be32(skb, NFTA_TRACE_ID, htonl(hash32_ptr(pkt->skb)))) 
> 
> > This could lead to duplicate IDs quite quickly. I can't think of any other
> > values where we know for sure they will stay constant while the skb is within
> > netfilter. How about combining this with a per CPU counter or something
> > similar?
> 
> I would not mind, it would result in ID change though for nfqueue case.
> If thats ok I'll use a pcpu counter that gets incremented when nft_meta
> sets skb->nftrace=1 and use __this_cpu_read(trace_id) instead (if we
> have pcpu id counter, is there any point in also using skb address...?)

Not sure, I guess not.

> > > +	switch (type) {
> > > +	case NFT_TRACETYPE_POLICY:
> > > +	case NFT_TRACETYPE_RETURN:
> > > +	case NFT_TRACETYPE_RULE:
> > > +		if (nla_put_be32(skb, NFTA_TRACE_VERDICT, htonl(verdict)))
> > > +			goto nla_put_failure;
> > 
> > It would be nice to have the full verdict available, IOW also the jump target.
> > 
> > You could simply pass struct nft_verdict to this function and adapt
> > nft_verdict_dump() to take the attribute value as parameter.
> 
> Will add NFTA_TRACE_JUMP/NFTA_TRACE_GOTO for that, ok?

Any reason not to use the standard verdict encoding? We even have an almost
ready to use function for that.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-25  9:35       ` Patrick McHardy
@ 2015-11-25 10:13         ` Florian Westphal
  2015-11-25 11:51           ` Patrick McHardy
  0 siblings, 1 reply; 80+ messages in thread
From: Florian Westphal @ 2015-11-25 10:13 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, netfilter-devel

Patrick McHardy <kaber@trash.net> wrote:
> > > > +     if (nla_put_be32(skb, NFTA_TRACE_ID, htonl(hash32_ptr(pkt->skb)))) 
> > 
> > > This could lead to duplicate IDs quite quickly. I can't think of any other
> > > values where we know for sure they will stay constant while the skb is within
> > > netfilter. How about combining this with a per CPU counter or something
> > > similar?
> > 
> > I would not mind, it would result in ID change though for nfqueue case.
> > If thats ok I'll use a pcpu counter that gets incremented when nft_meta
> > sets skb->nftrace=1 and use __this_cpu_read(trace_id) instead (if we
> > have pcpu id counter, is there any point in also using skb address...?)
> 
> Not sure, I guess not.

Ok, I'll move to pcpu id counter in v2

> > > > +	switch (type) {
> > > > +	case NFT_TRACETYPE_POLICY:
> > > > +	case NFT_TRACETYPE_RETURN:
> > > > +	case NFT_TRACETYPE_RULE:
> > > > +		if (nla_put_be32(skb, NFTA_TRACE_VERDICT, htonl(verdict)))
> > > > +			goto nla_put_failure;
> > > 
> > > It would be nice to have the full verdict available, IOW also the jump target.
> > > 
> > > You could simply pass struct nft_verdict to this function and adapt
> > > nft_verdict_dump() to take the attribute value as parameter.
> > 
> > Will add NFTA_TRACE_JUMP/NFTA_TRACE_GOTO for that, ok?
> 
> Any reason not to use the standard verdict encoding? We even have an almost
> ready to use function for that.

Sorry, could you be more specific?
How would you tell userspace where the jump/goto is going to?

What I am doing now in my local version:

NFTA_TRACE_VERDICT is the verbatim result of the hook (i.e. might
contain errno or queue id).

NFTA_TRACE_JUMP_TARGET is the name of the chain that we goto or jump to,
set when verdict == NFT_JUMP/_GOTO.

Alternative suggestions welcome.

This approach means that userspace must try a bit harder to decode
the verdict since we cannot use 'verdict & NF_VERDICT_MASK' if we're
looking at a NFT_* verdict when translating the integer to a string.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-25 10:13         ` Florian Westphal
@ 2015-11-25 11:51           ` Patrick McHardy
  2015-11-25 12:20             ` Florian Westphal
  0 siblings, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-25 11:51 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On 25.11, Florian Westphal wrote:
> > > > It would be nice to have the full verdict available, IOW also the jump target.
> > > > 
> > > > You could simply pass struct nft_verdict to this function and adapt
> > > > nft_verdict_dump() to take the attribute value as parameter.
> > > 
> > > Will add NFTA_TRACE_JUMP/NFTA_TRACE_GOTO for that, ok?
> > 
> > Any reason not to use the standard verdict encoding? We even have an almost
> > ready to use function for that.
> 
> Sorry, could you be more specific?
> How would you tell userspace where the jump/goto is going to?

We have nft_verdict_dump(), which encodes the verdict as nested attribute.
I'd suggest to simply use that one since we also already have parsing
functions for that in both nft and libnftnl and we can use the regular
data structures.

> What I am doing now in my local version:
> 
> NFTA_TRACE_VERDICT is the verbatim result of the hook (i.e. might
> contain errno or queue id).
> 
> NFTA_TRACE_JUMP_TARGET is the name of the chain that we goto or jump to,
> set when verdict == NFT_JUMP/_GOTO.
> 
> Alternative suggestions welcome.
> 
> This approach means that userspace must try a bit harder to decode
> the verdict since we cannot use 'verdict & NF_VERDICT_MASK' if we're
> looking at a NFT_* verdict when translating the integer to a string.

With the approach I mentioned we can use the normal decoding functions
which (at least in nft) handle this case fine.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure
  2015-11-25 11:51           ` Patrick McHardy
@ 2015-11-25 12:20             ` Florian Westphal
  0 siblings, 0 replies; 80+ messages in thread
From: Florian Westphal @ 2015-11-25 12:20 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, netfilter-devel

Patrick McHardy <kaber@trash.net> wrote:
> > Sorry, could you be more specific?
> > How would you tell userspace where the jump/goto is going to?
> 
> We have nft_verdict_dump(), which encodes the verdict as nested attribute.
> I'd suggest to simply use that one since we also already have parsing
> functions for that in both nft and libnftnl and we can use the regular
> data structures.

Thanks for clarifying, I'll switch NFTA_TRACE_VERDICT to nested attr.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-24 15:42                     ` Patrick McHardy
@ 2015-11-25 15:06                       ` Patrick McHardy
  2015-11-25 16:23                         ` Pablo Neira Ayuso
                                           ` (2 more replies)
  0 siblings, 3 replies; 80+ messages in thread
From: Patrick McHardy @ 2015-11-25 15:06 UTC (permalink / raw)
  To: Florian Westphal; +Cc: Pablo Neira Ayuso, netfilter-devel

[-- Attachment #1: Type: text/plain, Size: 3455 bytes --]

On 24.11, Patrick McHardy wrote:
> Sounds good. I'm having first success decoding headers using the nft internal
> protocol structure. Needs more refinement but I expect to have a RFC later
> today.

Just FYI, this is my current approach. Still WIP, just so you get the idea,
in case you'd like to add some comments.

Basically for the headers, we allocate a constant expression using the
header data, based on the hook and (not correctly done so far) ethertype
we set up the proto ctx and start expanding the payload expression.

This allows us to decode all the protocols nft knows of.

For things like mark and interfaces we do something quite similar, we
allocate the corresponding meta match and dump that.

All together this results in a quite small amount of code and reuses the
parts we have.

The current downside is mainly the output ordering and verbosity:

The ordering corresponds to the ordering of the header fields, f.i.:

trace id 85898000 ip ip length 60 ip id 220 ip ttl 64 ip protocol tcp ip saddr 192.168.122.1 ip daddr 192.168.122.84 tcp sport 39558 tcp dport 10000 iif ens3 
trace id 85898000 ip filter input verdict 4294967295 iif ens3 
trace id 85898000 rule tcp dport 10000 nftrace set 1 
trace id 85898000 ip filter input verdict 4294967295 iif ens3 
trace id 85898000 rule tcp dport 10000 counter packets 79 bytes 4740 
trace id 85898000 ip filter input verdict 4294967295 iif ens3 
trace id 85898000 rule tcp dport 10000 continue 
trace id 85898000 ip filter input verdict 4294967295 mark 0x00000001 iif ens3 
trace id 85898000 rule tcp dport 10000 mark set 0x00000001 
trace id 85898000 ip filter input verdict 1 mark 0x00000001 iif ens3 

As you can see, the IP addresses are the last two members of the IP header
that are dumped, which is not really ideal for readability. Not sure how
to fix that yet. Any ideas?

The verbosity results out of two things:

By default we dump every field we can decode. For testing purposes I included
a filter in the IPv4 header, so certain fields are skipped. A positive list
would also be possible but I've chosen this one so by default we will get
everything.

The second part is the we output normal nft expressions, so "ip" is repeated
for every header field. Would be easy to surpress that, I'm not sure since
the upside is that the expressions can be easily copy and pasted into the
ruleset if necessary.

I've also tested with ARP, a couple of fixed were necessary and I've added
some members to the ARP definitions for MAC and IP decoding. This is of course
not 100% correct since it simply assumes all ARP is related to these protocols:

trace id 85898200 arp ether daddr c9:4b:a9:00:54:52 ether saddr 63:f6:4b:00:54:52 ether type arp arp htype 1 arp ptype ip arp hlen 6 arp plen 4 arp operation reply arp sha 63:f6:4b:00:54:52 arp sip 192.168.122.1 arp tha c9:4b:a9:00:54:52 arp tip 192.168.122.84 iif ens3 
trace id 85898200 arp filter input verdict 4294967295 iif ens3 
trace id 85898200 rule nftrace set 1 
trace id 85898200 arp filter input verdict 4294967295 mark 0x00000001 iif ens3 
trace id 85898200 rule mark set 0x00000001 counter packets 599 bytes 27554 
trace id 85898200 arp filter input verdict 4294967295 mark 0x00000001 iif ens3 
trace id 85898200 rule mark 0x00000001 counter packets 599 bytes 27554 
trace id 85898200 arp filter input verdict 1 mark 0x00000001 iif ens3

Comments welcome, especially regarding the current limitations we have.

Cheers,
Patrick

[-- Attachment #2: x.diff --]
[-- Type: text/plain, Size: 7605 bytes --]

diff --git a/include/proto.h b/include/proto.h
index a43bf98..fa8ff8c 100644
--- a/include/proto.h
+++ b/include/proto.h
@@ -78,6 +78,7 @@ struct proto_desc {
 	enum proto_bases		base;
 	unsigned int			protocol_key;
 	unsigned int			length;
+	unsigned int			filter;
 	struct {
 		unsigned int			num;
 		const struct proto_desc		*desc;
@@ -170,6 +171,10 @@ enum arp_hdr_fields {
 	ARPHDR_HLN,
 	ARPHDR_PLN,
 	ARPHDR_OP,
+	ARPHDR_SHA,
+	ARPHDR_SPA,
+	ARPHDR_THA,
+	ARPHDR_TPA,
 };
 
 enum ip_hdr_fields {
diff --git a/src/netlink.c b/src/netlink.c
index 8ab7bbe..90665fb 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -2165,19 +2165,79 @@ static void trace_print_rule(const struct nftnl_trace *nlt)
 	}
 }
 
-static void trace_print_if(const struct nftnl_trace *nlt, uint16_t attr, const char *str)
+static void trace_print_hdr(struct proto_ctx *ctx,
+			    const struct nftnl_trace *nlt,
+			    unsigned int attr, unsigned int lvl)
 {
-	char __name[IFNAMSIZ];
-	const char *ifname;
+	struct list_head list = LIST_HEAD_INIT(list);
+	struct expr *rel, *lhs, *rhs, *tmp, *next;
+	const void *hdr;
+	uint32_t hlen;
+	unsigned int n;
 
-        if (!nftnl_trace_is_set(nlt, attr))
+	if (!nftnl_trace_is_set(nlt, attr))
 		return;
 
-	ifname = nft_if_indextoname(nftnl_trace_get_u32(nlt, attr), __name);
-	if (ifname)
-		printf(" %s %s", str, ifname);
-	else
-		printf(" %s %d", str, nftnl_trace_get_u32(nlt, attr));
+	hdr = nftnl_trace_get_data(nlt, attr, &hlen);
+	lhs = payload_expr_alloc(&netlink_location, NULL, 0);
+	payload_init_raw(lhs, lvl, 0, hlen * BITS_PER_BYTE);
+
+	rhs = constant_expr_alloc(&netlink_location,
+				  &invalid_type, BYTEORDER_INVALID,
+				  hlen * BITS_PER_BYTE, hdr);
+
+	payload_expr_expand(&list, lhs, NULL, ctx);
+	list_for_each_entry_safe(lhs, next, &list, list) {
+		tmp = constant_expr_splice(rhs, lhs->len);
+		expr_set_type(tmp, lhs->dtype, lhs->byteorder);
+
+		rel = relational_expr_alloc(&lhs->location, OP_EQ, lhs, tmp);
+		lhs->ops->pctx_update(ctx, rel);
+
+		if (lhs->dtype == &invalid_type)
+			goto next;
+		n = lhs->payload.tmpl - lhs->payload.desc->templates;
+		if (lhs->payload.desc->filter & (1 << n))
+			goto next;
+
+		expr_print(rel);
+		printf(" ");
+next:
+		expr_free(rel);
+	}
+}
+
+static void trace_print_packet(const struct nftnl_trace *nlt)
+{
+	struct proto_ctx ctx;
+
+	proto_ctx_init(&ctx, nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY));
+	// NFTA_TRACE_DEV_TYPE
+	proto_ctx_update(&ctx, PROTO_BASE_LL_HDR, &internal_location, &proto_eth);
+	trace_print_hdr(&ctx, nlt, NFTNL_TRACE_LL_HEADER,
+			PROTO_BASE_LL_HDR);
+	trace_print_hdr(&ctx, nlt, NFTNL_TRACE_NETWORK_HEADER,
+			PROTO_BASE_NETWORK_HDR);
+	trace_print_hdr(&ctx, nlt, NFTNL_TRACE_TRANSPORT_HEADER,
+			PROTO_BASE_TRANSPORT_HDR);
+}
+
+static struct expr *trace_alloc_expr(const struct nftnl_trace *nlt,
+				     unsigned int attr,
+				     struct expr *lhs)
+{
+	struct expr *rhs, *rel;
+	const void *data;
+	uint32_t len;
+
+	data = nftnl_trace_get_data(nlt, attr, &len);
+	rhs  = constant_expr_alloc(&netlink_location,
+				   lhs->dtype, lhs->byteorder,
+				   len * BITS_PER_BYTE, data);
+	rel = relational_expr_alloc(&netlink_location, OP_EQ, lhs, rhs);
+	expr_print(rel);
+	printf(" ");
+	return rel;
 }
 
 static int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type,
@@ -2194,11 +2254,36 @@ static int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type,
 	if (nftnl_trace_nlmsg_parse(nlh, nlt) < 0)
 		netlink_abi_error();
 
-	printf("trace ");
-	nftnl_trace_fprintf(stdout, nlt, monh->format);
+	printf("trace id %08x ", nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID));
+
+	printf("%s ", family2str(nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY)));
+	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_TABLE))
+		printf("%s ", nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE));
+	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_CHAIN))
+		printf("%s ", nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN));
+
+	// type
+	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_VERDICT))
+		printf("verdict %u ", nftnl_trace_get_u32(nlt, NFTNL_TRACE_VERDICT));
+
+	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_MARK))
+		trace_alloc_expr(nlt, NFTNL_TRACE_MARK,
+			meta_expr_alloc(&netlink_location, NFT_META_MARK));
+
+	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_VLAN_TAG))
+		printf("vlan id %u ", nftnl_trace_get_u16(nlt, NFTNL_TRACE_VLAN_TAG));
+
+	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_LL_HEADER) ||
+	    nftnl_trace_is_set(nlt, NFTNL_TRACE_NETWORK_HEADER))
+		trace_print_packet(nlt);
+
+	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_IIF))
+		trace_alloc_expr(nlt, NFTNL_TRACE_IIF,
+			meta_expr_alloc(&netlink_location, NFT_META_IIF));
 
-	trace_print_if(nlt, NFTNL_TRACE_IIF, "iif");
-	trace_print_if(nlt, NFTNL_TRACE_OIF, "oif");
+	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_OIF))
+		trace_alloc_expr(nlt, NFTNL_TRACE_OIF,
+			meta_expr_alloc(&netlink_location, NFT_META_OIF));
 
 	trace_print_rule(nlt);
 	printf("\n");
diff --git a/src/payload.c b/src/payload.c
index b75527a..48fc723 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -397,6 +397,7 @@ void payload_expr_expand(struct list_head *list, struct expr *expr,
 		goto raw;
 	assert(desc->base == expr->payload.base);
 
+restart:
 	for (i = 1; i < array_size(desc->templates); i++) {
 		tmpl = &desc->templates[i];
 		if (tmpl->offset != expr->payload.offset)
@@ -409,6 +410,7 @@ void payload_expr_expand(struct list_head *list, struct expr *expr,
 			expr->payload.offset += tmpl->len;
 			if (expr->len == off)
 				return;
+			goto restart;
 		} else
 			break;
 	}
diff --git a/src/proto.c b/src/proto.c
index 28b93cb..88999a9 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -503,6 +503,11 @@ const struct proto_desc proto_ip = {
 		PROTO_LINK(IPPROTO_DCCP,	&proto_dccp),
 		PROTO_LINK(IPPROTO_SCTP,	&proto_sctp),
 	},
+	.filter		= (1 << IPHDR_VERSION) |
+			  (1 << IPHDR_HDRLENGTH) |
+			  (1 << IPHDR_TOS) |
+			  (1 << IPHDR_FRAG_OFF) |
+			  (1 << IPHDR_CHECKSUM),
 	.templates	= {
 		[IPHDR_VERSION]		= HDR_BITFIELD("version", &integer_type, 4, 4),
 		[IPHDR_HDRLENGTH]	= HDR_BITFIELD("hdrlength", &integer_type, 0, 4),
@@ -663,13 +668,13 @@ const struct proto_desc proto_inet_service = {
 
 static const struct symbol_table arpop_tbl = {
 	.symbols	= {
-		SYMBOL("request",	ARPOP_REQUEST),
-		SYMBOL("reply",		ARPOP_REPLY),
-		SYMBOL("rrequest",	ARPOP_RREQUEST),
-		SYMBOL("rreply",	ARPOP_RREPLY),
-		SYMBOL("inrequest",	ARPOP_InREQUEST),
-		SYMBOL("inreply",	ARPOP_InREPLY),
-		SYMBOL("nak",		ARPOP_NAK),
+		SYMBOL("request",	__constant_htons(ARPOP_REQUEST)),
+		SYMBOL("reply",		__constant_htons(ARPOP_REPLY)),
+		SYMBOL("rrequest",	__constant_htons(ARPOP_RREQUEST)),
+		SYMBOL("rreply",	__constant_htons(ARPOP_RREPLY)),
+		SYMBOL("inrequest",	__constant_htons(ARPOP_InREQUEST)),
+		SYMBOL("inreply",	__constant_htons(ARPOP_InREPLY)),
+		SYMBOL("nak",		__constant_htons(ARPOP_NAK)),
 		SYMBOL_LIST_END
 	},
 };
@@ -698,6 +703,10 @@ const struct proto_desc proto_arp = {
 		[ARPHDR_HLN]		= ARPHDR_FIELD("hlen", ar_hln),
 		[ARPHDR_PLN]		= ARPHDR_FIELD("plen", ar_pln),
 		[ARPHDR_OP]		= ARPHDR_TYPE("operation", &arpop_type, ar_op),
+		[ARPHDR_SHA]		= PROTO_HDR_TEMPLATE("sha", &etheraddr_type, BYTEORDER_BIG_ENDIAN, 8 * BITS_PER_BYTE, 6 * BITS_PER_BYTE),
+		[ARPHDR_SPA]		= PROTO_HDR_TEMPLATE("sip", &ipaddr_type, BYTEORDER_BIG_ENDIAN, 14 * BITS_PER_BYTE, 4 * BITS_PER_BYTE),
+		[ARPHDR_THA]		= PROTO_HDR_TEMPLATE("tha", &etheraddr_type, BYTEORDER_BIG_ENDIAN, 18 * BITS_PER_BYTE, 6 * BITS_PER_BYTE),
+		[ARPHDR_TPA]		= PROTO_HDR_TEMPLATE("tip", &ipaddr_type, BYTEORDER_BIG_ENDIAN, 24 * BITS_PER_BYTE, 4 * BITS_PER_BYTE),
 	},
 };
 

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 15:06                       ` Patrick McHardy
@ 2015-11-25 16:23                         ` Pablo Neira Ayuso
  2015-11-25 16:34                           ` Patrick McHardy
  2015-11-25 16:24                         ` Florian Westphal
  2015-11-25 16:49                         ` Jan Engelhardt
  2 siblings, 1 reply; 80+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-25 16:23 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, netfilter-devel

On Wed, Nov 25, 2015 at 03:06:40PM +0000, Patrick McHardy wrote:
> @@ -698,6 +703,10 @@ const struct proto_desc proto_arp = {
>  		[ARPHDR_HLN]		= ARPHDR_FIELD("hlen", ar_hln),
>  		[ARPHDR_PLN]		= ARPHDR_FIELD("plen", ar_pln),
>  		[ARPHDR_OP]		= ARPHDR_TYPE("operation", &arpop_type, ar_op),
> +		[ARPHDR_SHA]		= PROTO_HDR_TEMPLATE("sha", &etheraddr_type, BYTEORDER_BIG_ENDIAN, 8 * BITS_PER_BYTE, 6 * BITS_PER_BYTE),
> +		[ARPHDR_SPA]		= PROTO_HDR_TEMPLATE("sip", &ipaddr_type, BYTEORDER_BIG_ENDIAN, 14 * BITS_PER_BYTE, 4 * BITS_PER_BYTE),
> +		[ARPHDR_THA]		= PROTO_HDR_TEMPLATE("tha", &etheraddr_type, BYTEORDER_BIG_ENDIAN, 18 * BITS_PER_BYTE, 6 * BITS_PER_BYTE),
> +		[ARPHDR_TPA]		= PROTO_HDR_TEMPLATE("tip", &ipaddr_type, BYTEORDER_BIG_ENDIAN, 24 * BITS_PER_BYTE, 4 * BITS_PER_BYTE),
>  	},
>  };
>  

Could you also push this chunk into the repository?

I have a similar patch here for this. Given that we only support ARP
for IPv4, we don't have to worry about the variable length offset in
this case.

Thanks.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 15:06                       ` Patrick McHardy
  2015-11-25 16:23                         ` Pablo Neira Ayuso
@ 2015-11-25 16:24                         ` Florian Westphal
  2015-11-25 16:46                           ` Patrick McHardy
  2015-11-25 16:49                         ` Jan Engelhardt
  2 siblings, 1 reply; 80+ messages in thread
From: Florian Westphal @ 2015-11-25 16:24 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, Pablo Neira Ayuso, netfilter-devel

Patrick McHardy <kaber@trash.net> wrote:
> On 24.11, Patrick McHardy wrote:
> > Sounds good. I'm having first success decoding headers using the nft internal
> > protocol structure. Needs more refinement but I expect to have a RFC later
> > today.
> 
> Just FYI, this is my current approach. Still WIP, just so you get the idea,
> in case you'd like to add some comments.
> 
> Basically for the headers, we allocate a constant expression using the
> header data, based on the hook and (not correctly done so far) ethertype
> we set up the proto ctx and start expanding the payload expression.

[..]

> All together this results in a quite small amount of code and reuses the
> parts we have.

Indeed.

> The current downside is mainly the output ordering and verbosity:
> 
> The ordering corresponds to the ordering of the header fields, f.i.:
> 
> trace id 85898000 ip ip length 60 ip id 220 ip ttl 64 ip protocol tcp ip saddr 192.168.122.1 ip daddr 192.168.122.84 tcp sport 39558 tcp dport 10000 iif ens3 
> trace id 85898000 ip filter input verdict 4294967295 iif ens3 
> trace id 85898000 rule tcp dport 10000 nftrace set 1 
> trace id 85898000 ip filter input verdict 4294967295 iif ens3 
> trace id 85898000 rule tcp dport 10000 counter packets 79 bytes 4740 
> trace id 85898000 ip filter input verdict 4294967295 iif ens3 
> trace id 85898000 rule tcp dport 10000 continue 
> trace id 85898000 ip filter input verdict 4294967295 mark 0x00000001 iif ens3 
> trace id 85898000 rule tcp dport 10000 mark set 0x00000001 
> trace id 85898000 ip filter input verdict 1 mark 0x00000001 iif ens3 
> 
> As you can see, the IP addresses are the last two members of the IP header
> that are dumped, which is not really ideal for readability. Not sure how
> to fix that yet. Any ideas?

Hmm, I think it actually increases readability, as all the other lines
you quoted above are a lot shorter the ip saddr part is a lot more
visible.

If nftrace netfilter rules are used properly (ie., with limit statement
or other means to narrow matching down) those long lines even sever as
kind-of delimiter to where a new round of trace output starts without
looking at the id.

As wrt. fixing it, I don't think this should be over-engineered.

I would propose to annotate the address fields in the protocol
description, similar to the filter you added, and then walk
header several times.

1st round dumps source address
2nd round dumps dst address
3rd round dumps the next protocol field
4th round dumps the rest that isn't 'blacklisted' (such as checksum).

Ugly, but given headers differ completely I don't see a better
solution.
Since headers are commonly small the overhead should not be
a big deal.

In case of ethernet, dst is first header field -- not sure if
we should re-order it so that src a:b.. dst d: .. is shown.

If you prefer to keep the real header ordering, then we don't
need to differentiate between these two.

> Comments welcome, especially regarding the current limitations we have.

Looks fantastic, I am leaning towards dropping the header formatting
from libnftl patch entirely.

> +	if (!nftnl_trace_is_set(nlt, attr))
>  		return;

Eeek, sorry about that.

> +static void trace_print_packet(const struct nftnl_trace *nlt)
> +{
> +	struct proto_ctx ctx;
> +
> +	proto_ctx_init(&ctx, nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY));
> +	// NFTA_TRACE_DEV_TYPE

This attribute should be exported already.

The limitation (same as with my patch) is that if we don't know the
value then we cannot pretty-print that L2 header.
I don't think thats a problem, we can just move on to NH.

> +static struct expr *trace_alloc_expr(const struct nftnl_trace *nlt,
> +				     unsigned int attr,
> +				     struct expr *lhs)
> +{
> +	struct expr *rhs, *rel;
> +	const void *data;
> +	uint32_t len;
> +
> +	data = nftnl_trace_get_data(nlt, attr, &len);
> +	rhs  = constant_expr_alloc(&netlink_location,
> +				   lhs->dtype, lhs->byteorder,
> +				   len * BITS_PER_BYTE, data);
> +	rel = relational_expr_alloc(&netlink_location, OP_EQ, lhs, rhs);
> +	expr_print(rel);
> +	printf(" ");
> +	return rel;
>  }
>  
>  static int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type,
> @@ -2194,11 +2254,36 @@ static int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type,
>  	if (nftnl_trace_nlmsg_parse(nlh, nlt) < 0)
>  		netlink_abi_error();
>  
> -	printf("trace ");
> -	nftnl_trace_fprintf(stdout, nlt, monh->format);
> +	printf("trace id %08x ", nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID));
> +
> +	printf("%s ", family2str(nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY)));
> +	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_TABLE))
> +		printf("%s ", nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE));
> +	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_CHAIN))
> +		printf("%s ", nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN));
> +
> +	// type
> +	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_VERDICT))
> +		printf("verdict %u ", nftnl_trace_get_u32(nlt, NFTNL_TRACE_VERDICT));

I am working on this.

Dissecting the verdict will happen in libnftnl, so NFTNL_TRACE_VERDICT will return
a verdict without extra information.

I'll add NFTNL_TRACE_NFQUEUE_ID to store the upper 16 bits for QUEUE verdicts.

> diff --git a/src/proto.c b/src/proto.c
> index 28b93cb..88999a9 100644
> --- a/src/proto.c
> +++ b/src/proto.c
> @@ -503,6 +503,11 @@ const struct proto_desc proto_ip = {
>  		PROTO_LINK(IPPROTO_DCCP,	&proto_dccp),
>  		PROTO_LINK(IPPROTO_SCTP,	&proto_sctp),
>  	},
> +	.filter		= (1 << IPHDR_VERSION) |
> +			  (1 << IPHDR_HDRLENGTH) |
> +			  (1 << IPHDR_TOS) |
> +			  (1 << IPHDR_FRAG_OFF) |
> +			  (1 << IPHDR_CHECKSUM),

Good that we suppress checksum, it will cause lot of confusion
due to offloads anyway.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 16:23                         ` Pablo Neira Ayuso
@ 2015-11-25 16:34                           ` Patrick McHardy
  0 siblings, 0 replies; 80+ messages in thread
From: Patrick McHardy @ 2015-11-25 16:34 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: Florian Westphal, netfilter-devel

On 25.11, Pablo Neira Ayuso wrote:
> On Wed, Nov 25, 2015 at 03:06:40PM +0000, Patrick McHardy wrote:
> > @@ -698,6 +703,10 @@ const struct proto_desc proto_arp = {
> >  		[ARPHDR_HLN]		= ARPHDR_FIELD("hlen", ar_hln),
> >  		[ARPHDR_PLN]		= ARPHDR_FIELD("plen", ar_pln),
> >  		[ARPHDR_OP]		= ARPHDR_TYPE("operation", &arpop_type, ar_op),
> > +		[ARPHDR_SHA]		= PROTO_HDR_TEMPLATE("sha", &etheraddr_type, BYTEORDER_BIG_ENDIAN, 8 * BITS_PER_BYTE, 6 * BITS_PER_BYTE),
> > +		[ARPHDR_SPA]		= PROTO_HDR_TEMPLATE("sip", &ipaddr_type, BYTEORDER_BIG_ENDIAN, 14 * BITS_PER_BYTE, 4 * BITS_PER_BYTE),
> > +		[ARPHDR_THA]		= PROTO_HDR_TEMPLATE("tha", &etheraddr_type, BYTEORDER_BIG_ENDIAN, 18 * BITS_PER_BYTE, 6 * BITS_PER_BYTE),
> > +		[ARPHDR_TPA]		= PROTO_HDR_TEMPLATE("tip", &ipaddr_type, BYTEORDER_BIG_ENDIAN, 24 * BITS_PER_BYTE, 4 * BITS_PER_BYTE),
> >  	},
> >  };
> >  
> 
> Could you also push this chunk into the repository?
> 
> I have a similar patch here for this. Given that we only support ARP
> for IPv4, we don't have to worry about the variable length offset in
> this case.

Sure. So far I've only added the decoding part, so the parser has no way
to support this yet. The symbol names are quite ugly, any ideas for nicer
ones?

Cheers,
Patrick

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 16:24                         ` Florian Westphal
@ 2015-11-25 16:46                           ` Patrick McHardy
  2015-11-25 17:32                             ` Patrick McHardy
                                               ` (2 more replies)
  0 siblings, 3 replies; 80+ messages in thread
From: Patrick McHardy @ 2015-11-25 16:46 UTC (permalink / raw)
  To: Florian Westphal; +Cc: Pablo Neira Ayuso, netfilter-devel

On 25.11, Florian Westphal wrote:
> Patrick McHardy <kaber@trash.net> wrote:
> > The ordering corresponds to the ordering of the header fields, f.i.:
> > 
> > trace id 85898000 ip ip length 60 ip id 220 ip ttl 64 ip protocol tcp ip saddr 192.168.122.1 ip daddr 192.168.122.84 tcp sport 39558 tcp dport 10000 iif ens3 
> > trace id 85898000 ip filter input verdict 4294967295 iif ens3 
> > trace id 85898000 rule tcp dport 10000 nftrace set 1 
> > trace id 85898000 ip filter input verdict 4294967295 iif ens3 
> > trace id 85898000 rule tcp dport 10000 counter packets 79 bytes 4740 
> > trace id 85898000 ip filter input verdict 4294967295 iif ens3 
> > trace id 85898000 rule tcp dport 10000 continue 
> > trace id 85898000 ip filter input verdict 4294967295 mark 0x00000001 iif ens3 
> > trace id 85898000 rule tcp dport 10000 mark set 0x00000001 
> > trace id 85898000 ip filter input verdict 1 mark 0x00000001 iif ens3 
> > 
> > As you can see, the IP addresses are the last two members of the IP header
> > that are dumped, which is not really ideal for readability. Not sure how
> > to fix that yet. Any ideas?
> 
> Hmm, I think it actually increases readability, as all the other lines
> you quoted above are a lot shorter the ip saddr part is a lot more
> visible.

They are actually still missing some minor parts from the original output :)

But if we want to shorten them, I would suggest f.i. to not repeat the
devices on every line. It seems to logically belong to the "packet" part,
same as vlan id. I guess the only thing we actually need to repeat is the
mark since that might change while we're within the ruleset.

> If nftrace netfilter rules are used properly (ie., with limit statement
> or other means to narrow matching down) those long lines even sever as
> kind-of delimiter to where a new round of trace output starts without
> looking at the id.

I agree, that part makes for a good delimiter.

> As wrt. fixing it, I don't think this should be over-engineered.
> 
> I would propose to annotate the address fields in the protocol
> description, similar to the filter you added, and then walk
> header several times.
> 
> 1st round dumps source address
> 2nd round dumps dst address
> 3rd round dumps the next protocol field
> 4th round dumps the rest that isn't 'blacklisted' (such as checksum).
> 
> Ugly, but given headers differ completely I don't see a better
> solution.
> Since headers are commonly small the overhead should not be
> a big deal.

I've also considered this and so far it was my favourite approach as
well. Unfortunately it requires annotations for all headers, but I guess
that's an acceptable tradeoff.

> In case of ethernet, dst is first header field -- not sure if
> we should re-order it so that src a:b.. dst d: .. is shown.
> 
> If you prefer to keep the real header ordering, then we don't
> need to differentiate between these two.

I personally generally prefer what I perceive as "logical ordering", which
is src, dst, ....

> > Comments welcome, especially regarding the current limitations we have.
> 
> Looks fantastic, I am leaning towards dropping the header formatting
> from libnftl patch entirely.

I agree, we could drop the header part and only print the meta data. So we
can see that something is happening and associate the events with decoded
messages, but full decoding seems unnecessary.

> > +	if (!nftnl_trace_is_set(nlt, attr))
> >  		return;
> 
> Eeek, sorry about that.
> 
> > +static void trace_print_packet(const struct nftnl_trace *nlt)
> > +{
> > +	struct proto_ctx ctx;
> > +
> > +	proto_ctx_init(&ctx, nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY));
> > +	// NFTA_TRACE_DEV_TYPE
> 
> This attribute should be exported already.

Yep, I just didn't integrate it properly yet.

> The limitation (same as with my patch) is that if we don't know the
> value then we cannot pretty-print that L2 header.
> I don't think thats a problem, we can just move on to NH.

It depends, f.i. for bridging we can infer it from the hook values. In fact
proto_ctx_init() already does that correctly for bridging.

> > +	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_VERDICT))
> > +		printf("verdict %u ", nftnl_trace_get_u32(nlt, NFTNL_TRACE_VERDICT));
> 
> I am working on this.
> 
> Dissecting the verdict will happen in libnftnl, so NFTNL_TRACE_VERDICT will return
> a verdict without extra information.
> 
> I'll add NFTNL_TRACE_NFQUEUE_ID to store the upper 16 bits for QUEUE verdicts.

I don't think that's necessary. All the other verdict parts (actually nft_data)
simply return the numeric verdict code and also accept them, both for encoded
DROP_ERRNOS and queue numbers. Is there any reason to diverge from this?

Thanks for your feedback. I'll start incorporating it now.

Cheers,
Patrick

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 15:06                       ` Patrick McHardy
  2015-11-25 16:23                         ` Pablo Neira Ayuso
  2015-11-25 16:24                         ` Florian Westphal
@ 2015-11-25 16:49                         ` Jan Engelhardt
  2015-11-25 16:53                           ` Patrick McHardy
  2 siblings, 1 reply; 80+ messages in thread
From: Jan Engelhardt @ 2015-11-25 16:49 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, Pablo Neira Ayuso, netfilter-devel


On Wednesday 2015-11-25 16:06, Patrick McHardy wrote:
>
>trace id 85898000 ip ip length 60 ip id 220 ip ttl 64 ip protocol tcp ip saddr 192.168.122.1 ip daddr 192.168.122.84 tcp sport 39558 tcp dport 10000 iif ens3 
>[...]
>The second part is the we output normal nft expressions, so "ip" is repeated
>for every header field. [...] the upside is that the expressions can be
>easily copy and pasted into the ruleset if necessary.

"ip ip" looks a bit of out of place. To illustrate,

	ip && ip.length==60 && ip.id==220 && ...

is what the rule seems to mean. However, it is also conceivable that
someone (who does not have the full knowledge as the .y parser does)
will read it as

	ip.ip.length==60 && ip.id==220 ...

and might wonder if that is some magic sauce to test the inside header of an
IPIP packet. Altogether, this causes the nft syntax to remain more confusing
than the classic iptables one where the &&-segmentation points are reasonably
known.


>trace id 85898200 arp filter input verdict 1 mark 0x00000001 iif ens3
>
>Comments welcome, especially regarding the current limitations we have.

I do not think that the far-right printing of IP addresses in the trace output
is a big deal. Even the iptables TRACE mechanism ends up showing the IP address
past column 80:

[239310.214731] TRACE: mangle:INPUT:policy:1 IN=wl0 OUT=
MAC=7c:7a:91:30:84:cd:18:83:bf:2d:7e:20:08:00 SRC=46.4.122.207
DST=192.168.217.18 LEN=88 TOS=0x00 PREC=0x00 TTL=56 ID=42841 DF PROTO=TCP
SPT=22 DPT=34572 SEQ=1941015595 ACK=2361189253 WINDOW=1382 RES=0x00 ACK PSH
URGP=0 OPT (0101080A0B6162F1038FDA1F) UID=25121 GID=100 

(add syslog timestamps in front for added effect).
And perhaps, to a particular reader, the L4 information - which is even
more right-shifted in both ipt and nft trace - may be more important
than the L3 part.

What I think is a doable way is to output the rule in evaluation order -
basically, the way it was input.
If the IP TTL is not that important, perhaps that expression should
have been moved "to the back" when the rule was generated by the
userspace tool before being entered into the kernel.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 16:49                         ` Jan Engelhardt
@ 2015-11-25 16:53                           ` Patrick McHardy
  2015-11-25 17:14                             ` Jan Engelhardt
  0 siblings, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-25 16:53 UTC (permalink / raw)
  To: Jan Engelhardt; +Cc: Florian Westphal, Pablo Neira Ayuso, netfilter-devel

On 25.11, Jan Engelhardt wrote:
> 
> On Wednesday 2015-11-25 16:06, Patrick McHardy wrote:
> >
> >trace id 85898000 ip ip length 60 ip id 220 ip ttl 64 ip protocol tcp ip saddr 192.168.122.1 ip daddr 192.168.122.84 tcp sport 39558 tcp dport 10000 iif ens3 
> >[...]
> >The second part is the we output normal nft expressions, so "ip" is repeated
> >for every header field. [...] the upside is that the expressions can be
> >easily copy and pasted into the ruleset if necessary.
> 
> "ip ip" looks a bit of out of place. To illustrate,
> 
> 	ip && ip.length==60 && ip.id==220 && ...
> 
> is what the rule seems to mean. However, it is also conceivable that
> someone (who does not have the full knowledge as the .y parser does)
> will read it as
> 
> 	ip.ip.length==60 && ip.id==220 ...
> 
> and might wonder if that is some magic sauce to test the inside header of an
> IPIP packet. Altogether, this causes the nft syntax to remain more confusing
> than the classic iptables one where the &&-segmentation points are reasonably
> known.

Its WIP output. It's supposed to read "ip packet", but I agree, I will
certainly not leave it like this.

> >trace id 85898200 arp filter input verdict 1 mark 0x00000001 iif ens3
> >
> >Comments welcome, especially regarding the current limitations we have.
> 
> I do not think that the far-right printing of IP addresses in the trace output
> is a big deal. Even the iptables TRACE mechanism ends up showing the IP address
> past column 80:
> 
> [239310.214731] TRACE: mangle:INPUT:policy:1 IN=wl0 OUT=
> MAC=7c:7a:91:30:84:cd:18:83:bf:2d:7e:20:08:00 SRC=46.4.122.207
> DST=192.168.217.18 LEN=88 TOS=0x00 PREC=0x00 TTL=56 ID=42841 DF PROTO=TCP
> SPT=22 DPT=34572 SEQ=1941015595 ACK=2361189253 WINDOW=1382 RES=0x00 ACK PSH
> URGP=0 OPT (0101080A0B6162F1038FDA1F) UID=25121 GID=100 
> 
> (add syslog timestamps in front for added effect).
> And perhaps, to a particular reader, the L4 information - which is even
> more right-shifted in both ipt and nft trace - may be more important
> than the L3 part.
> 
> What I think is a doable way is to output the rule in evaluation order -
> basically, the way it was input.
> If the IP TTL is not that important, perhaps that expression should
> have been moved "to the back" when the rule was generated by the
> userspace tool before being entered into the kernel.

Its a decoded packet dump, not the rule. The rule is of course output in
evaluation order.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 16:53                           ` Patrick McHardy
@ 2015-11-25 17:14                             ` Jan Engelhardt
  2015-11-25 17:24                               ` Patrick McHardy
  0 siblings, 1 reply; 80+ messages in thread
From: Jan Engelhardt @ 2015-11-25 17:14 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, Pablo Neira Ayuso, netfilter-devel


On Wednesday 2015-11-25 17:53, Patrick McHardy wrote:
>> 
>> What I think is a doable way is to output the rule in evaluation order -
>> basically, the way it was input.
>> If the IP TTL is not that important, perhaps that expression should
>> have been moved "to the back" when the rule was generated by the
>> userspace tool before being entered into the kernel.
>
>Its a decoded packet dump, not the rule.

Would it be possible to make the program which receives the trace over
netlink to take a command-line argument or a filename that specifies
which expressions to preferentially order to the left?
Something like

 trace --fields=ip.saddr,ip.daddr,tcp.dport,ip.ttl,*

(the ,* part being implicit if omitted)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 17:14                             ` Jan Engelhardt
@ 2015-11-25 17:24                               ` Patrick McHardy
  0 siblings, 0 replies; 80+ messages in thread
From: Patrick McHardy @ 2015-11-25 17:24 UTC (permalink / raw)
  To: Jan Engelhardt; +Cc: Florian Westphal, Pablo Neira Ayuso, netfilter-devel

On 25.11, Jan Engelhardt wrote:
> 
> On Wednesday 2015-11-25 17:53, Patrick McHardy wrote:
> >> 
> >> What I think is a doable way is to output the rule in evaluation order -
> >> basically, the way it was input.
> >> If the IP TTL is not that important, perhaps that expression should
> >> have been moved "to the back" when the rule was generated by the
> >> userspace tool before being entered into the kernel.
> >
> >Its a decoded packet dump, not the rule.
> 
> Would it be possible to make the program which receives the trace over
> netlink to take a command-line argument or a filename that specifies
> which expressions to preferentially order to the left?
> Something like
> 
>  trace --fields=ip.saddr,ip.daddr,tcp.dport,ip.ttl,*
> 
> (the ,* part being implicit if omitted)

It sounds like an interesting idea, especially if we omit fields be default.

Let's see:

I defintely don't want to add new lexing and grammar rules for all the
protocols, so the syntax would have to be based on the current expressions.
So it would likely not be a command line option but something which is handled
by the parser:

nft monitor trace decode ip saddr, ip daddr, tcp dport, tcp sequence, *

That should be easy to integrate.

Next question would be how to deal with unspecified protocols or how to
specify preferences for multiple protocols at once. In many address families
and on higher layers we normally don't know what kind of packets we will
receive. It might be preferrable to have an abstract way to specify the
fields of interest, but I'm unable to think of something reasonable.
We might be able to do some grouping, f.i. "l3proto identity" for source
and destination address of any L3 protocol, but many fields are hard to
group.

Alternatively we can of course always apply the default encoding and simply
allow to override it for one specific packet type, like ether + ip + tcp.

Suggestions are welcome.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 16:46                           ` Patrick McHardy
@ 2015-11-25 17:32                             ` Patrick McHardy
  2015-11-25 22:27                               ` Florian Westphal
  2015-11-25 22:52                             ` Florian Westphal
  2015-11-26 10:50                             ` Patrick McHardy
  2 siblings, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-25 17:32 UTC (permalink / raw)
  To: Florian Westphal; +Cc: Pablo Neira Ayuso, netfilter-devel

On 25.11, Patrick McHardy wrote:
> On 25.11, Florian Westphal wrote:
> > Hmm, I think it actually increases readability, as all the other lines
> > you quoted above are a lot shorter the ip saddr part is a lot more
> > visible.
> 
> They are actually still missing some minor parts from the original output :)
> 
> But if we want to shorten them, I would suggest f.i. to not repeat the
> devices on every line. It seems to logically belong to the "packet" part,
> same as vlan id. I guess the only thing we actually need to repeat is the
> mark since that might change while we're within the ruleset.

Actually thinking more about this, we might want to send a new "packet"
message whenever we enter nft_do_chain(). At that point the packet has been
processed by other parts of the network stack since the last "packet"
message and it might be helpful to know in which ways it has changed.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 17:32                             ` Patrick McHardy
@ 2015-11-25 22:27                               ` Florian Westphal
  2015-11-25 23:04                                 ` Patrick McHardy
  2015-11-25 23:42                                 ` Patrick McHardy
  0 siblings, 2 replies; 80+ messages in thread
From: Florian Westphal @ 2015-11-25 22:27 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, Pablo Neira Ayuso, netfilter-devel

Patrick McHardy <kaber@trash.net> wrote:
> On 25.11, Patrick McHardy wrote:
> > On 25.11, Florian Westphal wrote:
> > > Hmm, I think it actually increases readability, as all the other lines
> > > you quoted above are a lot shorter the ip saddr part is a lot more
> > > visible.
> > 
> > They are actually still missing some minor parts from the original output :)
> >
> > But if we want to shorten them, I would suggest f.i. to not repeat the
> > devices on every line. It seems to logically belong to the "packet" part,
> > same as vlan id. I guess the only thing we actually need to repeat is the
> > mark since that might change while we're within the ruleset.

We can do this, but we'll need to make sure that the oif gets printed at
one point (not available in prerouting)...

> Actually thinking more about this, we might want to send a new "packet"
> message whenever we enter nft_do_chain(). At that point the packet has been
> processed by other parts of the network stack since the last "packet"
> message and it might be helpful to know in which ways it has changed.

True, good point.  In that case I would propose to get rid of "packet"
message type completely.

Instead we'd include all the info that we currently have in "packet"
(i.e. vlanid, headers) on the first message type fired on each nft_do_chain()
invocation.

We can also move IIF/OIF info to this 'initial' message
(which might be of any type depending on the ruleset, due to POLICY
 type we would however always send at least one, even if there are no
 matches).

The price to be paid would be a new variable that we have to keep
on-stack to know when we can elide the extra packet data.

Does that sound reasonable?

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 16:46                           ` Patrick McHardy
  2015-11-25 17:32                             ` Patrick McHardy
@ 2015-11-25 22:52                             ` Florian Westphal
  2015-11-25 23:15                               ` Patrick McHardy
  2015-11-26 10:50                             ` Patrick McHardy
  2 siblings, 1 reply; 80+ messages in thread
From: Florian Westphal @ 2015-11-25 22:52 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, Pablo Neira Ayuso, netfilter-devel

Patrick McHardy <kaber@trash.net> wrote:
> > In case of ethernet, dst is first header field -- not sure if
> > we should re-order it so that src a:b.. dst d: .. is shown.
> > 
> > If you prefer to keep the real header ordering, then we don't
> > need to differentiate between these two.
> 
> I personally generally prefer what I perceive as "logical ordering", which
> is src, dst, ....

Same here.

> > Looks fantastic, I am leaning towards dropping the header formatting
> > from libnftl patch entirely.
> 
> I agree, we could drop the header part and only print the meta data. So we
> can see that something is happening and associate the events with decoded
> messages, but full decoding seems unnecessary.

I could also get rid of all formatting of course, i.e. remove the
libnftnl_trace_*printf functions, so libnftnl would just provide
the nftnl_trace struct to nftables frontend and the internal translation
of netlink messages to that struct.

> > The limitation (same as with my patch) is that if we don't know the
> > value then we cannot pretty-print that L2 header.
> > I don't think thats a problem, we can just move on to NH.
> 
> It depends, f.i. for bridging we can infer it from the hook values. In fact
> proto_ctx_init() already does that correctly for bridging.

Yes, this DEV_TYPE attribute is only included for NFPROTO_NETDEV where L2
could be anything ...

> > > +	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_VERDICT))
> > > +		printf("verdict %u ", nftnl_trace_get_u32(nlt, NFTNL_TRACE_VERDICT));
> > 
> > I am working on this.
> > 
> > Dissecting the verdict will happen in libnftnl, so NFTNL_TRACE_VERDICT will return
> > a verdict without extra information.
> > 
> > I'll add NFTNL_TRACE_NFQUEUE_ID to store the upper 16 bits for QUEUE verdicts.
> 
> I don't think that's necessary. All the other verdict parts (actually nft_data)
> simply return the numeric verdict code and also accept them, both for encoded
> DROP_ERRNOS and queue numbers. Is there any reason to diverge from this?

Hmm, to clarify:  The kernel will dump the verdict as-is.
But I don't see why nftables (nft) should have to start dissecting this
to e.g. get the nfqueue number.  So I'd rather put something like the
following into libnftnl and provide accessors for nft rather than
stuff it into the frontend tool:

verdict = mnl_get_ (netlink_data);
switch (verdict) {
case NFT_GOTO:
case NFT_JUMP: t->targetchain = get_target_chain(netlink_data);
case NFT_CONTINUE:
// all other known verdicts here
	trace->verdict = verdict;
	break;
default: /* unknown verdict, or extra data in upper bits */
     switch (verdict & 0xff) {
     case NF_QUEUE:
        trace->verdict = verdict & 0xff;
        trace->queue_id = verdict >> 16;
        break;
     }
 }

Without it, simple tasks like 'translate verdict to string' in nft
require extra exercise to strip away the irrelevant parts of the
verdict code.

Does that seem reasonable?

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 22:27                               ` Florian Westphal
@ 2015-11-25 23:04                                 ` Patrick McHardy
  2015-11-25 23:16                                   ` Florian Westphal
  2015-11-25 23:42                                 ` Patrick McHardy
  1 sibling, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-25 23:04 UTC (permalink / raw)
  To: Florian Westphal; +Cc: Pablo Neira Ayuso, netfilter-devel

On 25.11, Florian Westphal wrote:
> Patrick McHardy <kaber@trash.net> wrote:
> 
> > Actually thinking more about this, we might want to send a new "packet"
> > message whenever we enter nft_do_chain(). At that point the packet has been
> > processed by other parts of the network stack since the last "packet"
> > message and it might be helpful to know in which ways it has changed.
> 
> True, good point.  In that case I would propose to get rid of "packet"
> message type completely.
> 
> Instead we'd include all the info that we currently have in "packet"
> (i.e. vlanid, headers) on the first message type fired on each nft_do_chain()
> invocation.
> 
> We can also move IIF/OIF info to this 'initial' message
> (which might be of any type depending on the ruleset, due to POLICY
>  type we would however always send at least one, even if there are no
>  matches).
> 
> The price to be paid would be a new variable that we have to keep
> on-stack to know when we can elide the extra packet data.
> 
> Does that sound reasonable?

Sure, but is that really easier than including an unconditional (well,
skb->nf_trace == 1) call to nf_tables_trace_notify() before entering
the main loop? I don't see anything wrong the the packet message itself,
just thinking it might be useful to emit one more in this specific
spot.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 22:52                             ` Florian Westphal
@ 2015-11-25 23:15                               ` Patrick McHardy
  2015-11-25 23:19                                 ` Florian Westphal
  0 siblings, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-25 23:15 UTC (permalink / raw)
  To: Florian Westphal; +Cc: Pablo Neira Ayuso, netfilter-devel

[-- Attachment #1: Type: text/plain, Size: 3690 bytes --]

On 25.11, Florian Westphal wrote:
> Patrick McHardy <kaber@trash.net> wrote:
> 
> > > Looks fantastic, I am leaning towards dropping the header formatting
> > > from libnftl patch entirely.
> > 
> > I agree, we could drop the header part and only print the meta data. So we
> > can see that something is happening and associate the events with decoded
> > messages, but full decoding seems unnecessary.
> 
> I could also get rid of all formatting of course, i.e. remove the
> libnftnl_trace_*printf functions, so libnftnl would just provide
> the nftnl_trace struct to nftables frontend and the internal translation
> of netlink messages to that struct.

I think having some printing is useful to trace/debug netlink communication
itself, IOW the basic data. Just the full header decoding seems rather
unnecessary.

> > > The limitation (same as with my patch) is that if we don't know the
> > > value then we cannot pretty-print that L2 header.
> > > I don't think thats a problem, we can just move on to NH.
> > 
> > It depends, f.i. for bridging we can infer it from the hook values. In fact
> > proto_ctx_init() already does that correctly for bridging.
> 
> Yes, this DEV_TYPE attribute is only included for NFPROTO_NETDEV where L2
> could be anything ...

I actually changed that in my local version to include it whenever we have
pkt->in so we can decode ARP using dev_proto_desc(). I'm also including the
LL header whenever present so its now also used for f.i. incoming IPv4/v6
packets:

trace id 847cdc00 ip packet: iif ens3 ether daddr c9:4b:a9:00:54:52 ether saddr 63:f6:4b:00:54:52 ip hdrlength 4 ip version 5 ip tos 16 ip length 60 ip id 44588 ip frag-off 16384 ip ttl 64 ip checksum 5849 ip saddr 192.168.122.1 ip daddr 192.168.122.84 tcp sport 43178 tcp dport 10000

I've attached that change to the mail. At least the DEV_TYPE part is needed
to make sense out of the ARP ll header in a generic way.

> > > > +	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_VERDICT))
> > > > +		printf("verdict %u ", nftnl_trace_get_u32(nlt, NFTNL_TRACE_VERDICT));
> > > 
> > > I am working on this.
> > > 
> > > Dissecting the verdict will happen in libnftnl, so NFTNL_TRACE_VERDICT will return
> > > a verdict without extra information.
> > > 
> > > I'll add NFTNL_TRACE_NFQUEUE_ID to store the upper 16 bits for QUEUE verdicts.
> > 
> > I don't think that's necessary. All the other verdict parts (actually nft_data)
> > simply return the numeric verdict code and also accept them, both for encoded
> > DROP_ERRNOS and queue numbers. Is there any reason to diverge from this?
> 
> Hmm, to clarify:  The kernel will dump the verdict as-is.
> But I don't see why nftables (nft) should have to start dissecting this
> to e.g. get the nfqueue number.  So I'd rather put something like the
> following into libnftnl and provide accessors for nft rather than
> stuff it into the frontend tool:
> 
> verdict = mnl_get_ (netlink_data);
> switch (verdict) {
> case NFT_GOTO:
> case NFT_JUMP: t->targetchain = get_target_chain(netlink_data);
> case NFT_CONTINUE:
> // all other known verdicts here
> 	trace->verdict = verdict;
> 	break;
> default: /* unknown verdict, or extra data in upper bits */
>      switch (verdict & 0xff) {
>      case NF_QUEUE:
>         trace->verdict = verdict & 0xff;
>         trace->queue_id = verdict >> 16;
>         break;
>      }
>  }
> 
> Without it, simple tasks like 'translate verdict to string' in nft
> require extra exercise to strip away the irrelevant parts of the
> verdict code.
> 
> Does that seem reasonable?

Yeah, that seems fine. I though we already did that disection in
verdict_type_print(), but it was in fact only a local change queued
in my tree.

[-- Attachment #2: x.diff --]
[-- Type: text/plain, Size: 1522 bytes --]

diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index e22e929..3a0e22b 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -518,20 +518,9 @@ trace_notify_put_packet(struct sk_buff *nlskb, const struct nft_pktinfo *pkt)
 				   skb, pkt->xt.thoff, plen))
 		return false;
 
-	switch (pkt->pf) {
-	case NFPROTO_ARP: /* fallthrough */
-	case NFPROTO_BRIDGE:
-		break;
-	case NFPROTO_NETDEV:
-		if (WARN_ON_ONCE(!skb->dev))
-			break;
-		if (nla_put_be16(nlskb, NFTA_TRACE_DEV_TYPE,
-				 htons(skb->dev->type)))
-			return false;
-		break;
-	default:
-		return true;
-	}
+	if (pkt->in &&
+	    nla_put_be16(nlskb, NFTA_TRACE_DEV_TYPE, htons(pkt->in->type)))
+		return false;
 
 	if (skb_vlan_tag_get(skb) &&
 	    !nla_put_be16(nlskb, NFTA_TRACE_VLAN_TAG,
@@ -688,6 +677,7 @@ void nf_tables_trace_notify(const struct nft_pktinfo *pkt,
 	WARN_ON_ONCE(1);
 	kfree_skb(skb);
 }
+EXPORT_SYMBOL_GPL(nf_tables_trace_notify);
 
 static int nf_tables_dump_tables(struct sk_buff *skb,
 				 struct netlink_callback *cb)
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
index c2a60ac..9342779 100644
--- a/net/netfilter/nft_meta.c
+++ b/net/netfilter/nft_meta.c
@@ -350,6 +350,7 @@ void nft_meta_set_destroy(const struct nft_ctx *ctx,
 	if (priv->key == NFT_META_NFTRACE)
 		static_key_slow_dec(&nft_trace_enabled);
 }
+EXPORT_SYMBOL_GPL(nft_meta_set_destroy);
 
 static struct nft_expr_type nft_meta_type;
 static const struct nft_expr_ops nft_meta_get_ops = {

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 23:04                                 ` Patrick McHardy
@ 2015-11-25 23:16                                   ` Florian Westphal
  2015-11-25 23:30                                     ` Patrick McHardy
  0 siblings, 1 reply; 80+ messages in thread
From: Florian Westphal @ 2015-11-25 23:16 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, Pablo Neira Ayuso, netfilter-devel

Patrick McHardy <kaber@trash.net> wrote:
> > True, good point.  In that case I would propose to get rid of "packet"
> > message type completely.
> > 
> > Instead we'd include all the info that we currently have in "packet"
> > (i.e. vlanid, headers) on the first message type fired on each nft_do_chain()
> > invocation.
> > 
> > We can also move IIF/OIF info to this 'initial' message
> > (which might be of any type depending on the ruleset, due to POLICY
> >  type we would however always send at least one, even if there are no
> >  matches).
> > 
> > The price to be paid would be a new variable that we have to keep
> > on-stack to know when we can elide the extra packet data.
> > 
> > Does that sound reasonable?
> 
> Sure, but is that really easier than including an unconditional (well,
> skb->nf_trace == 1) call to nf_tables_trace_notify() before entering
> the main loop? I don't see anything wrong the the packet message itself,
> just thinking it might be useful to emit one more in this specific
> spot.

Its not easier, but it will keep the number of messages lower.

AFAIU with nf_tables_trace_notify() for each nft_do_chain() we will
have one more message for each table/hook combo...  Hmm...

I I'll see how painful the extra test for 'i have sent packet data
for this nft_do_chain invocation' is, if its too complicated
I'll move the nf_tables_trace_notify from nft_meta to nft_do_chain.

Let me know in case you spot a problem with that rationale.

Thanks!

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 23:15                               ` Patrick McHardy
@ 2015-11-25 23:19                                 ` Florian Westphal
  0 siblings, 0 replies; 80+ messages in thread
From: Florian Westphal @ 2015-11-25 23:19 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, Pablo Neira Ayuso, netfilter-devel

Patrick McHardy <kaber@trash.net> wrote:
> On 25.11, Florian Westphal wrote:
> > I could also get rid of all formatting of course, i.e. remove the
> > libnftnl_trace_*printf functions, so libnftnl would just provide
> > the nftnl_trace struct to nftables frontend and the internal translation
> > of netlink messages to that struct.
> 
> I think having some printing is useful to trace/debug netlink communication
> itself, IOW the basic data. Just the full header decoding seems rather
> unnecessary.

Okay.

> > Yes, this DEV_TYPE attribute is only included for NFPROTO_NETDEV where L2
> > could be anything ...
> 
> I actually changed that in my local version to include it whenever we have
> pkt->in so we can decode ARP using dev_proto_desc(). I'm also including the
> LL header whenever present so its now also used for f.i. incoming IPv4/v6
> packets:
> 
> trace id 847cdc00 ip packet: iif ens3 ether daddr c9:4b:a9:00:54:52 ether saddr 63:f6:4b:00:54:52 ip hdrlength 4 ip version 5 ip tos 16 ip length 60 ip id 44588 ip frag-off 16384 ip ttl 64 ip checksum 5849 ip saddr 192.168.122.1 ip daddr 192.168.122.84 tcp sport 43178 tcp dport 10000
> 
> I've attached that change to the mail. At least the DEV_TYPE part is needed
> to make sense out of the ARP ll header in a generic way.

I see, thanks!

> +	if (pkt->in &&
> +	    nla_put_be16(nlskb, NFTA_TRACE_DEV_TYPE, htons(pkt->in->type)))
> +		return false;

Yes, much better.  Thanks Patrick!

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 23:16                                   ` Florian Westphal
@ 2015-11-25 23:30                                     ` Patrick McHardy
  0 siblings, 0 replies; 80+ messages in thread
From: Patrick McHardy @ 2015-11-25 23:30 UTC (permalink / raw)
  To: Florian Westphal; +Cc: Pablo Neira Ayuso, netfilter-devel

On 26.11, Florian Westphal wrote:
> Patrick McHardy <kaber@trash.net> wrote:
> > > True, good point.  In that case I would propose to get rid of "packet"
> > > message type completely.
> > > 
> > > Instead we'd include all the info that we currently have in "packet"
> > > (i.e. vlanid, headers) on the first message type fired on each nft_do_chain()
> > > invocation.
> > > 
> > > We can also move IIF/OIF info to this 'initial' message
> > > (which might be of any type depending on the ruleset, due to POLICY
> > >  type we would however always send at least one, even if there are no
> > >  matches).
> > > 
> > > The price to be paid would be a new variable that we have to keep
> > > on-stack to know when we can elide the extra packet data.
> > > 
> > > Does that sound reasonable?
> > 
> > Sure, but is that really easier than including an unconditional (well,
> > skb->nf_trace == 1) call to nf_tables_trace_notify() before entering
> > the main loop? I don't see anything wrong the the packet message itself,
> > just thinking it might be useful to emit one more in this specific
> > spot.
> 
> Its not easier, but it will keep the number of messages lower.
> 
> AFAIU with nf_tables_trace_notify() for each nft_do_chain() we will
> have one more message for each table/hook combo...  Hmm...

Yeah that's really a bit unfortunate since we actually only care about the
first chain on every hook I guess. Basically once per hook, but it seems we
really need to use once per base chain unless we go deeper down in the stack.

> I I'll see how painful the extra test for 'i have sent packet data
> for this nft_do_chain invocation' is, if its too complicated
> I'll move the nf_tables_trace_notify from nft_meta to nft_do_chain.
> 
> Let me know in case you spot a problem with that rationale.

No, that seems reasonable to me.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 22:27                               ` Florian Westphal
  2015-11-25 23:04                                 ` Patrick McHardy
@ 2015-11-25 23:42                                 ` Patrick McHardy
  2015-11-25 23:56                                   ` Florian Westphal
  1 sibling, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-25 23:42 UTC (permalink / raw)
  To: Florian Westphal; +Cc: Pablo Neira Ayuso, netfilter-devel

On 25.11, Florian Westphal wrote:
> Patrick McHardy <kaber@trash.net> wrote:
> 
> > Actually thinking more about this, we might want to send a new "packet"
> > message whenever we enter nft_do_chain(). At that point the packet has been
> > processed by other parts of the network stack since the last "packet"
> > message and it might be helpful to know in which ways it has changed.
> 
> True, good point.  In that case I would propose to get rid of "packet"
> message type completely.
> 
> Instead we'd include all the info that we currently have in "packet"
> (i.e. vlanid, headers) on the first message type fired on each nft_do_chain()
> invocation.

One more comment since I'm just in the VLAN area: I think we need to include
the full vlan_tci and vlan_proto. Basically we want to be able to display
a dummy VLAN header I'd say instead of treating it like something special.

Even nicer would be to include the dummy VLAN header in the payload itself
and hide the offloading details, but that we can also do in userspace of
course.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 23:42                                 ` Patrick McHardy
@ 2015-11-25 23:56                                   ` Florian Westphal
  0 siblings, 0 replies; 80+ messages in thread
From: Florian Westphal @ 2015-11-25 23:56 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, Pablo Neira Ayuso, netfilter-devel

Patrick McHardy <kaber@trash.net> wrote:
> Even nicer would be to include the dummy VLAN header in the payload itself
> and hide the offloading details, but that we can also do in userspace of
> course.

Will do that.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-25 16:46                           ` Patrick McHardy
  2015-11-25 17:32                             ` Patrick McHardy
  2015-11-25 22:52                             ` Florian Westphal
@ 2015-11-26 10:50                             ` Patrick McHardy
  2015-11-26 11:03                               ` Florian Westphal
  2 siblings, 1 reply; 80+ messages in thread
From: Patrick McHardy @ 2015-11-26 10:50 UTC (permalink / raw)
  To: Florian Westphal; +Cc: Pablo Neira Ayuso, netfilter-devel

[-- Attachment #1: Type: text/plain, Size: 1711 bytes --]

On 25.11, Patrick McHardy wrote:
> On 25.11, Florian Westphal wrote:
> > I would propose to annotate the address fields in the protocol
> > description, similar to the filter you added, and then walk
> > header several times.
> > 
> > 1st round dumps source address
> > 2nd round dumps dst address
> > 3rd round dumps the next protocol field
> > 4th round dumps the rest that isn't 'blacklisted' (such as checksum).
> > 
> > Ugly, but given headers differ completely I don't see a better
> > solution.
> > Since headers are commonly small the overhead should not be
> > a big deal.
> 
> I've also considered this and so far it was my favourite approach as
> well. Unfortunately it requires annotations for all headers, but I guess
> that's an acceptable tradeoff.

Ok here's might current state. I've added an output filter and defined
output ordering, so we can surpress some fields and order the remaining
ones the way we want. I've also added redundant payload dependency
elimination.

Example output looks like this:

trace id 85060d00 arp packet: iif ens3 ether saddr 63:f6:4b:00:54:52 ether daddr c9:4b:a9:00:54:52 arp operation reply arp sha 63:f6:4b:00:54:52 arp sip 192.168.122.1 arp tha c9:4b:a9:00:54:52 arp tip 192.168.122.84

trace id 853ff400 ip packet: iif ens3 ether saddr 63:f6:4b:00:54:52 ether daddr c9:4b:a9:00:54:52 ip saddr 192.168.122.1 ip daddr 192.168.122.84 ip tos 16 ip ttl 64 ip id 38325 ip length 60 tcp sport 46156 tcp dport 10000

trace id 853ffc00 ip packet: oif ens3 ip saddr 192.168.122.84 ip daddr 192.168.122.1 ip tos 16 ip ttl 64 ip id 51655 ip length 40 tcp sport 10000 tcp dport 46156

If people are happy this way I'll start getting it into final shape.

Cheers,
Patrick

[-- Attachment #2: 1.diff --]
[-- Type: text/plain, Size: 5561 bytes --]

commit 0df38a649c851291352a410ee6ebbc9492f9b7d2
Author: Patrick McHardy <kaber@trash.net>
Date:   Wed Nov 25 18:46:14 2015 +0000

    payload: move payload depedency tracking to payload.c
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>

diff --git a/include/payload.h b/include/payload.h
index ca9b013..619a9c9 100644
--- a/include/payload.h
+++ b/include/payload.h
@@ -15,6 +15,24 @@ struct stmt;
 extern int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
 				  struct stmt **res);
 
+/**
+ * struct payload_dep_ctx - payload protocol dependency tracking
+ *
+ * @pbase: protocol base of last dependency match
+ * @pdep: last dependency match
+ */
+struct payload_dep_ctx {
+	enum proto_bases	pbase;
+	struct stmt		*pdep;
+};
+
+extern void payload_dependency_store(struct payload_dep_ctx *ctx,
+				     struct stmt *stmt,
+				     enum proto_bases base);
+extern void payload_dependency_kill(struct payload_dep_ctx *ctx,
+				    struct expr *expr);
+
+
 extern bool payload_is_adjacent(const struct expr *e1, const struct expr *e2);
 extern struct expr *payload_expr_join(const struct expr *e1,
 				      const struct expr *e2);
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 614fbe0..5d81068 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -945,34 +945,10 @@ static int netlink_parse_expr(struct nftnl_expr *nle, void *arg)
 
 struct rule_pp_ctx {
 	struct proto_ctx	pctx;
-	enum proto_bases	pbase;
-	struct stmt		*pdep;
+	struct payload_dep_ctx	pdctx;
 	struct stmt		*stmt;
 };
 
-/*
- * Kill a redundant payload dependecy that is implied by a higher layer payload expression.
- */
-static void payload_dependency_kill(struct rule_pp_ctx *ctx, struct expr *expr)
-{
-	if (ctx->pbase != PROTO_BASE_INVALID &&
-	    ctx->pbase == expr->payload.base &&
-	    ctx->pdep != NULL) {
-		list_del(&ctx->pdep->list);
-		stmt_free(ctx->pdep);
-		ctx->pbase = PROTO_BASE_INVALID;
-		ctx->pdep = NULL;
-	}
-}
-
-static void payload_dependency_store(struct rule_pp_ctx *ctx,
-				     struct stmt *stmt,
-				     enum proto_bases base)
-{
-	ctx->pbase = base + 1;
-	ctx->pdep  = stmt;
-}
-
 static void integer_type_postprocess(struct expr *expr)
 {
 	struct expr *i;
@@ -1036,7 +1012,7 @@ static void payload_match_expand(struct rule_pp_ctx *ctx,
 		 * kill it later on if made redundant by a higher layer
 		 * payload expression.
 		 */
-		if (ctx->pbase == PROTO_BASE_INVALID &&
+		if (ctx->pdctx.pbase == PROTO_BASE_INVALID &&
 		    left->flags & EXPR_F_PROTOCOL) {
 			unsigned int proto = mpz_get_be16(tmp->value);
 			const struct proto_desc *desc, *next;
@@ -1052,12 +1028,14 @@ static void payload_match_expand(struct rule_pp_ctx *ctx,
 			if (stacked_header) {
 				ctx->pctx.protocol[base].desc = next;
 				ctx->pctx.protocol[base].offset += desc->length;
-				payload_dependency_store(ctx, nstmt, base - 1);
+				payload_dependency_store(&ctx->pdctx,
+							 nstmt, base - 1);
 			} else {
-				payload_dependency_store(ctx, nstmt, base);
+				payload_dependency_store(&ctx->pdctx,
+							 nstmt, base);
 			}
 		} else {
-			payload_dependency_kill(ctx, nexpr->left);
+			payload_dependency_kill(&ctx->pdctx, nexpr->left);
 		}
 	}
 	list_del(&ctx->stmt->list);
@@ -1087,7 +1065,7 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx,
 		payload_expr_complete(payload, &ctx->pctx);
 		expr_set_type(expr->right, payload->dtype,
 			      payload->byteorder);
-		payload_dependency_kill(ctx, payload);
+		payload_dependency_kill(&ctx->pdctx, payload);
 		break;
 	}
 }
@@ -1104,9 +1082,9 @@ static void meta_match_postprocess(struct rule_pp_ctx *ctx,
 
 		expr->left->ops->pctx_update(&ctx->pctx, expr);
 
-		if (ctx->pbase == PROTO_BASE_INVALID &&
+		if (ctx->pdctx.pbase == PROTO_BASE_INVALID &&
 		    left->flags & EXPR_F_PROTOCOL)
-			payload_dependency_store(ctx, ctx->stmt,
+			payload_dependency_store(&ctx->pdctx, ctx->stmt,
 						 left->meta.base);
 		break;
 	case OP_LOOKUP:
@@ -1410,7 +1388,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
 		break;
 	case EXPR_PAYLOAD:
 		payload_expr_complete(expr, &ctx->pctx);
-		payload_dependency_kill(ctx, expr);
+		payload_dependency_kill(&ctx->pdctx, expr);
 		break;
 	case EXPR_VALUE:
 		// FIXME
diff --git a/src/payload.c b/src/payload.c
index a97041e..dabd504 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -282,6 +282,42 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
 }
 
 /**
+ * payload_dependency_store - store a possibly redundant protocol match
+ *
+ * @ctx: payload dependency context
+ * @stmt: payload match
+ * @base: base of payload match
+ */
+void payload_dependency_store(struct payload_dep_ctx *ctx,
+			      struct stmt *stmt, enum proto_bases base)
+{
+	ctx->pbase = base + 1;
+	ctx->pdep  = stmt;
+}
+
+/**
+ * payload_dependency_kill - kill a redundant payload depedency
+ *
+ * @ctx: payload dependency context
+ * @expr: higher layer payload expression
+ *
+ * Kill a redundant payload expression if a higher layer payload expression
+ * implies its existance.
+ */
+void payload_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr)
+{
+	if (ctx->pbase != PROTO_BASE_INVALID &&
+	    ctx->pbase == expr->payload.base &&
+	    ctx->pdep != NULL) {
+		list_del(&ctx->pdep->list);
+		stmt_free(ctx->pdep);
+
+		ctx->pbase = PROTO_BASE_INVALID;
+		ctx->pdep  = NULL;
+	}
+}
+
+/**
  * payload_expr_complete - fill in type information of a raw payload expr
  *
  * @expr:	the payload expression

[-- Attachment #3: 2.diff --]
[-- Type: text/plain, Size: 9582 bytes --]

commit a42310894bdb739f3e0e11bf500bfb580790b49f
Author: Patrick McHardy <kaber@trash.net>
Date:   Wed Nov 25 16:51:10 2015 +0000

    .

diff --git a/include/payload.h b/include/payload.h
index 619a9c9..59027a1 100644
--- a/include/payload.h
+++ b/include/payload.h
@@ -9,6 +9,7 @@ extern struct expr *payload_expr_alloc(const struct location *loc,
 				       unsigned int type);
 extern void payload_init_raw(struct expr *expr, enum proto_bases base,
 			     unsigned int offset, unsigned int len);
+extern unsigned int payload_hdr_field(const struct expr *expr);
 
 struct eval_ctx;
 struct stmt;
diff --git a/include/proto.h b/include/proto.h
index a31ab91..6397107 100644
--- a/include/proto.h
+++ b/include/proto.h
@@ -85,6 +85,11 @@ struct proto_desc {
 		const struct proto_desc		*desc;
 	}				protocols[PROTO_UPPER_MAX];
 	struct proto_hdr_template	templates[PROTO_HDRS_MAX];
+	struct {
+		uint8_t				order[PROTO_HDRS_MAX];
+		uint32_t			filter;
+	}				format;
+
 };
 
 #define PROTO_LINK(__num, __desc)	{ .num = (__num), .desc = (__desc), }
diff --git a/src/netlink.c b/src/netlink.c
index 8ab7bbe..63e7ac5 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -31,6 +31,7 @@
 #include <netlink.h>
 #include <mnl.h>
 #include <expression.h>
+#include <statement.h>
 #include <gmputil.h>
 #include <utils.h>
 #include <erec.h>
@@ -2165,19 +2166,130 @@ static void trace_print_rule(const struct nftnl_trace *nlt)
 	}
 }
 
-static void trace_print_if(const struct nftnl_trace *nlt, uint16_t attr, const char *str)
+static void trace_gen_hdr(struct list_head *stmts,
+			  struct proto_ctx *ctx, struct payload_dep_ctx *pctx,
+			  const struct nftnl_trace *nlt, unsigned int attr,
+			  enum proto_bases base)
 {
-	char __name[IFNAMSIZ];
-	const char *ifname;
+	struct list_head unordered = LIST_HEAD_INIT(unordered);
+	struct list_head list = LIST_HEAD_INIT(list);
+	struct expr *rel, *lhs, *rhs, *tmp, *nexpr;
+	struct stmt *stmt, *nstmt;
+	const struct proto_desc *desc;
+	const void *hdr;
+	uint32_t hlen;
+	unsigned int n;
 
-        if (!nftnl_trace_is_set(nlt, attr))
+	if (!nftnl_trace_is_set(nlt, attr))
 		return;
+	hdr = nftnl_trace_get_data(nlt, attr, &hlen);
+
+	lhs = payload_expr_alloc(&netlink_location, NULL, 0);
+	payload_init_raw(lhs, base, 0, hlen * BITS_PER_BYTE);
+	rhs = constant_expr_alloc(&netlink_location,
+				  &invalid_type, BYTEORDER_INVALID,
+				  hlen * BITS_PER_BYTE, hdr);
+
+	payload_expr_expand(&list, lhs, NULL, ctx);
+	list_for_each_entry_safe(lhs, nexpr, &list, list) {
+		tmp = constant_expr_splice(rhs, lhs->len);
+		expr_set_type(tmp, lhs->dtype, lhs->byteorder);
+
+		/* Skip unknown and filtered expressions */
+		desc = lhs->payload.desc;
+		if (lhs->dtype == &invalid_type ||
+		    desc->format.filter & (1 << payload_hdr_field(lhs))) {
+			expr_free(lhs);
+			expr_free(tmp);
+			continue;
+		}
 
-	ifname = nft_if_indextoname(nftnl_trace_get_u32(nlt, attr), __name);
-	if (ifname)
-		printf(" %s %s", str, ifname);
-	else
-		printf(" %s %d", str, nftnl_trace_get_u32(nlt, attr));
+		rel  = relational_expr_alloc(&lhs->location, OP_EQ, lhs, tmp);
+		stmt = expr_stmt_alloc(&rel->location, rel);
+		list_add_tail(&stmt->list, &unordered);
+	}
+
+	n = 0;
+next:
+	list_for_each_entry_safe(stmt, nstmt, &unordered, list) {
+		rel = stmt->expr;
+		lhs = rel->left;
+
+		/* Move statements to result list in defined order */
+		desc = lhs->payload.desc;
+		if (desc->format.order[n] &&
+		    desc->format.order[n] != payload_hdr_field(lhs))
+			continue;
+
+		list_move_tail(&stmt->list, stmts);
+		n++;
+
+		lhs->ops->pctx_update(ctx, rel);
+		if (lhs->flags & EXPR_F_PROTOCOL &&
+		    pctx->pbase == PROTO_BASE_INVALID)
+			payload_dependency_store(pctx, stmt, base);
+		else
+			payload_dependency_kill(pctx, lhs);
+
+		goto next;
+	}
+}
+
+static void trace_alloc_expr(const struct nftnl_trace *nlt, unsigned int attr,
+			     struct expr *lhs)
+{
+	struct expr *rhs, *rel;
+	const void *data;
+	uint32_t len;
+
+	data = nftnl_trace_get_data(nlt, attr, &len);
+	rhs  = constant_expr_alloc(&netlink_location,
+				   lhs->dtype, lhs->byteorder,
+				   len * BITS_PER_BYTE, data);
+	rel  = relational_expr_alloc(&netlink_location, OP_EQ, lhs, rhs);
+
+	expr_print(rel);
+	printf(" ");
+	expr_free(rel);
+}
+
+static void trace_print_packet(const struct nftnl_trace *nlt)
+{
+	struct list_head stmts = LIST_HEAD_INIT(stmts);
+	struct payload_dep_ctx pctx = {};
+	struct proto_ctx ctx;
+	uint16_t dev_type;
+	struct stmt *stmt, *next;
+
+	proto_ctx_init(&ctx, nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY));
+	if (ctx.protocol[PROTO_BASE_LL_HDR].desc == NULL &&
+	    nftnl_trace_is_set(nlt, NFTNL_TRACE_DEV_TYPE)) {
+		dev_type = nftnl_trace_get_u16(nlt, NFTNL_TRACE_DEV_TYPE);
+		proto_ctx_update(&ctx, PROTO_BASE_LL_HDR, &netlink_location,
+				 proto_dev_desc(dev_type));
+	}
+
+	printf("packet: ");
+
+	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_IIF))
+		trace_alloc_expr(nlt, NFTNL_TRACE_IIF,
+			meta_expr_alloc(&netlink_location, NFT_META_IIF));
+	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_OIF))
+		trace_alloc_expr(nlt, NFTNL_TRACE_OIF,
+			meta_expr_alloc(&netlink_location, NFT_META_OIF));
+
+	trace_gen_hdr(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_LL_HEADER,
+		      PROTO_BASE_LL_HDR);
+	trace_gen_hdr(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_NETWORK_HEADER,
+		      PROTO_BASE_NETWORK_HDR);
+	trace_gen_hdr(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_TRANSPORT_HEADER,
+		      PROTO_BASE_TRANSPORT_HDR);
+
+	list_for_each_entry_safe(stmt, next, &stmts, list) {
+		stmt_print(stmt);
+		printf(" ");
+		stmt_free(stmt);
+	}
 }
 
 static int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type,
@@ -2194,11 +2306,37 @@ static int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type,
 	if (nftnl_trace_nlmsg_parse(nlh, nlt) < 0)
 		netlink_abi_error();
 
-	printf("trace ");
-	nftnl_trace_fprintf(stdout, nlt, monh->format);
+	printf("trace id %08x ", nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID));
+
+	printf("%s ", family2str(nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY)));
+	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_TABLE))
+		printf("%s ", nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE));
+	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_CHAIN))
+		printf("%s ", nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN));
+
+	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_VERDICT)) {
+		unsigned int verdict;
+		struct expr *expr;
+
+		verdict = nftnl_trace_get_u32(nlt, NFTNL_TRACE_VERDICT);
+		expr = verdict_expr_alloc(&netlink_location, verdict, "");
+
+		printf("verdict ");
+		expr_print(expr);
+		printf(" ");
+	}
+
+	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_MARK))
+		trace_alloc_expr(nlt, NFTNL_TRACE_MARK,
+			meta_expr_alloc(&netlink_location, NFT_META_MARK));
+
+	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_VLAN_TAG))
+		printf("vlan id %u ",
+		       nftnl_trace_get_u16(nlt, NFTNL_TRACE_VLAN_TAG));
 
-	trace_print_if(nlt, NFTNL_TRACE_IIF, "iif");
-	trace_print_if(nlt, NFTNL_TRACE_OIF, "oif");
+	if (nftnl_trace_is_set(nlt, NFTNL_TRACE_LL_HEADER) ||
+	    nftnl_trace_is_set(nlt, NFTNL_TRACE_NETWORK_HEADER))
+		trace_print_packet(nlt);
 
 	trace_print_rule(nlt);
 	printf("\n");
diff --git a/src/payload.c b/src/payload.c
index dabd504..d00ddf6 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -138,6 +138,11 @@ void payload_init_raw(struct expr *expr, enum proto_bases base,
 	expr->len		= len;
 }
 
+unsigned int payload_hdr_field(const struct expr *expr)
+{
+	return expr->payload.tmpl - expr->payload.desc->templates;
+}
+
 static void payload_stmt_print(const struct stmt *stmt)
 {
 	expr_print(stmt->payload.expr);
@@ -457,6 +462,7 @@ void payload_expr_expand(struct list_head *list, struct expr *expr,
 		goto raw;
 	assert(desc->base == expr->payload.base);
 
+restart:
 	for (i = 1; i < array_size(desc->templates); i++) {
 		tmpl = &desc->templates[i];
 		if (tmpl->offset != expr->payload.offset)
@@ -469,6 +475,7 @@ void payload_expr_expand(struct list_head *list, struct expr *expr,
 			expr->payload.offset += tmpl->len;
 			if (expr->len == off)
 				return;
+			goto restart;
 		} else
 			break;
 	}
diff --git a/src/proto.c b/src/proto.c
index 803ee97..8e1fa02 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -331,6 +331,9 @@ const struct proto_desc proto_icmp = {
 		[ICMPHDR_GATEWAY]	= ICMPHDR_FIELD("gateway", un.gateway),
 		[ICMPHDR_MTU]		= ICMPHDR_FIELD("mtu", un.frag.mtu),
 	},
+	.format		= {
+		.filter	= (1 << ICMPHDR_CHECKSUM),
+	},
 };
 
 /*
@@ -520,6 +523,14 @@ const struct proto_desc proto_ip = {
 		[IPHDR_SADDR]		= IPHDR_ADDR("saddr",		saddr),
 		[IPHDR_DADDR]		= IPHDR_ADDR("daddr",		daddr),
 	},
+	.format		= {
+		.order	= {
+			IPHDR_SADDR, IPHDR_DADDR, IPHDR_TOS, IPHDR_TTL,
+			IPHDR_ID, IPHDR_PROTOCOL, IPHDR_LENGTH,
+		},
+		.filter	= (1 << IPHDR_VERSION)  | (1 << IPHDR_HDRLENGTH) |
+			  (1 << IPHDR_FRAG_OFF) | (1 << IPHDR_CHECKSUM),
+	},
 };
 
 /*
@@ -708,6 +719,10 @@ const struct proto_desc proto_arp = {
 		[ARPHDR_THA]		= PROTO_HDR_TEMPLATE("tha", &etheraddr_type, BYTEORDER_BIG_ENDIAN, 18 * BITS_PER_BYTE, 6 * BITS_PER_BYTE),
 		[ARPHDR_TPA]		= PROTO_HDR_TEMPLATE("tip", &ipaddr_type, BYTEORDER_BIG_ENDIAN, 24 * BITS_PER_BYTE, 4 * BITS_PER_BYTE),
 	},
+	.format		= {
+		.filter	= (1 << ARPHDR_HRD) | (1 << ARPHDR_PRO) |
+			  (1 << ARPHDR_HLN) | (1 << ARPHDR_PLN),
+	},
 };
 
 /*
@@ -807,6 +822,12 @@ const struct proto_desc proto_eth = {
 		[ETHHDR_SADDR]		= ETHHDR_ADDR("saddr", ether_shost),
 		[ETHHDR_TYPE]		= ETHHDR_TYPE("type", ether_type),
 	},
+	.format		= {
+		.order	= {
+			ETHHDR_SADDR, ETHHDR_DADDR, ETHHDR_TYPE,
+		},
+	},
+
 };
 
 static void __init proto_init(void)

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-26 10:50                             ` Patrick McHardy
@ 2015-11-26 11:03                               ` Florian Westphal
  2015-11-26 11:42                                 ` Patrick McHardy
  0 siblings, 1 reply; 80+ messages in thread
From: Florian Westphal @ 2015-11-26 11:03 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian Westphal, Pablo Neira Ayuso, netfilter-devel

Patrick McHardy <kaber@trash.net> wrote:
> Ok here's might current state. I've added an output filter and defined
> output ordering, so we can surpress some fields and order the remaining
> ones the way we want. I've also added redundant payload dependency
> elimination.
> 
> Example output looks like this:
> 
> trace id 85060d00 arp packet: iif ens3 ether saddr 63:f6:4b:00:54:52 ether daddr c9:4b:a9:00:54:52 arp operation reply arp sha 63:f6:4b:00:54:52 arp sip 192.168.122.1 arp tha c9:4b:a9:00:54:52 arp tip 192.168.122.84
> 
> trace id 853ff400 ip packet: iif ens3 ether saddr 63:f6:4b:00:54:52 ether daddr c9:4b:a9:00:54:52 ip saddr 192.168.122.1 ip daddr 192.168.122.84 ip tos 16 ip ttl 64 ip id 38325 ip length 60 tcp sport 46156 tcp dport 10000
> 
> trace id 853ffc00 ip packet: oif ens3 ip saddr 192.168.122.84 ip daddr 192.168.122.1 ip tos 16 ip ttl 64 ip id 51655 ip length 40 tcp sport 10000 tcp dport 46156
> 
> If people are happy this way I'll start getting it into final shape.

Please do, looks great!

But note that I'm still busy with v2 of the libnftnl and kernel parts,
there will be minor changes there.

1. VLAN_TAG attr will be removed, I'll insert vlan header after ethernet
one in the LL_HEADER payload.
2. IIF, OIF etc attributes will be removed.  Instead, I plan to reuse
meta keys for this in a nested TRACE_META attribute.

Not sure yet how the libnftnl part will look like, I'd prefer to reuse
meta decoding parts that we have in libnftnl already
(my thinking was that if we'd want e.g. secmark later we could
 do so more easily if we'd just reuse meta key values).

3. PACKET message type has been removed.  Kernel will insert the HEADER
payloads in the first message sent from each do_chain invocation.

I think this will not interfere with your patch too much.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present
  2015-11-26 11:03                               ` Florian Westphal
@ 2015-11-26 11:42                                 ` Patrick McHardy
  0 siblings, 0 replies; 80+ messages in thread
From: Patrick McHardy @ 2015-11-26 11:42 UTC (permalink / raw)
  To: Florian Westphal; +Cc: Pablo Neira Ayuso, netfilter-devel

On 26.11, Florian Westphal wrote:
> Patrick McHardy <kaber@trash.net> wrote:
> > Ok here's might current state. I've added an output filter and defined
> > output ordering, so we can surpress some fields and order the remaining
> > ones the way we want. I've also added redundant payload dependency
> > elimination.
> > 
> > Example output looks like this:
> > 
> > trace id 85060d00 arp packet: iif ens3 ether saddr 63:f6:4b:00:54:52 ether daddr c9:4b:a9:00:54:52 arp operation reply arp sha 63:f6:4b:00:54:52 arp sip 192.168.122.1 arp tha c9:4b:a9:00:54:52 arp tip 192.168.122.84
> > 
> > trace id 853ff400 ip packet: iif ens3 ether saddr 63:f6:4b:00:54:52 ether daddr c9:4b:a9:00:54:52 ip saddr 192.168.122.1 ip daddr 192.168.122.84 ip tos 16 ip ttl 64 ip id 38325 ip length 60 tcp sport 46156 tcp dport 10000
> > 
> > trace id 853ffc00 ip packet: oif ens3 ip saddr 192.168.122.84 ip daddr 192.168.122.1 ip tos 16 ip ttl 64 ip id 51655 ip length 40 tcp sport 10000 tcp dport 46156
> > 
> > If people are happy this way I'll start getting it into final shape.
> 
> Please do, looks great!

Great :)

> But note that I'm still busy with v2 of the libnftnl and kernel parts,
> there will be minor changes there.
> 
> 1. VLAN_TAG attr will be removed, I'll insert vlan header after ethernet
> one in the LL_HEADER payload.
> 2. IIF, OIF etc attributes will be removed.  Instead, I plan to reuse
> meta keys for this in a nested TRACE_META attribute.

Both sound like good ideas, however regarding meta we'd have to use the
nft attributes even if we're using the tracing infrastructure for different
subsystems as discussed previously. I guess that would be Ok, just wanted
to mention it.

> Not sure yet how the libnftnl part will look like, I'd prefer to reuse
> meta decoding parts that we have in libnftnl already
> (my thinking was that if we'd want e.g. secmark later we could
>  do so more easily if we'd just reuse meta key values).
> 
> 3. PACKET message type has been removed.  Kernel will insert the HEADER
> payloads in the first message sent from each do_chain invocation.
> 
> I think this will not interfere with your patch too much.

Probably not, should be quite easy to adapt to any interface changes.


BTW, I had a another idea regarding the kernel side. Just mentioning it
in case you find it interesting:

We're currently only sending traces for matching rules. If we get NFT_BREAK
we'll skip sending a trace.

It might also be of interest *why* a rule didn't match. A possibility without
too much overhead would be in the NFT_BREAK case to send:

* a trace message
* the current register contents
* the current *expr

That would allow userspace to look at the first non-matching expression,
determine the meaning of the register contents and show the expression and
the actual contents.

So you'd get a rule, let's say an expression "iif eth0" and the register
content "iif eth1".

Just an idea.

^ permalink raw reply	[flat|nested] 80+ messages in thread

end of thread, other threads:[~2015-11-26 11:42 UTC | newest]

Thread overview: 80+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-24 10:02 [PATCH 0/6] nftables trace support Florian Westphal
2015-11-24 10:02 ` [PATCH nf-next 1/6] netfilter: nf_tables: extend tracing infrastructure Florian Westphal
2015-11-24 10:17   ` Pablo Neira Ayuso
2015-11-24 10:27     ` Florian Westphal
2015-11-24 10:30       ` Pablo Neira Ayuso
2015-11-24 10:35         ` Patrick McHardy
2015-11-24 11:11         ` Florian Westphal
2015-11-24 10:22   ` Pablo Neira Ayuso
2015-11-24 10:28     ` Florian Westphal
2015-11-24 10:33       ` Patrick McHardy
2015-11-24 10:44         ` Pablo Neira Ayuso
2015-11-24 10:45           ` Pablo Neira Ayuso
2015-11-24 10:47             ` Patrick McHardy
2015-11-24 10:36       ` Pablo Neira Ayuso
2015-11-24 10:44   ` Patrick McHardy
2015-11-25  0:55   ` Patrick McHardy
2015-11-25  8:39     ` Florian Westphal
2015-11-25  8:48       ` Florian Westphal
2015-11-25  9:35       ` Patrick McHardy
2015-11-25 10:13         ` Florian Westphal
2015-11-25 11:51           ` Patrick McHardy
2015-11-25 12:20             ` Florian Westphal
2015-11-24 10:02 ` [PATCH nf-next 2/6] netfilter: nf_tables: wrap tracing with a static key Florian Westphal
2015-11-24 10:13   ` Patrick McHardy
2015-11-24 10:21     ` Florian Westphal
2015-11-24 10:28       ` Patrick McHardy
2015-11-24 10:19   ` Pablo Neira Ayuso
2015-11-24 10:02 ` [PATCH nf-next 3/6] netfilter: nf_tables: disable old tracing if listener is present Florian Westphal
2015-11-24 10:16   ` Patrick McHardy
2015-11-24 10:24   ` Pablo Neira Ayuso
2015-11-24 10:31     ` Florian Westphal
2015-11-24 10:39       ` Pablo Neira Ayuso
2015-11-24 10:53         ` Patrick McHardy
2015-11-24 11:10           ` Florian Westphal
2015-11-24 11:33             ` Patrick McHardy
2015-11-24 15:15               ` Florian Westphal
2015-11-24 15:26                 ` Patrick McHardy
2015-11-24 15:35                   ` Florian Westphal
2015-11-24 15:42                     ` Patrick McHardy
2015-11-25 15:06                       ` Patrick McHardy
2015-11-25 16:23                         ` Pablo Neira Ayuso
2015-11-25 16:34                           ` Patrick McHardy
2015-11-25 16:24                         ` Florian Westphal
2015-11-25 16:46                           ` Patrick McHardy
2015-11-25 17:32                             ` Patrick McHardy
2015-11-25 22:27                               ` Florian Westphal
2015-11-25 23:04                                 ` Patrick McHardy
2015-11-25 23:16                                   ` Florian Westphal
2015-11-25 23:30                                     ` Patrick McHardy
2015-11-25 23:42                                 ` Patrick McHardy
2015-11-25 23:56                                   ` Florian Westphal
2015-11-25 22:52                             ` Florian Westphal
2015-11-25 23:15                               ` Patrick McHardy
2015-11-25 23:19                                 ` Florian Westphal
2015-11-26 10:50                             ` Patrick McHardy
2015-11-26 11:03                               ` Florian Westphal
2015-11-26 11:42                                 ` Patrick McHardy
2015-11-25 16:49                         ` Jan Engelhardt
2015-11-25 16:53                           ` Patrick McHardy
2015-11-25 17:14                             ` Jan Engelhardt
2015-11-25 17:24                               ` Patrick McHardy
2015-11-25  0:57   ` Patrick McHardy
2015-11-24 10:02 ` [PATCH libnftnl 4/6] src: rename EXPORT_SYMBOL to EXPORT_SYMBOL_ALIAS Florian Westphal
2015-11-24 10:11   ` Pablo Neira Ayuso
2015-11-24 10:02 ` [PATCH libnftnl 5/6] src: add trace infrastructure support Florian Westphal
2015-11-24 12:16   ` Patrick McHardy
2015-11-24 14:53     ` Patrick McHardy
2015-11-24 10:02 ` [PATCH nftables 6/6] src: add trace support to nft monitor mode Florian Westphal
2015-11-24 10:25   ` Patrick McHardy
2015-11-24 10:48     ` Florian Westphal
2015-11-24 10:58       ` Patrick McHardy
2015-11-24 11:01         ` Pablo Neira Ayuso
2015-11-24 11:07           ` Patrick McHardy
2015-11-24 11:14             ` Pablo Neira Ayuso
2015-11-24 11:14         ` Florian Westphal
2015-11-24 11:41           ` Patrick McHardy
2015-11-24 10:53     ` Pablo Neira Ayuso
2015-11-24 11:04       ` Patrick McHardy
2015-11-24 11:12         ` Pablo Neira Ayuso
2015-11-24 11:36           ` Patrick McHardy

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.