netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Pablo Neira Ayuso <pablo@netfilter.org>
To: Eric Leblond <eric@regit.org>
Cc: Florian Westphal <fw@strlen.de>, netfilter-devel@vger.kernel.org
Subject: Re: [PATCHv2] netfilter: nft: add queue module
Date: Wed, 4 Dec 2013 12:00:21 +0100	[thread overview]
Message-ID: <20131204110021.GA11380@localhost> (raw)
In-Reply-To: <1385824444-4506-1-git-send-email-eric@regit.org>

Hi Eric,

First off, thanks for this patch. Some comments below.

On Sat, Nov 30, 2013 at 04:14:04PM +0100, Eric Leblond wrote:
> This patch adds a new nft module named "nft_queue" which is a
> nftables target sending packet to nfnetlink_queue subsystem. It has
> the same level of functionnality as is iptables ancestor and share
> some code with it.
> 
> Signed-off-by: Eric Leblond <eric@regit.org>
> ---
>  include/uapi/linux/netfilter/nf_tables.h |  20 ++++
>  net/netfilter/Kconfig                    |   9 ++
>  net/netfilter/Makefile                   |   1 +
>  net/netfilter/nft_queue.c                | 192 +++++++++++++++++++++++++++++++
>  4 files changed, 222 insertions(+)
>  create mode 100644 net/netfilter/nft_queue.c
> 
> diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
> index fbfd229..256d36b 100644
> --- a/include/uapi/linux/netfilter/nf_tables.h
> +++ b/include/uapi/linux/netfilter/nf_tables.h
> @@ -658,6 +658,26 @@ enum nft_log_attributes {
>  #define NFTA_LOG_MAX		(__NFTA_LOG_MAX - 1)
>  
>  /**
> + * enum nft_queue_attributes - nf_tables queue expression netlink attributes
> + *
> + * @NFTA_QUEUE_NUM: netlink queue to send messages to (NLA_U16)
> + * @NFTA_QUEUE_TOTAL: number of queues to load balance packets on (NLA_U16)
> + * @NFTA_QUEUE_FLAGS: various flags (NLA_U16)
> + */
> +enum nft_queue_attributes {
> +	NFTA_QUEUE_UNSPEC,
> +	NFTA_QUEUE_NUM,
> +	NFTA_QUEUE_TOTAL,
> +	NFTA_QUEUE_FLAGS,
> +	__NFTA_QUEUE_MAX
> +};
> +#define NFTA_QUEUE_MAX		(__NFTA_QUEUE_MAX - 1)
> +
> +#define NFT_QUEUE_FLAG_BYPASS		0x01 /* for compatibility with v2 */
> +#define NFT_QUEUE_FLAG_CPU_FANOUT	0x02 /* use current CPU (no hashing) */
> +#define NFT_QUEUE_FLAG_MASK		0x03
> +
> +/**
>   * enum nft_reject_types - nf_tables reject expression reject types
>   *
>   * @NFT_REJECT_ICMP_UNREACH: reject using ICMP unreachable
> diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
> index c3398cd..cf0872d 100644
> --- a/net/netfilter/Kconfig
> +++ b/net/netfilter/Kconfig
> @@ -456,6 +456,15 @@ config NFT_NAT
>  	depends on NF_NAT
>  	tristate "Netfilter nf_tables nat module"
>  
> +config NFT_QUEUE
> +	depends on NF_TABLES
> +	depends on NETFILTER_XTABLES
> +	depends on NETFILTER_NETLINK_QUEUE
> +	tristate "Netfilter nf_tables queue module"
> +	help
> +	  This is required if you intend to use nfnetlink queue
> +	  on more than the default queue 0 or with the other features
> +
>  config NFT_COMPAT
>  	depends on NF_TABLES
>  	depends on NETFILTER_XTABLES
> diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
> index 394483b..e763746 100644
> --- a/net/netfilter/Makefile
> +++ b/net/netfilter/Makefile
> @@ -76,6 +76,7 @@ obj-$(CONFIG_NFT_META)		+= nft_meta.o
>  obj-$(CONFIG_NFT_CT)		+= nft_ct.o
>  obj-$(CONFIG_NFT_LIMIT)		+= nft_limit.o
>  obj-$(CONFIG_NFT_NAT)		+= nft_nat.o
> +obj-$(CONFIG_NFT_QUEUE)		+= nft_queue.o
>  #nf_tables-objs			+= nft_meta_target.o
>  obj-$(CONFIG_NFT_RBTREE)	+= nft_rbtree.o
>  obj-$(CONFIG_NFT_HASH)		+= nft_hash.o
> diff --git a/net/netfilter/nft_queue.c b/net/netfilter/nft_queue.c
> new file mode 100644
> index 0000000..88cdf16
> --- /dev/null
> +++ b/net/netfilter/nft_queue.c
> @@ -0,0 +1,192 @@
> +/*
> + * Copyright (c) 2013 Eric Leblond <eric@regit.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/netlink.h>
> +
> +#include <linux/ip.h>
> +#include <linux/ipv6.h>
> +#include <linux/jhash.h>
> +
> +#include <linux/jhash.h>
> +#include <linux/netfilter.h>
> +#include <linux/netfilter/nf_tables.h>
> +#include <net/netfilter/nf_tables.h>
> +
> +struct nft_queue {
> +	u16			queuenum;
> +	u16			queues_total;
> +	u16			flags;
> +	int			family;
                                ^
This structure is very important that it doesn't have any hole (at its
best) to reduce the size of the expression area in the rule. My
proposal:

...
{
	u16			queue_num;
	u16			queue_total;
	u16			flags;
	u8			family;
}

> +};
> +
> +static u32 jhash_initval __read_mostly;

>From here:

> +static u32 hash_v4(const struct sk_buff *skb)
> +{
> +	const struct iphdr *iph = ip_hdr(skb);
> +
> +	/* packets in either direction go into same queue */
> +	if ((__force u32)iph->saddr < (__force u32)iph->daddr)
> +		return jhash_3words((__force u32)iph->saddr,
> +			(__force u32)iph->daddr, iph->protocol, jhash_initval);
> +
> +	return jhash_3words((__force u32)iph->daddr,
> +			(__force u32)iph->saddr, iph->protocol, jhash_initval);
> +}
> +
> +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
> +static u32 hash_v6(const struct sk_buff *skb)
> +{
> +	const struct ipv6hdr *ip6h = ipv6_hdr(skb);
> +	u32 a, b, c;
> +
> +	if ((__force u32)ip6h->saddr.s6_addr32[3] <
> +	    (__force u32)ip6h->daddr.s6_addr32[3]) {
> +		a = (__force u32) ip6h->saddr.s6_addr32[3];
> +		b = (__force u32) ip6h->daddr.s6_addr32[3];
> +	} else {
> +		b = (__force u32) ip6h->saddr.s6_addr32[3];
> +		a = (__force u32) ip6h->daddr.s6_addr32[3];
> +	}
> +
> +	if ((__force u32)ip6h->saddr.s6_addr32[1] <
> +	    (__force u32)ip6h->daddr.s6_addr32[1])
> +		c = (__force u32) ip6h->saddr.s6_addr32[1];
> +	else
> +		c = (__force u32) ip6h->daddr.s6_addr32[1];
> +
> +	return jhash_3words(a, b, c, jhash_initval);
> +}
> +#endif
> +
> +static u32
> +nfqueue_hash(const struct nft_pktinfo *pkt, const struct nft_queue *priv)
> +{
> +	u32 queue = priv->queuenum;
> +
> +	if (priv->family == AF_INET)
> +		queue += ((u64) hash_v4(pkt->skb) * priv->queues_total) >> 32;
> +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
> +	else if (priv->family == AF_INET6)
> +		queue += ((u64) hash_v6(pkt->skb) * priv->queues_total) >> 32;
> +#endif
> +
> +	return queue;
> +}

