@@ -389,10 +389,84 @@ static int trie_update_elem(struct bpf_map *map,
389
389
return ret ;
390
390
}
391
391
392
- static int trie_delete_elem (struct bpf_map * map , void * key )
392
+ /* Called from syscall or from eBPF program */
393
+ static int trie_delete_elem (struct bpf_map * map , void * _key )
393
394
{
394
- /* TODO */
395
- return - ENOSYS ;
395
+ struct lpm_trie * trie = container_of (map , struct lpm_trie , map );
396
+ struct bpf_lpm_trie_key * key = _key ;
397
+ struct lpm_trie_node __rcu * * trim ;
398
+ struct lpm_trie_node * node ;
399
+ unsigned long irq_flags ;
400
+ unsigned int next_bit ;
401
+ size_t matchlen = 0 ;
402
+ int ret = 0 ;
403
+
404
+ if (key -> prefixlen > trie -> max_prefixlen )
405
+ return - EINVAL ;
406
+
407
+ raw_spin_lock_irqsave (& trie -> lock , irq_flags );
408
+
409
+ /* Walk the tree looking for an exact key/length match and keeping
410
+ * track of where we could begin trimming the tree. The trim-point
411
+ * is the sub-tree along the walk consisting of only single-child
412
+ * intermediate nodes and ending at a leaf node that we want to
413
+ * remove.
414
+ */
415
+ trim = & trie -> root ;
416
+ node = rcu_dereference_protected (
417
+ trie -> root , lockdep_is_held (& trie -> lock ));
418
+ while (node ) {
419
+ matchlen = longest_prefix_match (trie , node , key );
420
+
421
+ if (node -> prefixlen != matchlen ||
422
+ node -> prefixlen == key -> prefixlen )
423
+ break ;
424
+
425
+ next_bit = extract_bit (key -> data , node -> prefixlen );
426
+ /* If we hit a node that has more than one child or is a valid
427
+ * prefix itself, do not remove it. Reset the root of the trim
428
+ * path to its descendant on our path.
429
+ */
430
+ if (!(node -> flags & LPM_TREE_NODE_FLAG_IM ) ||
431
+ (node -> child [0 ] && node -> child [1 ]))
432
+ trim = & node -> child [next_bit ];
433
+ node = rcu_dereference_protected (
434
+ node -> child [next_bit ], lockdep_is_held (& trie -> lock ));
435
+ }
436
+
437
+ if (!node || node -> prefixlen != key -> prefixlen ||
438
+ (node -> flags & LPM_TREE_NODE_FLAG_IM )) {
439
+ ret = - ENOENT ;
440
+ goto out ;
441
+ }
442
+
443
+ trie -> n_entries -- ;
444
+
445
+ /* If the node we are removing is not a leaf node, simply mark it
446
+ * as intermediate and we are done.
447
+ */
448
+ if (rcu_access_pointer (node -> child [0 ]) ||
449
+ rcu_access_pointer (node -> child [1 ])) {
450
+ node -> flags |= LPM_TREE_NODE_FLAG_IM ;
451
+ goto out ;
452
+ }
453
+
454
+ /* trim should now point to the slot holding the start of a path from
455
+ * zero or more intermediate nodes to our leaf node for deletion.
456
+ */
457
+ while ((node = rcu_dereference_protected (
458
+ * trim , lockdep_is_held (& trie -> lock )))) {
459
+ RCU_INIT_POINTER (* trim , NULL );
460
+ trim = rcu_access_pointer (node -> child [0 ]) ?
461
+ & node -> child [0 ] :
462
+ & node -> child [1 ];
463
+ kfree_rcu (node , rcu );
464
+ }
465
+
466
+ out :
467
+ raw_spin_unlock_irqrestore (& trie -> lock , irq_flags );
468
+
469
+ return ret ;
396
470
}
397
471
398
472
#define LPM_DATA_SIZE_MAX 256
0 commit comments