Skip to content

Commit fa23e0d

Browse files
Florian Westphalummakynes
authored andcommitted
netfilter: nf_tables: allow clone callbacks to sleep
Sven Auhagen reports transaction failures with following error: ./main.nft:13:1-26: Error: Could not process rule: Cannot allocate memory percpu: allocation failed, size=16 align=8 atomic=1, atomic alloc failed, no space left This points to failing pcpu allocation with GFP_ATOMIC flag. However, transactions happen from user context and are allowed to sleep. One case where we can call into percpu allocator with GFP_ATOMIC is nft_counter expression. Normally this happens from control plane, so this could use GFP_KERNEL instead. But one use case, element insertion from packet path, needs to use GFP_ATOMIC allocations (nft_dynset expression). At this time, .clone callbacks always use GFP_ATOMIC for this reason. Add gfp_t argument to the .clone function and pass GFP_KERNEL or GFP_ATOMIC flag depending on context, this allows all clone memory allocations to sleep for the normal (transaction) case. Cc: Sven Auhagen <[email protected]> Signed-off-by: Florian Westphal <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent a8a388c commit fa23e0d

File tree

8 files changed

+23
-21
lines changed

8 files changed

+23
-21
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ struct nft_expr_info;
416416

417417
int nft_expr_inner_parse(const struct nft_ctx *ctx, const struct nlattr *nla,
418418
struct nft_expr_info *info);
419-
int nft_expr_clone(struct nft_expr *dst, struct nft_expr *src);
419+
int nft_expr_clone(struct nft_expr *dst, struct nft_expr *src, gfp_t gfp);
420420
void nft_expr_destroy(const struct nft_ctx *ctx, struct nft_expr *expr);
421421
int nft_expr_dump(struct sk_buff *skb, unsigned int attr,
422422
const struct nft_expr *expr, bool reset);
@@ -935,7 +935,7 @@ struct nft_expr_ops {
935935
struct nft_regs *regs,
936936
const struct nft_pktinfo *pkt);
937937
int (*clone)(struct nft_expr *dst,
938-
const struct nft_expr *src);
938+
const struct nft_expr *src, gfp_t gfp);
939939
unsigned int size;
940940

