aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/uapi/linux/netfilter/nf_tables.h2
-rw-r--r--net/netfilter/nft_queue.c102
2 files changed, 92 insertions, 12 deletions
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index bcfb892ff148..1cf41dd838b2 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -894,12 +894,14 @@ enum nft_log_attributes {
894 * @NFTA_QUEUE_NUM: netlink queue to send messages to (NLA_U16) 894 * @NFTA_QUEUE_NUM: netlink queue to send messages to (NLA_U16)
895 * @NFTA_QUEUE_TOTAL: number of queues to load balance packets on (NLA_U16) 895 * @NFTA_QUEUE_TOTAL: number of queues to load balance packets on (NLA_U16)
896 * @NFTA_QUEUE_FLAGS: various flags (NLA_U16) 896 * @NFTA_QUEUE_FLAGS: various flags (NLA_U16)
897 * @NFTA_QUEUE_SREG_QNUM: source register of queue number (NLA_U32: nft_registers)
897 */ 898 */
898enum nft_queue_attributes { 899enum nft_queue_attributes {
899 NFTA_QUEUE_UNSPEC, 900 NFTA_QUEUE_UNSPEC,
900 NFTA_QUEUE_NUM, 901 NFTA_QUEUE_NUM,
901 NFTA_QUEUE_TOTAL, 902 NFTA_QUEUE_TOTAL,
902 NFTA_QUEUE_FLAGS, 903 NFTA_QUEUE_FLAGS,
904 NFTA_QUEUE_SREG_QNUM,
903 __NFTA_QUEUE_MAX 905 __NFTA_QUEUE_MAX
904}; 906};
905#define NFTA_QUEUE_MAX (__NFTA_QUEUE_MAX - 1) 907#define NFTA_QUEUE_MAX (__NFTA_QUEUE_MAX - 1)
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,