netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Pablo Neira Ayuso <pablo@netfilter.org>
To: netfilter-devel@vger.kernel.org
Cc: davem@davemloft.net, netdev@vger.kernel.org
Subject: [PATCH 40/50] netfilter: nf_tables: add stateful object reference to set elements
Date: Wed,  7 Dec 2016 22:52:46 +0100	[thread overview]
Message-ID: <1481147576-5690-41-git-send-email-pablo@netfilter.org> (raw)
In-Reply-To: <1481147576-5690-1-git-send-email-pablo@netfilter.org>

This patch allows you to refer to stateful objects from set elements.
This provides the infrastructure to create maps where the right hand
side of the mapping is a stateful object.

This allows us to build dictionaries of stateful objects, that you can
use to perform fast lookups using any arbitrary key combination.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/net/netfilter/nf_tables.h        |  9 ++++
 include/uapi/linux/netfilter/nf_tables.h |  8 ++++
 net/netfilter/nf_tables_api.c            | 72 +++++++++++++++++++++++++++-----
 3 files changed, 79 insertions(+), 10 deletions(-)

diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index ce6fb6e83b32..85f0f03f1e87 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -326,6 +326,7 @@ void nft_unregister_set(struct nft_set_ops *ops);
  * 	@name: name of the set
  * 	@ktype: key type (numeric type defined by userspace, not used in the kernel)
  * 	@dtype: data type (verdict or numeric type defined by userspace)
+ * 	@objtype: object type (see NFT_OBJECT_* definitions)
  * 	@size: maximum set size
  * 	@nelems: number of elements
  * 	@ndeact: number of deactivated elements queued for removal
