1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2019 Facebook */
3 #include <linux/rculist.h>
4 #include <linux/list.h>
5 #include <linux/hash.h>
6 #include <linux/types.h>
7 #include <linux/spinlock.h>
9 #include <net/bpf_sk_storage.h>
11 #include <uapi/linux/btf.h>
13 static atomic_t cache_idx
;
16 struct hlist_head list
;
20 /* Thp map is not the primary owner of a bpf_sk_storage_elem.
21 * Instead, the sk->sk_bpf_storage is.
23 * The map (bpf_sk_storage_map) is for two purposes
24 * 1. Define the size of the "sk local storage". It is
25 * the map's value_size.
27 * 2. Maintain a list to keep track of all elems such
28 * that they can be cleaned up during the map destruction.
30 * When a bpf local storage is being looked up for a
31 * particular sk, the "bpf_map" pointer is actually used
32 * as the "key" to search in the list of elem in
35 * Hence, consider sk->sk_bpf_storage is the mini-map
36 * with the "bpf_map" pointer as the searching key.
38 struct bpf_sk_storage_map
{
40 /* Lookup elem does not require accessing the map.
42 * Updating/Deleting requires a bucket lock to
43 * link/unlink the elem from the map. Having
44 * multiple buckets to improve contention.
46 struct bucket
*buckets
;
52 struct bpf_sk_storage_data
{
53 /* smap is used as the searching key when looking up
54 * from sk->sk_bpf_storage.
56 * Put it in the same cacheline as the data to minimize
57 * the number of cachelines access during the cache hit case.
59 struct bpf_sk_storage_map __rcu
*smap
;
60 u8 data
[0] __aligned(8);
63 /* Linked to bpf_sk_storage and bpf_sk_storage_map */
64 struct bpf_sk_storage_elem
{
65 struct hlist_node map_node
; /* Linked to bpf_sk_storage_map */
66 struct hlist_node snode
; /* Linked to bpf_sk_storage */
67 struct bpf_sk_storage __rcu
*sk_storage
;
70 /* The data is stored in aother cacheline to minimize
71 * the number of cachelines access during a cache hit.
73 struct bpf_sk_storage_data sdata ____cacheline_aligned
;
76 #define SELEM(_SDATA) container_of((_SDATA), struct bpf_sk_storage_elem, sdata)
77 #define SDATA(_SELEM) (&(_SELEM)->sdata)
78 #define BPF_SK_STORAGE_CACHE_SIZE 16
80 struct bpf_sk_storage
{
81 struct bpf_sk_storage_data __rcu
*cache
[BPF_SK_STORAGE_CACHE_SIZE
];
82 struct hlist_head list
; /* List of bpf_sk_storage_elem */
83 struct sock
*sk
; /* The sk that owns the the above "list" of
84 * bpf_sk_storage_elem.
87 raw_spinlock_t lock
; /* Protect adding/removing from the "list" */
90 static struct bucket
*select_bucket(struct bpf_sk_storage_map
*smap
,
91 struct bpf_sk_storage_elem
*selem
)
93 return &smap
->buckets
[hash_ptr(selem
, smap
->bucket_log
)];
96 static int omem_charge(struct sock
*sk
, unsigned int size
)
98 /* same check as in sock_kmalloc() */
99 if (size
<= sysctl_optmem_max
&&
100 atomic_read(&sk
->sk_omem_alloc
) + size
< sysctl_optmem_max
) {
101 atomic_add(size
, &sk
->sk_omem_alloc
);
108 static bool selem_linked_to_sk(const struct bpf_sk_storage_elem
*selem
)
110 return !hlist_unhashed(&selem
->snode
);
113 static bool selem_linked_to_map(const struct bpf_sk_storage_elem
*selem
)
115 return !hlist_unhashed(&selem
->map_node
);
118 static struct bpf_sk_storage_elem
*selem_alloc(struct bpf_sk_storage_map
*smap
,
119 struct sock
*sk
, void *value
,
122 struct bpf_sk_storage_elem
*selem
;
124 if (charge_omem
&& omem_charge(sk
, smap
->elem_size
))
127 selem
= kzalloc(smap
->elem_size
, GFP_ATOMIC
| __GFP_NOWARN
);
130 memcpy(SDATA(selem
)->data
, value
, smap
->map
.value_size
);
135 atomic_sub(smap
->elem_size
, &sk
->sk_omem_alloc
);
140 /* sk_storage->lock must be held and selem->sk_storage == sk_storage.
141 * The caller must ensure selem->smap is still valid to be
142 * dereferenced for its smap->elem_size and smap->cache_idx.
144 static bool __selem_unlink_sk(struct bpf_sk_storage
*sk_storage
,
145 struct bpf_sk_storage_elem
*selem
,
148 struct bpf_sk_storage_map
*smap
;
149 bool free_sk_storage
;
152 smap
= rcu_dereference(SDATA(selem
)->smap
);
155 /* All uncharging on sk->sk_omem_alloc must be done first.
156 * sk may be freed once the last selem is unlinked from sk_storage.
159 atomic_sub(smap
->elem_size
, &sk
->sk_omem_alloc
);
161 free_sk_storage
= hlist_is_singular_node(&selem
->snode
,
163 if (free_sk_storage
) {
164 atomic_sub(sizeof(struct bpf_sk_storage
), &sk
->sk_omem_alloc
);
165 sk_storage
->sk
= NULL
;
166 /* After this RCU_INIT, sk may be freed and cannot be used */
167 RCU_INIT_POINTER(sk
->sk_bpf_storage
, NULL
);
169 /* sk_storage is not freed now. sk_storage->lock is
170 * still held and raw_spin_unlock_bh(&sk_storage->lock)
171 * will be done by the caller.
173 * Although the unlock will be done under
174 * rcu_read_lock(), it is more intutivie to
175 * read if kfree_rcu(sk_storage, rcu) is done
176 * after the raw_spin_unlock_bh(&sk_storage->lock).
178 * Hence, a "bool free_sk_storage" is returned
179 * to the caller which then calls the kfree_rcu()
183 hlist_del_init_rcu(&selem
->snode
);
184 if (rcu_access_pointer(sk_storage
->cache
[smap
->cache_idx
]) ==
186 RCU_INIT_POINTER(sk_storage
->cache
[smap
->cache_idx
], NULL
);
188 kfree_rcu(selem
, rcu
);
190 return free_sk_storage
;
193 static void selem_unlink_sk(struct bpf_sk_storage_elem
*selem
)
195 struct bpf_sk_storage
*sk_storage
;
196 bool free_sk_storage
= false;
198 if (unlikely(!selem_linked_to_sk(selem
)))
199 /* selem has already been unlinked from sk */
202 sk_storage
= rcu_dereference(selem
->sk_storage
);
203 raw_spin_lock_bh(&sk_storage
->lock
);
204 if (likely(selem_linked_to_sk(selem
)))
205 free_sk_storage
= __selem_unlink_sk(sk_storage
, selem
, true);
206 raw_spin_unlock_bh(&sk_storage
->lock
);
209 kfree_rcu(sk_storage
, rcu
);
212 /* sk_storage->lock must be held and sk_storage->list cannot be empty */
213 static void __selem_link_sk(struct bpf_sk_storage
*sk_storage
,
214 struct bpf_sk_storage_elem
*selem
)
216 RCU_INIT_POINTER(selem
->sk_storage
, sk_storage
);
217 hlist_add_head(&selem
->snode
, &sk_storage
->list
);
220 static void selem_unlink_map(struct bpf_sk_storage_elem
*selem
)
222 struct bpf_sk_storage_map
*smap
;
225 if (unlikely(!selem_linked_to_map(selem
)))
226 /* selem has already be unlinked from smap */
229 smap
= rcu_dereference(SDATA(selem
)->smap
);
230 b
= select_bucket(smap
, selem
);
231 raw_spin_lock_bh(&b
->lock
);
232 if (likely(selem_linked_to_map(selem
)))
233 hlist_del_init_rcu(&selem
->map_node
);
234 raw_spin_unlock_bh(&b
->lock
);
237 static void selem_link_map(struct bpf_sk_storage_map
*smap
,
238 struct bpf_sk_storage_elem
*selem
)
240 struct bucket
*b
= select_bucket(smap
, selem
);
242 raw_spin_lock_bh(&b
->lock
);
243 RCU_INIT_POINTER(SDATA(selem
)->smap
, smap
);
244 hlist_add_head_rcu(&selem
->map_node
, &b
->list
);
245 raw_spin_unlock_bh(&b
->lock
);
248 static void selem_unlink(struct bpf_sk_storage_elem
*selem
)
250 /* Always unlink from map before unlinking from sk_storage
251 * because selem will be freed after successfully unlinked from
254 selem_unlink_map(selem
);
255 selem_unlink_sk(selem
);
258 static struct bpf_sk_storage_data
*
259 __sk_storage_lookup(struct bpf_sk_storage
*sk_storage
,
260 struct bpf_sk_storage_map
*smap
,
263 struct bpf_sk_storage_data
*sdata
;
264 struct bpf_sk_storage_elem
*selem
;
266 /* Fast path (cache hit) */
267 sdata
= rcu_dereference(sk_storage
->cache
[smap
->cache_idx
]);
268 if (sdata
&& rcu_access_pointer(sdata
->smap
) == smap
)
271 /* Slow path (cache miss) */
272 hlist_for_each_entry_rcu(selem
, &sk_storage
->list
, snode
)
273 if (rcu_access_pointer(SDATA(selem
)->smap
) == smap
)
279 sdata
= SDATA(selem
);
280 if (cacheit_lockit
) {
281 /* spinlock is needed to avoid racing with the
282 * parallel delete. Otherwise, publishing an already
283 * deleted sdata to the cache will become a use-after-free
284 * problem in the next __sk_storage_lookup().
286 raw_spin_lock_bh(&sk_storage
->lock
);
287 if (selem_linked_to_sk(selem
))
288 rcu_assign_pointer(sk_storage
->cache
[smap
->cache_idx
],
290 raw_spin_unlock_bh(&sk_storage
->lock
);
296 static struct bpf_sk_storage_data
*
297 sk_storage_lookup(struct sock
*sk
, struct bpf_map
*map
, bool cacheit_lockit
)
299 struct bpf_sk_storage
*sk_storage
;
300 struct bpf_sk_storage_map
*smap
;
302 sk_storage
= rcu_dereference(sk
->sk_bpf_storage
);
306 smap
= (struct bpf_sk_storage_map
*)map
;
307 return __sk_storage_lookup(sk_storage
, smap
, cacheit_lockit
);
310 static int check_flags(const struct bpf_sk_storage_data
*old_sdata
,
313 if (old_sdata
&& (map_flags
& ~BPF_F_LOCK
) == BPF_NOEXIST
)
314 /* elem already exists */
317 if (!old_sdata
&& (map_flags
& ~BPF_F_LOCK
) == BPF_EXIST
)
318 /* elem doesn't exist, cannot update it */
324 static int sk_storage_alloc(struct sock
*sk
,
325 struct bpf_sk_storage_map
*smap
,
326 struct bpf_sk_storage_elem
*first_selem
)
328 struct bpf_sk_storage
*prev_sk_storage
, *sk_storage
;
331 err
= omem_charge(sk
, sizeof(*sk_storage
));
335 sk_storage
= kzalloc(sizeof(*sk_storage
), GFP_ATOMIC
| __GFP_NOWARN
);
340 INIT_HLIST_HEAD(&sk_storage
->list
);
341 raw_spin_lock_init(&sk_storage
->lock
);
344 __selem_link_sk(sk_storage
, first_selem
);
345 selem_link_map(smap
, first_selem
);
346 /* Publish sk_storage to sk. sk->sk_lock cannot be acquired.
347 * Hence, atomic ops is used to set sk->sk_bpf_storage
348 * from NULL to the newly allocated sk_storage ptr.
350 * From now on, the sk->sk_bpf_storage pointer is protected
351 * by the sk_storage->lock. Hence, when freeing
352 * the sk->sk_bpf_storage, the sk_storage->lock must
353 * be held before setting sk->sk_bpf_storage to NULL.
355 prev_sk_storage
= cmpxchg((struct bpf_sk_storage
**)&sk
->sk_bpf_storage
,
357 if (unlikely(prev_sk_storage
)) {
358 selem_unlink_map(first_selem
);
362 /* Note that even first_selem was linked to smap's
363 * bucket->list, first_selem can be freed immediately
364 * (instead of kfree_rcu) because
365 * bpf_sk_storage_map_free() does a
366 * synchronize_rcu() before walking the bucket->list.
367 * Hence, no one is accessing selem from the
368 * bucket->list under rcu_read_lock().
376 atomic_sub(sizeof(*sk_storage
), &sk
->sk_omem_alloc
);
380 /* sk cannot be going away because it is linking new elem
381 * to sk->sk_bpf_storage. (i.e. sk->sk_refcnt cannot be 0).
382 * Otherwise, it will become a leak (and other memory issues
383 * during map destruction).
385 static struct bpf_sk_storage_data
*sk_storage_update(struct sock
*sk
,
390 struct bpf_sk_storage_data
*old_sdata
= NULL
;
391 struct bpf_sk_storage_elem
*selem
;
392 struct bpf_sk_storage
*sk_storage
;
393 struct bpf_sk_storage_map
*smap
;
396 /* BPF_EXIST and BPF_NOEXIST cannot be both set */
397 if (unlikely((map_flags
& ~BPF_F_LOCK
) > BPF_EXIST
) ||
398 /* BPF_F_LOCK can only be used in a value with spin_lock */
399 unlikely((map_flags
& BPF_F_LOCK
) && !map_value_has_spin_lock(map
)))
400 return ERR_PTR(-EINVAL
);
402 smap
= (struct bpf_sk_storage_map
*)map
;
403 sk_storage
= rcu_dereference(sk
->sk_bpf_storage
);
404 if (!sk_storage
|| hlist_empty(&sk_storage
->list
)) {
405 /* Very first elem for this sk */
406 err
= check_flags(NULL
, map_flags
);
410 selem
= selem_alloc(smap
, sk
, value
, true);
412 return ERR_PTR(-ENOMEM
);
414 err
= sk_storage_alloc(sk
, smap
, selem
);
417 atomic_sub(smap
->elem_size
, &sk
->sk_omem_alloc
);
424 if ((map_flags
& BPF_F_LOCK
) && !(map_flags
& BPF_NOEXIST
)) {
425 /* Hoping to find an old_sdata to do inline update
426 * such that it can avoid taking the sk_storage->lock
427 * and changing the lists.
429 old_sdata
= __sk_storage_lookup(sk_storage
, smap
, false);
430 err
= check_flags(old_sdata
, map_flags
);
433 if (old_sdata
&& selem_linked_to_sk(SELEM(old_sdata
))) {
434 copy_map_value_locked(map
, old_sdata
->data
,
440 raw_spin_lock_bh(&sk_storage
->lock
);
442 /* Recheck sk_storage->list under sk_storage->lock */
443 if (unlikely(hlist_empty(&sk_storage
->list
))) {
444 /* A parallel del is happening and sk_storage is going
445 * away. It has just been checked before, so very
446 * unlikely. Return instead of retry to keep things
453 old_sdata
= __sk_storage_lookup(sk_storage
, smap
, false);
454 err
= check_flags(old_sdata
, map_flags
);
458 if (old_sdata
&& (map_flags
& BPF_F_LOCK
)) {
459 copy_map_value_locked(map
, old_sdata
->data
, value
, false);
460 selem
= SELEM(old_sdata
);
464 /* sk_storage->lock is held. Hence, we are sure
465 * we can unlink and uncharge the old_sdata successfully
466 * later. Hence, instead of charging the new selem now
467 * and then uncharge the old selem later (which may cause
468 * a potential but unnecessary charge failure), avoid taking
469 * a charge at all here (the "!old_sdata" check) and the
470 * old_sdata will not be uncharged later during __selem_unlink_sk().
472 selem
= selem_alloc(smap
, sk
, value
, !old_sdata
);
478 /* First, link the new selem to the map */
479 selem_link_map(smap
, selem
);
481 /* Second, link (and publish) the new selem to sk_storage */
482 __selem_link_sk(sk_storage
, selem
);
484 /* Third, remove old selem, SELEM(old_sdata) */
486 selem_unlink_map(SELEM(old_sdata
));
487 __selem_unlink_sk(sk_storage
, SELEM(old_sdata
), false);
491 raw_spin_unlock_bh(&sk_storage
->lock
);
495 raw_spin_unlock_bh(&sk_storage
->lock
);
499 static int sk_storage_delete(struct sock
*sk
, struct bpf_map
*map
)
501 struct bpf_sk_storage_data
*sdata
;
503 sdata
= sk_storage_lookup(sk
, map
, false);
507 selem_unlink(SELEM(sdata
));
512 /* Called by __sk_destruct() */
513 void bpf_sk_storage_free(struct sock
*sk
)
515 struct bpf_sk_storage_elem
*selem
;
516 struct bpf_sk_storage
*sk_storage
;
517 bool free_sk_storage
= false;
518 struct hlist_node
*n
;
521 sk_storage
= rcu_dereference(sk
->sk_bpf_storage
);
527 /* Netiher the bpf_prog nor the bpf-map's syscall
528 * could be modifying the sk_storage->list now.
529 * Thus, no elem can be added-to or deleted-from the
530 * sk_storage->list by the bpf_prog or by the bpf-map's syscall.
532 * It is racing with bpf_sk_storage_map_free() alone
533 * when unlinking elem from the sk_storage->list and
534 * the map's bucket->list.
536 raw_spin_lock_bh(&sk_storage
->lock
);
537 hlist_for_each_entry_safe(selem
, n
, &sk_storage
->list
, snode
) {
538 /* Always unlink from map before unlinking from
541 selem_unlink_map(selem
);
542 free_sk_storage
= __selem_unlink_sk(sk_storage
, selem
, true);
544 raw_spin_unlock_bh(&sk_storage
->lock
);
548 kfree_rcu(sk_storage
, rcu
);
551 static void bpf_sk_storage_map_free(struct bpf_map
*map
)
553 struct bpf_sk_storage_elem
*selem
;
554 struct bpf_sk_storage_map
*smap
;
558 smap
= (struct bpf_sk_storage_map
*)map
;
562 /* bpf prog and the userspace can no longer access this map
563 * now. No new selem (of this map) can be added
564 * to the sk->sk_bpf_storage or to the map bucket's list.
566 * The elem of this map can be cleaned up here
568 * by bpf_sk_storage_free() during __sk_destruct().
570 for (i
= 0; i
< (1U << smap
->bucket_log
); i
++) {
571 b
= &smap
->buckets
[i
];
574 /* No one is adding to b->list now */
575 while ((selem
= hlist_entry_safe(rcu_dereference_raw(hlist_first_rcu(&b
->list
)),
576 struct bpf_sk_storage_elem
,
584 /* bpf_sk_storage_free() may still need to access the map.
585 * e.g. bpf_sk_storage_free() has unlinked selem from the map
586 * which then made the above while((selem = ...)) loop
587 * exited immediately.
589 * However, the bpf_sk_storage_free() still needs to access
590 * the smap->elem_size to do the uncharging in
591 * __selem_unlink_sk().
593 * Hence, wait another rcu grace period for the
594 * bpf_sk_storage_free() to finish.
598 kvfree(smap
->buckets
);
602 static int bpf_sk_storage_map_alloc_check(union bpf_attr
*attr
)
604 if (attr
->map_flags
!= BPF_F_NO_PREALLOC
|| attr
->max_entries
||
605 attr
->key_size
!= sizeof(int) || !attr
->value_size
||
606 /* Enforce BTF for userspace sk dumping */
607 !attr
->btf_key_type_id
|| !attr
->btf_value_type_id
)
610 if (!capable(CAP_SYS_ADMIN
))
613 if (attr
->value_size
>= KMALLOC_MAX_SIZE
-
614 MAX_BPF_STACK
- sizeof(struct bpf_sk_storage_elem
) ||
615 /* U16_MAX is much more than enough for sk local storage
616 * considering a tcp_sock is ~2k.
618 attr
->value_size
> U16_MAX
- sizeof(struct bpf_sk_storage_elem
))
624 static struct bpf_map
*bpf_sk_storage_map_alloc(union bpf_attr
*attr
)
626 struct bpf_sk_storage_map
*smap
;
631 smap
= kzalloc(sizeof(*smap
), GFP_USER
| __GFP_NOWARN
);
633 return ERR_PTR(-ENOMEM
);
634 bpf_map_init_from_attr(&smap
->map
, attr
);
636 /* Use at least 2 buckets, select_bucket() is undefined behavior with 1 bucket */
637 smap
->bucket_log
= max_t(u32
, 1, ilog2(roundup_pow_of_two(num_possible_cpus())));
638 nbuckets
= 1U << smap
->bucket_log
;
639 smap
->buckets
= kvcalloc(sizeof(*smap
->buckets
), nbuckets
,
640 GFP_USER
| __GFP_NOWARN
);
641 if (!smap
->buckets
) {
643 return ERR_PTR(-ENOMEM
);
645 cost
= sizeof(*smap
->buckets
) * nbuckets
+ sizeof(*smap
);
647 for (i
= 0; i
< nbuckets
; i
++) {
648 INIT_HLIST_HEAD(&smap
->buckets
[i
].list
);
649 raw_spin_lock_init(&smap
->buckets
[i
].lock
);
652 smap
->elem_size
= sizeof(struct bpf_sk_storage_elem
) + attr
->value_size
;
653 smap
->cache_idx
= (unsigned int)atomic_inc_return(&cache_idx
) %
654 BPF_SK_STORAGE_CACHE_SIZE
;
655 smap
->map
.pages
= round_up(cost
, PAGE_SIZE
) >> PAGE_SHIFT
;
660 static int notsupp_get_next_key(struct bpf_map
*map
, void *key
,
666 static int bpf_sk_storage_map_check_btf(const struct bpf_map
*map
,
667 const struct btf
*btf
,
668 const struct btf_type
*key_type
,
669 const struct btf_type
*value_type
)
673 if (BTF_INFO_KIND(key_type
->info
) != BTF_KIND_INT
)
676 int_data
= *(u32
*)(key_type
+ 1);
677 if (BTF_INT_BITS(int_data
) != 32 || BTF_INT_OFFSET(int_data
))
683 static void *bpf_fd_sk_storage_lookup_elem(struct bpf_map
*map
, void *key
)
685 struct bpf_sk_storage_data
*sdata
;
690 sock
= sockfd_lookup(fd
, &err
);
692 sdata
= sk_storage_lookup(sock
->sk
, map
, true);
694 return sdata
? sdata
->data
: NULL
;
700 static int bpf_fd_sk_storage_update_elem(struct bpf_map
*map
, void *key
,
701 void *value
, u64 map_flags
)
703 struct bpf_sk_storage_data
*sdata
;
708 sock
= sockfd_lookup(fd
, &err
);
710 sdata
= sk_storage_update(sock
->sk
, map
, value
, map_flags
);
712 return PTR_ERR_OR_ZERO(sdata
);
718 static int bpf_fd_sk_storage_delete_elem(struct bpf_map
*map
, void *key
)
724 sock
= sockfd_lookup(fd
, &err
);
726 err
= sk_storage_delete(sock
->sk
, map
);
734 BPF_CALL_4(bpf_sk_storage_get
, struct bpf_map
*, map
, struct sock
*, sk
,
735 void *, value
, u64
, flags
)
737 struct bpf_sk_storage_data
*sdata
;
739 if (flags
> BPF_SK_STORAGE_GET_F_CREATE
)
740 return (unsigned long)NULL
;
742 sdata
= sk_storage_lookup(sk
, map
, true);
744 return (unsigned long)sdata
->data
;
746 if (flags
== BPF_SK_STORAGE_GET_F_CREATE
&&
747 /* Cannot add new elem to a going away sk.
748 * Otherwise, the new elem may become a leak
749 * (and also other memory issues during map
752 refcount_inc_not_zero(&sk
->sk_refcnt
)) {
753 sdata
= sk_storage_update(sk
, map
, value
, BPF_NOEXIST
);
754 /* sk must be a fullsock (guaranteed by verifier),
755 * so sock_gen_put() is unnecessary.
758 return IS_ERR(sdata
) ?
759 (unsigned long)NULL
: (unsigned long)sdata
->data
;
762 return (unsigned long)NULL
;
765 BPF_CALL_2(bpf_sk_storage_delete
, struct bpf_map
*, map
, struct sock
*, sk
)
767 if (refcount_inc_not_zero(&sk
->sk_refcnt
)) {
770 err
= sk_storage_delete(sk
, map
);
778 const struct bpf_map_ops sk_storage_map_ops
= {
779 .map_alloc_check
= bpf_sk_storage_map_alloc_check
,
780 .map_alloc
= bpf_sk_storage_map_alloc
,
781 .map_free
= bpf_sk_storage_map_free
,
782 .map_get_next_key
= notsupp_get_next_key
,
783 .map_lookup_elem
= bpf_fd_sk_storage_lookup_elem
,
784 .map_update_elem
= bpf_fd_sk_storage_update_elem
,
785 .map_delete_elem
= bpf_fd_sk_storage_delete_elem
,
786 .map_check_btf
= bpf_sk_storage_map_check_btf
,
789 const struct bpf_func_proto bpf_sk_storage_get_proto
= {
790 .func
= bpf_sk_storage_get
,
792 .ret_type
= RET_PTR_TO_MAP_VALUE_OR_NULL
,
793 .arg1_type
= ARG_CONST_MAP_PTR
,
794 .arg2_type
= ARG_PTR_TO_SOCKET
,
795 .arg3_type
= ARG_PTR_TO_MAP_VALUE_OR_NULL
,
796 .arg4_type
= ARG_ANYTHING
,
799 const struct bpf_func_proto bpf_sk_storage_delete_proto
= {
800 .func
= bpf_sk_storage_delete
,
802 .ret_type
= RET_INTEGER
,
803 .arg1_type
= ARG_CONST_MAP_PTR
,
804 .arg2_type
= ARG_PTR_TO_SOCKET
,