to there, it looks very similar to NFQUEUE. You can move these
functions to net/netfilter/nf_queue.h. You'll have to inline them and
add the jhash_initval parameter. You'll need an initial patch to
prepare this change and adapt xt_NFQUEUE.c

> +
> +static void nft_queue_eval(const struct nft_expr *expr,
> +			      struct nft_data data[NFT_REG_MAX + 1],
> +			      const struct nft_pktinfo *pkt)
> +{
> +	struct nft_queue *priv = nft_expr_priv(expr);
> +	u32 queue = priv->queuenum;
> +	u32 ret;
> +
> +	if (priv->queues_total > 1) {
> +		if (priv->flags & NFT_QUEUE_FLAG_CPU_FANOUT) {
> +			int cpu = smp_processor_id();
> +
> +			queue = priv->queuenum + cpu % priv->queues_total;
> +		} else
> +			queue = nfqueue_hash(pkt, priv);
> +	}
> +
> +	ret = NF_QUEUE_NR(queue);
> +	if (priv->flags & NFT_QUEUE_FLAG_BYPASS)
> +		ret |= NF_VERDICT_FLAG_QUEUE_BYPASS;
> +
> +	data[NFT_REG_VERDICT].verdict = ret;
> +}
> +
> +static const struct nla_policy nft_queue_policy[NFTA_QUEUE_MAX + 1] = {
> +	[NFTA_QUEUE_NUM]		= { .type = NLA_U16 },
> +	[NFTA_QUEUE_TOTAL]		= { .type = NLA_U16 },
> +	[NFTA_QUEUE_FLAGS]		= { .type = NLA_U16 },
                          ^------------^
Comestic: I think one tab should be fine.

> +};
> +
> +static int nft_queue_init(const struct nft_ctx *ctx,
> +			   const struct nft_expr *expr,
> +			   const struct nlattr * const tb[])
> +{
> +	struct nft_queue *priv = nft_expr_priv(expr);
> +
> +	while (jhash_initval == 0)
> +		jhash_initval = prandom_u32();

Different initialization approach with regards to xt_NFQUEUE, any
reason for that change?

> +
> +	priv->family = ctx->afi->family;
> +
> +	if (tb[NFTA_QUEUE_NUM] == NULL)
> +		return -EINVAL;
> +	priv->queuenum = ntohs(nla_get_be16(tb[NFTA_QUEUE_NUM]));
> +
> +	if (tb[NFTA_QUEUE_TOTAL] != NULL)
> +		priv->queues_total = ntohs(nla_get_be16(tb[NFTA_QUEUE_TOTAL]));
> +	if (tb[NFTA_QUEUE_FLAGS] != NULL) {
> +		priv->flags = ntohs(nla_get_be16(tb[NFTA_QUEUE_FLAGS]));
> +		if (priv->flags & ~NFT_QUEUE_FLAG_MASK)
> +			return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +static int nft_queue_dump(struct sk_buff *skb, const struct nft_expr *expr)
> +{
> +	const struct nft_queue *priv = nft_expr_priv(expr);
> +
> +	if (nla_put_be16(skb, NFTA_QUEUE_NUM, htons(priv->queuenum)))
> +		goto nla_put_failure;
> +
> +	if (nla_put_be16(skb, NFTA_QUEUE_TOTAL, htons(priv->queues_total)))
> +		goto nla_put_failure;
> +
> +	if (nla_put_be16(skb, NFTA_QUEUE_FLAGS, htons(priv->flags)))
> +		goto nla_put_failure;

Comestic: Perhaps you can squash these three put lines in one single
if to save a couple of lines, the code will be still quite readable.

> +
> +	return 0;
> +
> +nla_put_failure:
> +	return -1;
> +}
> +
> +static struct nft_expr_type nft_queue_type;
> +static const struct nft_expr_ops nft_queue_ops = {
> +	.type		= &nft_queue_type,
> +	.size		= NFT_EXPR_SIZE(sizeof(struct nft_queue)),
> +	.eval		= nft_queue_eval,
> +	.init		= nft_queue_init,
> +	.dump		= nft_queue_dump,
> +};
> +
> +static struct nft_expr_type nft_queue_type __read_mostly = {
> +	.name		= "queue",
> +	.ops		= &nft_queue_ops,
> +	.policy		= nft_queue_policy,
> +	.maxattr	= NFTA_QUEUE_MAX,
> +	.owner		= THIS_MODULE,
> +};
> +
> +static int __init nft_queue_module_init(void)
> +{
> +	return nft_register_expr(&nft_queue_type);
> +}
> +
> +static void __exit nft_queue_module_exit(void)
> +{
> +	nft_unregister_expr(&nft_queue_type);
> +}
> +
> +module_init(nft_queue_module_init);
> +module_exit(nft_queue_module_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Eric Leblond <eric@regit.org>");
> +MODULE_ALIAS_NFT_EXPR("queue");
> -- 
> 1.8.4.4
> 

  reply	other threads:[~2013-12-04 11:00 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-11-30 10:52 [nft PATCH] add support for queue target Eric Leblond
2013-11-30 10:56 ` [PATCH 1/2] netfilter: nft: fix issue with verdict support Eric Leblond
2013-11-30 10:56   ` [PATCH 2/2] netfilter: nft: add queue module Eric Leblond
2013-11-30 12:26     ` Florian Westphal
2013-11-30 15:14       ` [PATCHv2] " Eric Leblond
2013-12-04 11:00         ` Pablo Neira Ayuso [this message]
2013-12-04 11:31           ` Florian Westphal
2013-12-04 11:39             ` Pablo Neira Ayuso
2013-12-04 12:47           ` Eric Leblond
2013-12-05 17:09             ` Pablo Neira Ayuso
2013-12-05 21:31               ` [PATCHv3 0/3] add nft_queue module Eric Leblond
2013-12-05 21:31                 ` [PATCHv3 1/3] netfilter: nft: fix issue with verdict support Eric Leblond
2013-12-05 21:31                 ` [PATCHv3 2/3] netfilter: xt_NFQUEUE: separate reusable code Eric Leblond
2013-12-05 21:41                   ` Pablo Neira Ayuso
2013-12-05 23:24                     ` [PATCHv4 0/3] add nft_queue module Eric Leblond
2013-12-05 23:24                       ` [PATCHv4 1/3] netfilter: nft: fix issue with verdict support Eric Leblond
2013-12-05 23:24                       ` [PATCHv4 2/3] netfilter: xt_NFQUEUE: separate reusable code Eric Leblond
2013-12-07 22:56                         ` Pablo Neira Ayuso
2013-12-05 23:24                       ` [PATCHv4 3/3] netfilter: nft: add queue module Eric Leblond
2013-12-07 22:57                       ` [PATCHv4 0/3] add nft_queue module Pablo Neira Ayuso
2013-12-10 10:09                         ` Eric Leblond
2013-12-05 21:31                 ` [PATCHv3 3/3] netfilter: nft: add queue module Eric Leblond
2013-12-02  6:39     ` [PATCH 2/2] " Tomasz Bursztyka
2013-12-02  9:32       ` Eric Leblond
2013-12-02 11:03         ` Tomasz Bursztyka
2013-11-30 10:57 ` [libnftables PATCH 1/2] expr: add support for nfnetlink queue Eric Leblond
2013-11-30 10:57   ` [libnftables PATCH 2/2] test: add tests for expr queue Eric Leblond
2013-12-10 10:03   ` [libnftables PATCH 1/2] expr: add support for nfnetlink queue Pablo Neira Ayuso
2013-11-30 10:57 ` [nft PATCH] Add support for queue target Eric Leblond
2013-12-29 18:28   ` [nftables PATCHv2 0/1] Support " Eric Leblond
2013-12-29 18:28     ` [nftables PATCHv2] Add support " Eric Leblond
2014-01-04  0:09       ` Pablo Neira Ayuso

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=20131204110021.GA11380@localhost \
    --to=pablo@netfilter.org \
    --cc=eric@regit.org \
    --cc=fw@strlen.de \
    --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).