@@ -347,6 +348,7 @@ struct nft_set {
 	char				name[NFT_SET_MAXNAMELEN];
 	u32				ktype;
 	u32				dtype;
+	u32				objtype;
 	u32				size;
 	atomic_t			nelems;
 	u32				ndeact;
@@ -416,6 +418,7 @@ void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
  *	@NFT_SET_EXT_EXPIRATION: element expiration time
  *	@NFT_SET_EXT_USERDATA: user data associated with the element
  *	@NFT_SET_EXT_EXPR: expression assiociated with the element
+ *	@NFT_SET_EXT_OBJREF: stateful object reference associated with element
  *	@NFT_SET_EXT_NUM: number of extension types
  */
 enum nft_set_extensions {
@@ -426,6 +429,7 @@ enum nft_set_extensions {
 	NFT_SET_EXT_EXPIRATION,
 	NFT_SET_EXT_USERDATA,
 	NFT_SET_EXT_EXPR,
+	NFT_SET_EXT_OBJREF,
 	NFT_SET_EXT_NUM
 };
 
@@ -554,6 +558,11 @@ static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,
 	return elem + set->ops->elemsize;
 }
 
+static inline struct nft_object **nft_set_ext_obj(const struct nft_set_ext *ext)
+{
+	return nft_set_ext(ext, NFT_SET_EXT_OBJREF);
+}
+
 void *nft_set_elem_init(const struct nft_set *set,
 			const struct nft_set_ext_tmpl *tmpl,
 			const u32 *key, const u32 *data,
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 4864caca1e8e..a6b52dbff08c 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -255,6 +255,7 @@ enum nft_rule_compat_attributes {
  * @NFT_SET_MAP: set is used as a dictionary
  * @NFT_SET_TIMEOUT: set uses timeouts
  * @NFT_SET_EVAL: set contains expressions for evaluation
+ * @NFT_SET_OBJECT: set contains stateful objects
  */
 enum nft_set_flags {
 	NFT_SET_ANONYMOUS		= 0x1,
@@ -263,6 +264,7 @@ enum nft_set_flags {
 	NFT_SET_MAP			= 0x8,
 	NFT_SET_TIMEOUT			= 0x10,
 	NFT_SET_EVAL			= 0x20,
+	NFT_SET_OBJECT			= 0x40,
 };
 
 /**
@@ -304,6 +306,7 @@ enum nft_set_desc_attributes {
  * @NFTA_SET_TIMEOUT: default timeout value (NLA_U64)
  * @NFTA_SET_GC_INTERVAL: garbage collection interval (NLA_U32)
  * @NFTA_SET_USERDATA: user data (NLA_BINARY)
+ * @NFTA_SET_OBJ_TYPE: stateful object type (NLA_U32: NFT_OBJECT_*)
  */
 enum nft_set_attributes {
 	NFTA_SET_UNSPEC,
@@ -321,6 +324,7 @@ enum nft_set_attributes {
 	NFTA_SET_GC_INTERVAL,
 	NFTA_SET_USERDATA,
 	NFTA_SET_PAD,
+	NFTA_SET_OBJ_TYPE,
 	__NFTA_SET_MAX
 };
 #define NFTA_SET_MAX		(__NFTA_SET_MAX - 1)
@@ -344,6 +348,7 @@ enum nft_set_elem_flags {
  * @NFTA_SET_ELEM_EXPIRATION: expiration time (NLA_U64)
  * @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY)
  * @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes)
+ * @NFTA_SET_ELEM_OBJREF: stateful object reference (NLA_STRING)
  */
 enum nft_set_elem_attributes {
 	NFTA_SET_ELEM_UNSPEC,
@@ -355,6 +360,7 @@ enum nft_set_elem_attributes {
 	NFTA_SET_ELEM_USERDATA,
 	NFTA_SET_ELEM_EXPR,
 	NFTA_SET_ELEM_PAD,
+	NFTA_SET_ELEM_OBJREF,
 	__NFTA_SET_ELEM_MAX
 };
 #define NFTA_SET_ELEM_MAX	(__NFTA_SET_ELEM_MAX - 1)
@@ -1207,6 +1213,8 @@ enum nft_fib_flags {
 #define NFT_OBJECT_UNSPEC	0
 #define NFT_OBJECT_COUNTER	1
 #define NFT_OBJECT_QUOTA	2
+#define __NFT_OBJECT_MAX	3
+#define NFT_OBJECT_MAX		(__NFT_OBJECT_MAX - 1)
 
 /**
  * enum nft_object_attributes - nf_tables stateful object netlink attributes
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index c5419701ca79..8228714c42d5 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -2452,6 +2452,7 @@ static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
 	[NFTA_SET_GC_INTERVAL]		= { .type = NLA_U32 },
 	[NFTA_SET_USERDATA]		= { .type = NLA_BINARY,
 					    .len  = NFT_USERDATA_MAXLEN },
+	[NFTA_SET_OBJ_TYPE]		= { .type = NLA_U32 },
 };
 
 static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
@@ -2609,6 +2610,9 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
 		if (nla_put_be32(skb, NFTA_SET_DATA_LEN, htonl(set->dlen)))
 			goto nla_put_failure;
 	}
+	if (set->flags & NFT_SET_OBJECT &&
+	    nla_put_be32(skb, NFTA_SET_OBJ_TYPE, htonl(set->objtype)))
+		goto nla_put_failure;
 
 	if (set->timeout &&
 	    nla_put_be64(skb, NFTA_SET_TIMEOUT,
@@ -2838,7 +2842,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
 	unsigned int size;
 	bool create;
 	u64 timeout;
-	u32 ktype, dtype, flags, policy, gc_int;
+	u32 ktype, dtype, flags, policy, gc_int, objtype;
 	struct nft_set_desc desc;
 	unsigned char *udata;
 	u16 udlen;
@@ -2868,11 +2872,12 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
 		flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
 		if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
 			      NFT_SET_INTERVAL | NFT_SET_TIMEOUT |
-			      NFT_SET_MAP | NFT_SET_EVAL))
+			      NFT_SET_MAP | NFT_SET_EVAL |
+			      NFT_SET_OBJECT))
 			return -EINVAL;
-		/* Only one of both operations is supported */
-		if ((flags & (NFT_SET_MAP | NFT_SET_EVAL)) ==
-			     (NFT_SET_MAP | NFT_SET_EVAL))
+		/* Only one of these operations is supported */
+		if ((flags & (NFT_SET_MAP | NFT_SET_EVAL | NFT_SET_OBJECT)) ==
+			     (NFT_SET_MAP | NFT_SET_EVAL | NFT_SET_OBJECT))
 			return -EOPNOTSUPP;
 	}
 
@@ -2897,6 +2902,19 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
 	} else if (flags & NFT_SET_MAP)
 		return -EINVAL;
 
+	if (nla[NFTA_SET_OBJ_TYPE] != NULL) {
+		if (!(flags & NFT_SET_OBJECT))
+			return -EINVAL;
+
+		objtype = ntohl(nla_get_be32(nla[NFTA_SET_OBJ_TYPE]));
+		if (objtype == NFT_OBJECT_UNSPEC ||
+		    objtype > NFT_OBJECT_MAX)
+			return -EINVAL;
+	} else if (flags & NFT_SET_OBJECT)
+		return -EINVAL;
+	else
+		objtype = NFT_OBJECT_UNSPEC;
+
 	timeout = 0;
 	if (nla[NFTA_SET_TIMEOUT] != NULL) {
 		if (!(flags & NFT_SET_TIMEOUT))
@@ -2984,6 +3002,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
 	set->ktype = ktype;
 	set->klen  = desc.klen;
 	set->dtype = dtype;
+	set->objtype = objtype;
 	set->dlen  = desc.dlen;
 	set->flags = flags;
 	set->size  = desc.size;
@@ -3126,6 +3145,10 @@ const struct nft_set_ext_type nft_set_ext_types[] = {
 	[NFT_SET_EXT_EXPR]		= {
 		.align	= __alignof__(struct nft_expr),
 	},
+	[NFT_SET_EXT_OBJREF]		= {
+		.len	= sizeof(struct nft_object *),
+		.align	= __alignof__(struct nft_object *),
+	},
 	[NFT_SET_EXT_FLAGS]		= {
 		.len	= sizeof(u8),
 		.align	= __alignof__(u8),
@@ -3214,6 +3237,11 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
 	    nft_expr_dump(skb, NFTA_SET_ELEM_EXPR, nft_set_ext_expr(ext)) < 0)
 		goto nla_put_failure;
 
+	if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF) &&
+	    nla_put_string(skb, NFTA_SET_ELEM_OBJREF,
+			   (*nft_set_ext_obj(ext))->name) < 0)
+		goto nla_put_failure;
+
 	if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
 	    nla_put_be32(skb, NFTA_SET_ELEM_FLAGS,
 		         htonl(*nft_set_ext_flags(ext))))
@@ -3508,7 +3536,8 @@ void nft_set_elem_destroy(const struct nft_set *set, void *elem,
 		nft_data_uninit(nft_set_ext_data(ext), set->dtype);
 	if (destroy_expr && nft_set_ext_exists(ext, NFT_SET_EXT_EXPR))
 		nf_tables_expr_destroy(NULL, nft_set_ext_expr(ext));
-
+	if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
+		(*nft_set_ext_obj(ext))->use--;
 	kfree(elem);
 }
 EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
@@ -3533,11 +3562,13 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
 			    const struct nlattr *attr, u32 nlmsg_flags)
 {
 	struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
+	u8 genmask = nft_genmask_next(ctx->net);
 	struct nft_data_desc d1, d2;
 	struct nft_set_ext_tmpl tmpl;
 	struct nft_set_ext *ext, *ext2;
 	struct nft_set_elem elem;
 	struct nft_set_binding *binding;
+	struct nft_object *obj = NULL;
 	struct nft_userdata *udata;
 	struct nft_data data;
 	enum nft_registers dreg;
@@ -3600,6 +3631,20 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
 			nft_set_ext_add(&tmpl, NFT_SET_EXT_TIMEOUT);
 	}
 
+	if (nla[NFTA_SET_ELEM_OBJREF] != NULL) {
+		if (!(set->flags & NFT_SET_OBJECT)) {
+			err = -EINVAL;
+			goto err2;
+		}
+		obj = nf_tables_obj_lookup(ctx->table, nla[NFTA_SET_ELEM_OBJREF],
+					   set->objtype, genmask);
+		if (IS_ERR(obj)) {
+			err = PTR_ERR(obj);
+			goto err2;
+		}
+		nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF);
+	}
+
 	if (nla[NFTA_SET_ELEM_DATA] != NULL) {
 		err = nft_data_init(ctx, &data, sizeof(data), &d2,
 				    nla[NFTA_SET_ELEM_DATA]);
@@ -3658,6 +3703,10 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
 		udata->len = ulen - 1;
 		nla_memcpy(&udata->data, nla[NFTA_SET_ELEM_USERDATA], ulen);
 	}
+	if (obj) {
+		*nft_set_ext_obj(ext) = obj;
+		obj->use++;
+	}
 
 	trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set);
 	if (trans == NULL)
