2 * Copyright (c) 2013 Eric Leblond <eric@regit.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * Development of this code partly funded by OISF
9 * (http://www.openinfosecfoundation.org/)
12 #include <linux/kernel.h>
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/netlink.h>
16 #include <linux/jhash.h>
17 #include <linux/netfilter.h>
18 #include <linux/netfilter/nf_tables.h>
19 #include <net/netfilter/nf_tables.h>
20 #include <net/netfilter/nf_queue.h>
22 static u32 jhash_initval __read_mostly
;
30 static void nft_queue_eval(const struct nft_expr
*expr
,
31 struct nft_data data
[NFT_REG_MAX
+ 1],
32 const struct nft_pktinfo
*pkt
)
34 struct nft_queue
*priv
= nft_expr_priv(expr
);
35 u32 queue
= priv
->queuenum
;
38 if (priv
->queues_total
> 1) {
39 if (priv
->flags
& NFT_QUEUE_FLAG_CPU_FANOUT
) {
40 int cpu
= smp_processor_id();
42 queue
= priv
->queuenum
+ cpu
% priv
->queues_total
;
44 queue
= nfqueue_hash(pkt
->skb
, queue
,
45 priv
->queues_total
, pkt
->ops
->pf
,
50 ret
= NF_QUEUE_NR(queue
);
51 if (priv
->flags
& NFT_QUEUE_FLAG_BYPASS
)
52 ret
|= NF_VERDICT_FLAG_QUEUE_BYPASS
;
54 data
[NFT_REG_VERDICT
].verdict
= ret
;
57 static const struct nla_policy nft_queue_policy
[NFTA_QUEUE_MAX
+ 1] = {
58 [NFTA_QUEUE_NUM
] = { .type
= NLA_U16
},
59 [NFTA_QUEUE_TOTAL
] = { .type
= NLA_U16
},
60 [NFTA_QUEUE_FLAGS
] = { .type
= NLA_U16
},
63 static int nft_queue_init(const struct nft_ctx
*ctx
,
64 const struct nft_expr
*expr
,
65 const struct nlattr
* const tb
[])
67 struct nft_queue
*priv
= nft_expr_priv(expr
);
69 if (tb
[NFTA_QUEUE_NUM
] == NULL
)
72 init_hashrandom(&jhash_initval
);
73 priv
->queuenum
= ntohs(nla_get_be16(tb
[NFTA_QUEUE_NUM
]));
75 if (tb
[NFTA_QUEUE_TOTAL
] != NULL
)
76 priv
->queues_total
= ntohs(nla_get_be16(tb
[NFTA_QUEUE_TOTAL
]));
77 if (tb
[NFTA_QUEUE_FLAGS
] != NULL
) {
78 priv
->flags
= ntohs(nla_get_be16(tb
[NFTA_QUEUE_FLAGS
]));
79 if (priv
->flags
& ~NFT_QUEUE_FLAG_MASK
)
85 static int nft_queue_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
87 const struct nft_queue
*priv
= nft_expr_priv(expr
);
89 if (nla_put_be16(skb
, NFTA_QUEUE_NUM
, htons(priv
->queuenum
)) ||
90 nla_put_be16(skb
, NFTA_QUEUE_TOTAL
, htons(priv
->queues_total
)) ||
91 nla_put_be16(skb
, NFTA_QUEUE_FLAGS
, htons(priv
->flags
)))
100 static struct nft_expr_type nft_queue_type
;
101 static const struct nft_expr_ops nft_queue_ops
= {
102 .type
= &nft_queue_type
,
103 .size
= NFT_EXPR_SIZE(sizeof(struct nft_queue
)),
104 .eval
= nft_queue_eval
,
105 .init
= nft_queue_init
,
106 .dump
= nft_queue_dump
,
109 static struct nft_expr_type nft_queue_type __read_mostly
= {
111 .ops
= &nft_queue_ops
,
112 .policy
= nft_queue_policy
,
113 .maxattr
= NFTA_QUEUE_MAX
,
114 .owner
= THIS_MODULE
,
117 static int __init
nft_queue_module_init(void)
119 return nft_register_expr(&nft_queue_type
);
122 static void __exit
nft_queue_module_exit(void)
124 nft_unregister_expr(&nft_queue_type
);
127 module_init(nft_queue_module_init
);
128 module_exit(nft_queue_module_exit
);
130 MODULE_LICENSE("GPL");
131 MODULE_AUTHOR("Eric Leblond <eric@regit.org>");
132 MODULE_ALIAS_NFT_EXPR("queue");