aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorLiping Zhang <liping.zhang@spreadtrum.com>2016-09-14 11:41:46 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2016-09-23 03:29:50 -0400
commit8061bb54436c19fd16b7c734a69ff60bac26e3e9 (patch)
treedc741bf1d2d48f5645dc42dcdbc20a5b1678c3f4 /net
parent36b701fae12ac763a568037e4e7c96b5727a8b3e (diff)
netfilter: nft_queue: add _SREG_QNUM attr to select the queue number
Currently, the user can specify the queue numbers by _QUEUE_NUM and _QUEUE_TOTAL attributes, this is enough in most situations. But acctually, it is not very flexible, for example: tcp dport 80 mapped to queue0 tcp dport 81 mapped to queue1 tcp dport 82 mapped to queue2 In order to do this thing, we must add 3 nft rules, and more mapping meant more rules ... So take one register to select the queue number, then we can add one simple rule to mapping queues, maybe like this: queue num tcp dport map { 80:0, 81:1, 82:2 ... } Florian Westphal also proposed wider usage scenarios: queue num jhash ip saddr . ip daddr mod ... queue num meta cpu ... queue num meta mark ... The last point is how to load a queue number from sreg, although we can use *(u16*)&regs->data[reg] to load the queue number, just like nat expr to load its l4port do. But we will cooperate with hash expr, meta cpu, meta mark expr and so on. They all store the result to u32 type, so cast it to u16 pointer and dereference it will generate wrong result in the big endian system. So just keep it simple, we treat queue number as u32 type, although u16 type is already enough. Suggested-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: Liping Zhang <liping.zhang@spreadtrum.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/nft_queue.c102
1 files changed, 90 insertions, 12 deletions
diff --git a/net/netfilter/nft_queue.c b/net/netfilter/nft_queue.c
index d16d59959ff6..393d359a1889 100644
--- a/net/netfilter/nft_queue.c
+++ b/net/netfilter/nft_queue.c
@@ -22,9 +22,10 @@
22static u32 jhash_initval __read_mostly; 22static u32 jhash_initval __read_mostly;
23 23
24struct nft_queue { 24struct nft_queue {
25 u16 queuenum; 25 enum nft_registers sreg_qnum:8;
26 u16 queues_total; 26 u16 queuenum;
27 u16 flags; 27 u16 queues_total;
28 u16 flags;
28}; 29};
29 30
30static void nft_queue_eval(const struct nft_expr *expr, 31static void nft_queue_eval(const struct nft_expr *expr,
@@ -54,26 +55,39 @@ static void nft_queue_eval(const struct nft_expr *expr,
54 regs->verdict.code = ret; 55 regs->verdict.code = ret;
55} 56}
56 57
58static void nft_queue_sreg_eval(const struct nft_expr *expr,
59 struct nft_regs *regs,
60 const struct nft_pktinfo *pkt)
61{
62 struct nft_queue *priv = nft_expr_priv(expr);
63 u32 queue, ret;
64
65 queue = regs->data[priv->sreg_qnum];
66
67 ret = NF_QUEUE_NR(queue);
68 if (priv->flags & NFT_QUEUE_FLAG_BYPASS)
69 ret |= NF_VERDICT_FLAG_QUEUE_BYPASS;
70
71 regs->verdict.code = ret;
72}
73
57static const struct nla_policy nft_queue_policy[NFTA_QUEUE_MAX + 1] = { 74static const struct nla_policy nft_queue_policy[NFTA_QUEUE_MAX + 1] = {
58 [NFTA_QUEUE_NUM] = { .type = NLA_U16 }, 75 [NFTA_QUEUE_NUM] = { .type = NLA_U16 },
59 [NFTA_QUEUE_TOTAL] = { .type = NLA_U16 }, 76 [NFTA_QUEUE_TOTAL] = { .type = NLA_U16 },
60 [NFTA_QUEUE_FLAGS] = { .type = NLA_U16 }, 77 [NFTA_QUEUE_FLAGS] = { .type = NLA_U16 },
78 [NFTA_QUEUE_SREG_QNUM] = { .type = NLA_U32 },
61}; 79};
62 80
63static int nft_queue_init(const struct nft_ctx *ctx, 81static int nft_queue_init(const struct nft_ctx *ctx,
64 const struct nft_expr *expr, 82 const struct nft_expr *expr,
65 const struct nlattr * const tb[]) 83 const struct nlattr * const tb[])
66{ 84{
67 struct nft_queue *priv = nft_expr_priv(expr); 85 struct nft_queue *priv = nft_expr_priv(expr);
68 u32 maxid; 86 u32 maxid;
69 87
70 if (tb[NFTA_QUEUE_NUM] == NULL)
71 return -EINVAL;
72
73 init_hashrandom(&jhash_initval);
74 priv->queuenum = ntohs(nla_get_be16(tb[NFTA_QUEUE_NUM])); 88 priv->queuenum = ntohs(nla_get_be16(tb[NFTA_QUEUE_NUM]));
75 89
76 if (tb[NFTA_QUEUE_TOTAL] != NULL) 90 if (tb[NFTA_QUEUE_TOTAL])
77 priv->queues_total = ntohs(nla_get_be16(tb[NFTA_QUEUE_TOTAL])); 91 priv->queues_total = ntohs(nla_get_be16(tb[NFTA_QUEUE_TOTAL]));
78 else 92 else
79 priv->queues_total = 1; 93 priv->queues_total = 1;
@@ -85,11 +99,34 @@ static int nft_queue_init(const struct nft_ctx *ctx,
85 if (maxid > U16_MAX) 99 if (maxid > U16_MAX)
86 return -ERANGE; 100 return -ERANGE;
87 101
88 if (tb[NFTA_QUEUE_FLAGS] != NULL) { 102 if (tb[NFTA_QUEUE_FLAGS]) {
103 priv->flags = ntohs(nla_get_be16(tb[NFTA_QUEUE_FLAGS]));
104 if (priv->flags & ~NFT_QUEUE_FLAG_MASK)
105 return -EINVAL;
106 }
107 return 0;
108}
109
110static int nft_queue_sreg_init(const struct nft_ctx *ctx,
111 const struct nft_expr *expr,
112 const struct nlattr * const tb[])
113{
114 struct nft_queue *priv = nft_expr_priv(expr);
115 int err;
116
117 priv->sreg_qnum = nft_parse_register(tb[NFTA_QUEUE_SREG_QNUM]);
118 err = nft_validate_register_load(priv->sreg_qnum, sizeof(u32));
119 if (err < 0)
120 return err;
121
122 if (tb[NFTA_QUEUE_FLAGS]) {
89 priv->flags = ntohs(nla_get_be16(tb[NFTA_QUEUE_FLAGS])); 123 priv->flags = ntohs(nla_get_be16(tb[NFTA_QUEUE_FLAGS]));
90 if (priv->flags & ~NFT_QUEUE_FLAG_MASK) 124 if (priv->flags & ~NFT_QUEUE_FLAG_MASK)
91 return -EINVAL; 125 return -EINVAL;
126 if (priv->flags & NFT_QUEUE_FLAG_CPU_FANOUT)
127 return -EOPNOTSUPP;
92 } 128 }
129
93 return 0; 130 return 0;
94} 131}
95 132
@@ -108,6 +145,21 @@ nla_put_failure:
108 return -1; 145 return -1;
109} 146}
110 147
148static int
149nft_queue_sreg_dump(struct sk_buff *skb, const struct nft_expr *expr)
150{
151 const struct nft_queue *priv = nft_expr_priv(expr);
152
153 if (nft_dump_register(skb, NFTA_QUEUE_SREG_QNUM, priv->sreg_qnum) ||
154 nla_put_be16(skb, NFTA_QUEUE_FLAGS, htons(priv->flags)))
155 goto nla_put_failure;
156
157 return 0;
158
159nla_put_failure:
160 return -1;
161}
162
111static struct nft_expr_type nft_queue_type; 163static struct nft_expr_type nft_queue_type;
112static const struct nft_expr_ops nft_queue_ops = { 164static const struct nft_expr_ops nft_queue_ops = {
113 .type = &nft_queue_type, 165 .type = &nft_queue_type,
@@ -117,9 +169,35 @@ static const struct nft_expr_ops nft_queue_ops = {
117 .dump = nft_queue_dump, 169 .dump = nft_queue_dump,
118}; 170};
119 171
172static const struct nft_expr_ops nft_queue_sreg_ops = {
173 .type = &nft_queue_type,
174 .size = NFT_EXPR_SIZE(sizeof(struct nft_queue)),
175 .eval = nft_queue_sreg_eval,
176 .init = nft_queue_sreg_init,
177 .dump = nft_queue_sreg_dump,
178};
179
180static const struct nft_expr_ops *
181nft_queue_select_ops(const struct nft_ctx *ctx,
182 const struct nlattr * const tb[])
183{
184 if (tb[NFTA_QUEUE_NUM] && tb[NFTA_QUEUE_SREG_QNUM])
185 return ERR_PTR(-EINVAL);
186
187 init_hashrandom(&jhash_initval);
188
189 if (tb[NFTA_QUEUE_NUM])
190 return &nft_queue_ops;
191
192 if (tb[NFTA_QUEUE_SREG_QNUM])
193 return &nft_queue_sreg_ops;
194
195 return ERR_PTR(-EINVAL);
196}
197
120static struct nft_expr_type nft_queue_type __read_mostly = { 198static struct nft_expr_type nft_queue_type __read_mostly = {
121 .name = "queue", 199 .name = "queue",
122 .ops = &nft_queue_ops, 200 .select_ops = &nft_queue_select_ops,
123 .policy = nft_queue_policy, 201 .policy = nft_queue_policy,
124 .maxattr = NFTA_QUEUE_MAX, 202 .maxattr = NFTA_QUEUE_MAX,
125 .owner = THIS_MODULE, 203 .owner = THIS_MODULE,