@@ -3667,10 +3716,13 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
 	err = set->ops->insert(ctx->net, set, &elem, &ext2);
 	if (err) {
 		if (err == -EEXIST) {
-			if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) &&
-			    nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) &&
-			    memcmp(nft_set_ext_data(ext),
-				   nft_set_ext_data(ext2), set->dlen) != 0)
+			if ((nft_set_ext_exists(ext, NFT_SET_EXT_DATA) &&
+			     nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) &&
+			     memcmp(nft_set_ext_data(ext),
+				    nft_set_ext_data(ext2), set->dlen) != 0) ||
+			    (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF) &&
+			     nft_set_ext_exists(ext2, NFT_SET_EXT_OBJREF) &&
+			     *nft_set_ext_obj(ext) != *nft_set_ext_obj(ext2)))
 				err = -EBUSY;
 			else if (!(nlmsg_flags & NLM_F_EXCL))
 				err = 0;
-- 
2.1.4

  parent reply	other threads:[~2016-12-07 21:52 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-12-07 21:52 [PATCH 00/50] Netfilter/IPVS updates for net-next Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 01/50] ipvs: Use IS_ERR_OR_NULL(svc) instead of IS_ERR(svc) || svc == NULL Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 02/50] ipvs: Decrement ttl Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 03/50] netfilter: update Arturo Borrero Gonzalez email address Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 04/50] netfilter: built-in NAT support for DCCP Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 05/50] netfilter: built-in NAT support for SCTP Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 06/50] netfilter: built-in NAT support for UDPlite Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 07/50] netfilter: nf_log: do not assume ethernet header in netdev family Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 08/50] netfilter: nfnetlink_log: add "nf-logger-5-1" module alias name Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 09/50] netfilter: nf_conntrack_tuple_common.h: fix #include Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 10/50] netfilter: conntrack: built-in support for DCCP Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 11/50] netfilter: conntrack: built-in support for SCTP Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 12/50] netfilter: conntrack: built-in support for UDPlite Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 13/50] netfilter: conntrack: remove unused init_net hook Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 14/50] netfilter: add and use nf_ct_netns_get/put Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 15/50] netfilter: nat: add dependencies on conntrack module Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 16/50] netfilter: nf_tables: add conntrack dependencies for nat/masq/redir expressions Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 17/50] netfilter: conntrack: register hooks in netns when needed by ruleset Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 18/50] netfilter: conntrack: add nf_conntrack_default_on sysctl Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 19/50] netfilter: defrag: only register defrag functionality if needed Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 20/50] netfilter: introduce accessor functions for hook entries Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 21/50] netfilter: decouple nf_hook_entry and nf_hook_ops Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 22/50] netfilter: convert while loops to for loops Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 23/50] netfilter: x_tables: pass xt_counters struct instead of packet counter Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 24/50] netfilter: x_tables: pass xt_counters struct to counter allocator Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 25/50] netfilter: x_tables: pack percpu counter allocations Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 26/50] netfilter: nft_fib: convert htonl to ntohl properly Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 27/50] netfilter: nft_fib_ipv4: initialize *dest to zero Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 28/50] netfilter: nft_payload: layer 4 checksum adjustment for pseudoheader fields Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 29/50] netfilter: xt_multiport: Fix wrong unmatch result with multiple ports Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 30/50] netfilter: ingress: translate 0 nf_hook_slow retval to -1 Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 31/50] netfilter: add and use nf_fwd_netdev_egress Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 32/50] netfilter: nf_tables: add stateful objects Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 33/50] netfilter: nft_counter: add stateful object type Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 34/50] netfilter: nft_quota: " Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 35/50] netfilter: nf_tables: add stateful object reference expression Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 36/50] netfilter: nft_quota: dump consumed quota Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 37/50] netfilter: nf_tables: atomic dump and reset for stateful objects Pablo Neira Ayuso
