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
;
31 static void nft_queue_eval(const struct nft_expr
*expr
,
32 struct nft_data data
[NFT_REG_MAX
+ 1],
33 const struct nft_pktinfo
*pkt
)
35 struct nft_queue
*priv
= nft_expr_priv(expr
);
36 u32 queue
= priv
->queuenum
;
39 if (priv
->queues_total
> 1) {
40 if (priv
->flags
& NFT_QUEUE_FLAG_CPU_FANOUT
) {
41 int cpu
= smp_processor_id();
43 queue
= priv
->queuenum
+ cpu
% priv
->queues_total
;
45 queue
= nfqueue_hash(pkt
->skb
, queue
,
46 priv
->queues_total
, priv
->family
,
51 ret
= NF_QUEUE_NR(queue
);
52 if (priv
->flags
& NFT_QUEUE_FLAG_BYPASS
)
53 ret
|= NF_VERDICT_FLAG_QUEUE_BYPASS
;
55 data
[NFT_REG_VERDICT
].verdict
= ret
;
58 static const struct nla_policy nft_queue_policy
[NFTA_QUEUE_MAX
+ 1] = {
59 [NFTA_QUEUE_NUM
] = { .type
= NLA_U16
},
60 [NFTA_QUEUE_TOTAL
] = { .type
= NLA_U16
},
61 [NFTA_QUEUE_FLAGS
] = { .type
= NLA_U16
},
64 static int nft_queue_init(const struct nft_ctx
*ctx
,
65 const struct nft_expr
*expr
,
66 const struct nlattr
* const tb
[])
68 struct nft_queue
*priv
= nft_expr_priv(expr
);
70 if (tb
[NFTA_QUEUE_NUM
] == NULL
)
73 init_hashrandom(&jhash_initval
);
74 priv
->family
= ctx
->afi
->family
;
75 priv
->queuenum
= ntohs(nla_get_be16(tb
[NFTA_QUEUE_NUM
]));
77 if (tb
[NFTA_QUEUE_TOTAL
] != NULL
)
78 priv
->queues_total
= ntohs(nla_get_be16(tb
[NFTA_QUEUE_TOTAL
]));
79 if (tb
[NFTA_QUEUE_FLAGS
] != NULL
) {
80 priv
->flags
= ntohs(nla_get_be16(tb
[NFTA_QUEUE_FLAGS
]));
81 if (priv
->flags
& ~NFT_QUEUE_FLAG_MASK
)
87 static int nft_queue_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
89 const struct nft_queue
*priv
= nft_expr_priv(expr
);
91 if (nla_put_be16(skb
, NFTA_QUEUE_NUM
, htons(priv
->queuenum
)) ||
92 nla_put_be16(skb
, NFTA_QUEUE_TOTAL
, htons(priv
->queues_total
)) ||
93 nla_put_be16(skb
, NFTA_QUEUE_FLAGS
, htons(priv
->flags
)))
102 static struct nft_expr_type nft_queue_type
;
103 static const struct nft_expr_ops nft_queue_ops
= {
104 .type
= &nft_queue_type
,
105 .size
= NFT_EXPR_SIZE(sizeof(struct nft_queue
)),
106 .eval
= nft_queue_eval
,
107 .init
= nft_queue_init
,
108 .dump
= nft_queue_dump
,
111 static struct nft_expr_type nft_queue_type __read_mostly
= {
113 .ops
= &nft_queue_ops
,
114 .policy
= nft_queue_policy
,
115 .maxattr
= NFTA_QUEUE_MAX
,
116 .owner
= THIS_MODULE
,
119 static int __init
nft_queue_module_init(void)
121 return nft_register_expr(&nft_queue_type
);
124 static void __exit
nft_queue_module_exit(void)
126 nft_unregister_expr(&nft_queue_type
);
129 module_init(nft_queue_module_init
);
130 module_exit(nft_queue_module_exit
);
132 MODULE_LICENSE("GPL");
133 MODULE_AUTHOR("Eric Leblond <eric@regit.org>");
134 MODULE_ALIAS_NFT_EXPR("queue");