diff options
-rw-r--r-- | include/uapi/linux/netfilter/nf_tables.h | 2 | ||||
-rw-r--r-- | net/netfilter/nft_queue.c | 102 |
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 | */ |
898 | enum nft_queue_attributes { | 899 | enum 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 @@ | |||
22 | static u32 jhash_initval __read_mostly; | 22 | static u32 jhash_initval __read_mostly; |
23 | 23 | ||
24 | struct nft_queue { | 24 | struct 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 | ||
30 | static void nft_queue_eval(const struct nft_expr *expr, | 31 | static 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 | ||
58 | static 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 | |||
57 | static const struct nla_policy nft_queue_policy[NFTA_QUEUE_MAX + 1] = { | 74 | static 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 | ||
63 | static int nft_queue_init(const struct nft_ctx *ctx, | 81 | static 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 | |||
110 | static 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 | ||
148 | static int | ||
149 | nft_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 | |||
159 | nla_put_failure: | ||
160 | return -1; | ||
161 | } | ||
162 | |||
111 | static struct nft_expr_type nft_queue_type; | 163 | static struct nft_expr_type nft_queue_type; |
112 | static const struct nft_expr_ops nft_queue_ops = { | 164 | static 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 | ||
172 | static 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 | |||
180 | static const struct nft_expr_ops * | ||
181 | nft_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 | |||
120 | static struct nft_expr_type nft_queue_type __read_mostly = { | 198 | static 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, |