2016-12-09  0:40   ` Paul Gortmaker
2016-12-09 10:24     ` Pablo Neira Ayuso
2016-12-09 14:24       ` Eric Dumazet
2016-12-09 15:22         ` Eric Dumazet
2016-12-10 12:21           ` Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 38/50] netfilter: nf_tables: notify internal updates of " Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 39/50] netfilter: nft_quota: add depleted flag for objects Pablo Neira Ayuso
2016-12-07 21:52 ` Pablo Neira Ayuso [this message]
2016-12-07 21:52 ` [PATCH 41/50] netfilter: nft_objref: support for stateful object maps Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 42/50] netfilter: nf_tables: allow to filter stateful object dumps by type Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 43/50] netfilter: rpfilter: bypass ipv4 lbcast packets with zeronet source Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 44/50] netfilter: nat: skip checksum on offload SCTP packets Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 45/50] netfilter: nf_tables: constify struct nft_ctx * parameter in nft_trans_alloc() Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 46/50] netfilter: nft_set: introduce nft_{hash, rbtree}_deactivate_one() Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 47/50] netfilter: nf_tables: support for set flushing Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 48/50] netfilter: x_tables: avoid warn and OOM killer on vmalloc call Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 49/50] netfilter: xt_bpf: support ebpf Pablo Neira Ayuso
2016-12-07 21:52 ` [PATCH 50/50] netfilter: nft_quota: allow to restore consumed quota Pablo Neira Ayuso
2016-12-08  0:29 ` [PATCH 00/50] Netfilter/IPVS updates for net-next David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1481147576-5690-41-git-send-email-pablo@netfilter.org \
    --to=pablo@netfilter.org \
    --cc=davem@davemloft.net \
    --cc=netdev@vger.kernel.org \
    --cc=netfilter-devel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).