Skip to content

Commit 2e9ff3f

Browse files
Hou Taogregkh
authored andcommitted
bpf: Handle in-place update for full LPM trie correctly
[ Upstream commit 532d6b3 ] When a LPM trie is full, in-place updates of existing elements incorrectly return -ENOSPC. Fix this by deferring the check of trie->n_entries. For new insertions, n_entries must not exceed max_entries. However, in-place updates are allowed even when the trie is full. Fixes: b95a5c4 ("bpf: add a longest prefix match trie map implementation") Reviewed-by: Toke Høiland-Jørgensen <[email protected]> Signed-off-by: Hou Tao <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent c1ab31e commit 2e9ff3f

File tree

1 file changed

+21
-23
lines changed

1 file changed

+21
-23
lines changed

kernel/bpf/lpm_trie.c

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,16 @@ static struct lpm_trie_node *lpm_trie_node_alloc(const struct lpm_trie *trie,
302302
return node;
303303
}
304304

305+
static int trie_check_add_elem(struct lpm_trie *trie, u64 flags)
306+
{
307+
if (flags == BPF_EXIST)
308+
return -ENOENT;
309+
if (trie->n_entries == trie->map.max_entries)
310+
return -ENOSPC;
311+
trie->n_entries++;
312+
return 0;
313+
}
314+
305315
/* Called from syscall or from eBPF program */
306316
static long trie_update_elem(struct bpf_map *map,
307317
void *_key, void *value, u64 flags)
@@ -325,20 +335,12 @@ static long trie_update_elem(struct bpf_map *map,
325335
spin_lock_irqsave(&trie->lock, irq_flags);
326336

327337
/* Allocate and fill a new node */
328-
329-
if (trie->n_entries == trie->map.max_entries) {
330-
ret = -ENOSPC;
331-
goto out;
332-
}
333-
334338
new_node = lpm_trie_node_alloc(trie, value);
335339
if (!new_node) {
336340
ret = -ENOMEM;
337341
goto out;
338342
}
339343

340-
trie->n_entries++;
341-
342344
new_node->prefixlen = key->prefixlen;
343345
RCU_INIT_POINTER(new_node->child[0], NULL);
344346
RCU_INIT_POINTER(new_node->child[1], NULL);
@@ -368,10 +370,10 @@ static long trie_update_elem(struct bpf_map *map,
368370
* simply assign the @new_node to that slot and be done.
369371
*/
370372
if (!node) {
371-
if (flags == BPF_EXIST) {
372-
ret = -ENOENT;
373+
ret = trie_check_add_elem(trie, flags);
374+
if (ret)
373375
goto out;
374-
}
376+
375377
rcu_assign_pointer(*slot, new_node);
376378
goto out;
377379
}
@@ -385,10 +387,10 @@ static long trie_update_elem(struct bpf_map *map,
385387
ret = -EEXIST;
386388
goto out;
387389
}
388-
trie->n_entries--;
389-
} else if (flags == BPF_EXIST) {
390-
ret = -ENOENT;
391-
goto out;
390+
} else {
391+
ret = trie_check_add_elem(trie, flags);
392+
if (ret)
393+
goto out;
392394
}
393395

394396
new_node->child[0] = node->child[0];
@@ -400,10 +402,9 @@ static long trie_update_elem(struct bpf_map *map,
400402
goto out;
401403
}
402404

403-
if (flags == BPF_EXIST) {
404-
ret = -ENOENT;
405+
ret = trie_check_add_elem(trie, flags);
406+
if (ret)
405407
goto out;
406-
}
407408

408409
/* If the new node matches the prefix completely, it must be inserted
409410
* as an ancestor. Simply insert it between @node and *@slot.
@@ -417,6 +418,7 @@ static long trie_update_elem(struct bpf_map *map,
417418

418419
im_node = lpm_trie_node_alloc(trie, NULL);
419420
if (!im_node) {
421+
trie->n_entries--;
420422
ret = -ENOMEM;
421423
goto out;
422424
}
@@ -438,12 +440,8 @@ static long trie_update_elem(struct bpf_map *map,
438440
rcu_assign_pointer(*slot, im_node);
439441

440442
out:
441-
if (ret) {
442-
if (new_node)
443-
trie->n_entries--;
443+
if (ret)
444444
kfree(new_node);
445-
}
446-
447445
spin_unlock_irqrestore(&trie->lock, irq_flags);
448446
kfree_rcu(free_node, rcu);
449447

0 commit comments

Comments
 (0)