941941
int (*init)(const struct nft_ctx *ctx,

net/netfilter/nf_tables_api.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3333,15 +3333,15 @@ static struct nft_expr *nft_expr_init(const struct nft_ctx *ctx,
33333333
return ERR_PTR(err);
33343334
}
33353335

3336-
int nft_expr_clone(struct nft_expr *dst, struct nft_expr *src)
3336+
int nft_expr_clone(struct nft_expr *dst, struct nft_expr *src, gfp_t gfp)
33373337
{
33383338
int err;
33393339

33403340
if (WARN_ON_ONCE(!src->ops->clone))
33413341
return -EINVAL;
33423342

33433343
dst->ops = src->ops;
3344-
err = src->ops->clone(dst, src);
3344+
err = src->ops->clone(dst, src, gfp);
33453345
if (err < 0)
33463346
return err;
33473347

@@ -6525,7 +6525,7 @@ int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
65256525
if (!expr)
65266526
goto err_expr;
65276527

6528-
err = nft_expr_clone(expr, set->exprs[i]);
6528+
err = nft_expr_clone(expr, set->exprs[i], GFP_KERNEL_ACCOUNT);
65296529
if (err < 0) {
65306530
kfree(expr);
65316531
goto err_expr;
@@ -6564,7 +6564,7 @@ static int nft_set_elem_expr_setup(struct nft_ctx *ctx,
65646564

65656565
for (i = 0; i < num_exprs; i++) {
65666566
expr = nft_setelem_expr_at(elem_expr, elem_expr->size);
6567-
err = nft_expr_clone(expr, expr_array[i]);
6567+
err = nft_expr_clone(expr, expr_array[i], GFP_KERNEL_ACCOUNT);
65686568
if (err < 0)
65696569
goto err_elem_expr_setup;
65706570

net/netfilter/nft_connlimit.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,12 +210,12 @@ static void nft_connlimit_destroy(const struct nft_ctx *ctx,
210210
nft_connlimit_do_destroy(ctx, priv);
211211
}
212212

213-
static int nft_connlimit_clone(struct nft_expr *dst, const struct nft_expr *src)
213+
static int nft_connlimit_clone(struct nft_expr *dst, const struct nft_expr *src, gfp_t gfp)
214214
{
215215
struct nft_connlimit *priv_dst = nft_expr_priv(dst);
216216
struct nft_connlimit *priv_src = nft_expr_priv(src);
217217

218-
priv_dst->list = kmalloc(sizeof(*priv_dst->list), GFP_ATOMIC);
218+
priv_dst->list = kmalloc(sizeof(*priv_dst->list), gfp);
219219
if (!priv_dst->list)
220220
return -ENOMEM;
221221

net/netfilter/nft_counter.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ static void nft_counter_destroy(const struct nft_ctx *ctx,
226226
nft_counter_do_destroy(priv);
227227
}
228228

229-
static int nft_counter_clone(struct nft_expr *dst, const struct nft_expr *src)
229+
static int nft_counter_clone(struct nft_expr *dst, const struct nft_expr *src, gfp_t gfp)
230230
{
231231
struct nft_counter_percpu_priv *priv = nft_expr_priv(src);
232232
struct nft_counter_percpu_priv *priv_clone = nft_expr_priv(dst);
@@ -236,7 +236,7 @@ static int nft_counter_clone(struct nft_expr *dst, const struct nft_expr *src)
236236

237237
nft_counter_fetch(priv, &total);
238238

239-
cpu_stats = alloc_percpu_gfp(struct nft_counter, GFP_ATOMIC);
239+
cpu_stats = alloc_percpu_gfp(struct nft_counter, gfp);
240240
if (cpu_stats == NULL)
241241
return -ENOMEM;
242242

net/netfilter/nft_dynset.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ static int nft_dynset_expr_setup(const struct nft_dynset *priv,
3535

3636
for (i = 0; i < priv->num_exprs; i++) {
3737
expr = nft_setelem_expr_at(elem_expr, elem_expr->size);
38-
if (nft_expr_clone(expr, priv->expr_array[i]) < 0)
38+
if (nft_expr_clone(expr, priv->expr_array[i], GFP_ATOMIC) < 0)
3939
return -1;
4040

4141
elem_expr->size += priv->expr_array[i]->ops->size;

net/netfilter/nft_last.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,12 @@ static void nft_last_destroy(const struct nft_ctx *ctx,
102102
kfree(priv->last);
103103
}
104104

105-
static int nft_last_clone(struct nft_expr *dst, const struct nft_expr *src)
105+
static int nft_last_clone(struct nft_expr *dst, const struct nft_expr *src, gfp_t gfp)
106106
{
107107
struct nft_last_priv *priv_dst = nft_expr_priv(dst);
108108
struct nft_last_priv *priv_src = nft_expr_priv(src);
109109

110-
priv_dst->last = kzalloc(sizeof(*priv_dst->last), GFP_ATOMIC);
110+
priv_dst->last = kzalloc(sizeof(*priv_dst->last), gfp);
111111
if (!priv_dst->last)
112112
return -ENOMEM;
113113

net/netfilter/nft_limit.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -150,15 +150,15 @@ static void nft_limit_destroy(const struct nft_ctx *ctx,
150150
}
151151

152152
static int nft_limit_clone(struct nft_limit_priv *priv_dst,
153-
const struct nft_limit_priv *priv_src)
153+
const struct nft_limit_priv *priv_src, gfp_t gfp)
154154
{
155155
priv_dst->tokens_max = priv_src->tokens_max;
156156
priv_dst->rate = priv_src->rate;
157157
priv_dst->nsecs = priv_src->nsecs;
158158
priv_dst->burst = priv_src->burst;
159159
priv_dst->invert = priv_src->invert;
160160

161-
priv_dst->limit = kmalloc(sizeof(*priv_dst->limit), GFP_ATOMIC);
161+
priv_dst->limit = kmalloc(sizeof(*priv_dst->limit), gfp);
162162
if (!priv_dst->limit)
163163
return -ENOMEM;
164164

@@ -223,14 +223,15 @@ static void nft_limit_pkts_destroy(const struct nft_ctx *ctx,
223223
nft_limit_destroy(ctx, &priv->limit);
224224
}
225225

226-
static int nft_limit_pkts_clone(struct nft_expr *dst, const struct nft_expr *src)
226+
static int nft_limit_pkts_clone(struct nft_expr *dst, const struct nft_expr *src,
227+
gfp_t gfp)
227228
{
228229
struct nft_limit_priv_pkts *priv_dst = nft_expr_priv(dst);
229230
struct nft_limit_priv_pkts *priv_src = nft_expr_priv(src);
230231

231232
priv_dst->cost = priv_src->cost;
232233

233-
return nft_limit_clone(&priv_dst->limit, &priv_src->limit);
234+
return nft_limit_clone(&priv_dst->limit, &priv_src->limit, gfp);
234235
}
235236

236237
static struct nft_expr_type nft_limit_type;
@@ -281,12 +282,13 @@ static void nft_limit_bytes_destroy(const struct nft_ctx *ctx,
281282
nft_limit_destroy(ctx, priv);
282283
}
283284

284-
static int nft_limit_bytes_clone(struct nft_expr *dst, const struct nft_expr *src)
285+
static int nft_limit_bytes_clone(struct nft_expr *dst, const struct nft_expr *src,
286+
gfp_t gfp)
285287
{
286288
struct nft_limit_priv *priv_dst = nft_expr_priv(dst);
287289
struct nft_limit_priv *priv_src = nft_expr_priv(src);
288290

289-
return nft_limit_clone(priv_dst, priv_src);
291+
return nft_limit_clone(priv_dst, priv_src, gfp);
290292
}
291293

292294
static const struct nft_expr_ops nft_limit_bytes_ops = {

net/netfilter/nft_quota.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,15 +233,15 @@ static void nft_quota_destroy(const struct nft_ctx *ctx,
233233
return nft_quota_do_destroy(ctx, priv);
234234
}
235235

236-
static int nft_quota_clone(struct nft_expr *dst, const struct nft_expr *src)
236+
static int nft_quota_clone(struct nft_expr *dst, const struct nft_expr *src, gfp_t gfp)
237237
{
238238
struct nft_quota *priv_dst = nft_expr_priv(dst);
239239
struct nft_quota *priv_src = nft_expr_priv(src);
240240

241241
priv_dst->quota = priv_src->quota;
242242
priv_dst->flags = priv_src->flags;
243243

244-
priv_dst->consumed = kmalloc(sizeof(*priv_dst->consumed), GFP_ATOMIC);
244+
priv_dst->consumed = kmalloc(sizeof(*priv_dst->consumed), gfp);
245245
if (!priv_dst->consumed)
246246
return -ENOMEM;
247247

0 commit comments

Comments
 (0)