1 // SPDX-License-Identifier: GPL-2.0
2 /* XSKMAP used for AF_XDP sockets
3 * Copyright(c) 2018 Intel Corporation.
7 #include <linux/capability.h>
8 #include <net/xdp_sock.h>
9 #include <linux/slab.h>
10 #include <linux/sched.h>
14 struct xdp_sock
**xsk_map
;
15 struct list_head __percpu
*flush_list
;
18 static struct bpf_map
*xsk_map_alloc(union bpf_attr
*attr
)
24 if (!capable(CAP_NET_ADMIN
))
25 return ERR_PTR(-EPERM
);
27 if (attr
->max_entries
== 0 || attr
->key_size
!= 4 ||
28 attr
->value_size
!= 4 ||
29 attr
->map_flags
& ~(BPF_F_NUMA_NODE
| BPF_F_RDONLY
| BPF_F_WRONLY
))
30 return ERR_PTR(-EINVAL
);
32 m
= kzalloc(sizeof(*m
), GFP_USER
);
34 return ERR_PTR(-ENOMEM
);
36 bpf_map_init_from_attr(&m
->map
, attr
);
38 cost
= (u64
)m
->map
.max_entries
* sizeof(struct xdp_sock
*);
39 cost
+= sizeof(struct list_head
) * num_possible_cpus();
41 /* Notice returns -EPERM on if map size is larger than memlock limit */
42 err
= bpf_map_charge_init(&m
->map
.memory
, cost
);
48 m
->flush_list
= alloc_percpu(struct list_head
);
52 for_each_possible_cpu(cpu
)
53 INIT_LIST_HEAD(per_cpu_ptr(m
->flush_list
, cpu
));
55 m
->xsk_map
= bpf_map_area_alloc(m
->map
.max_entries
*
56 sizeof(struct xdp_sock
*),
63 free_percpu(m
->flush_list
);
65 bpf_map_charge_finish(&m
->map
.memory
);
71 static void xsk_map_free(struct bpf_map
*map
)
73 struct xsk_map
*m
= container_of(map
, struct xsk_map
, map
);
76 bpf_clear_redirect_map(map
);
79 for (i
= 0; i
< map
->max_entries
; i
++) {
86 sock_put((struct sock
*)xs
);
89 free_percpu(m
->flush_list
);
90 bpf_map_area_free(m
->xsk_map
);
94 static int xsk_map_get_next_key(struct bpf_map
*map
, void *key
, void *next_key
)
96 struct xsk_map
*m
= container_of(map
, struct xsk_map
, map
);
97 u32 index
= key
? *(u32
*)key
: U32_MAX
;
100 if (index
>= m
->map
.max_entries
) {
105 if (index
== m
->map
.max_entries
- 1)
111 struct xdp_sock
*__xsk_map_lookup_elem(struct bpf_map
*map
, u32 key
)
113 struct xsk_map
*m
= container_of(map
, struct xsk_map
, map
);
116 if (key
>= map
->max_entries
)
119 xs
= READ_ONCE(m
->xsk_map
[key
]);
123 int __xsk_map_redirect(struct bpf_map
*map
, struct xdp_buff
*xdp
,
126 struct xsk_map
*m
= container_of(map
, struct xsk_map
, map
);
127 struct list_head
*flush_list
= this_cpu_ptr(m
->flush_list
);
130 err
= xsk_rcv(xs
, xdp
);
134 if (!xs
->flush_node
.prev
)
135 list_add(&xs
->flush_node
, flush_list
);
140 void __xsk_map_flush(struct bpf_map
*map
)
142 struct xsk_map
*m
= container_of(map
, struct xsk_map
, map
);
143 struct list_head
*flush_list
= this_cpu_ptr(m
->flush_list
);
144 struct xdp_sock
*xs
, *tmp
;
146 list_for_each_entry_safe(xs
, tmp
, flush_list
, flush_node
) {
148 __list_del_clearprev(&xs
->flush_node
);
152 static void *xsk_map_lookup_elem(struct bpf_map
*map
, void *key
)
154 WARN_ON_ONCE(!rcu_read_lock_held());
155 return __xsk_map_lookup_elem(map
, *(u32
*)key
);
158 static void *xsk_map_lookup_elem_sys_only(struct bpf_map
*map
, void *key
)
160 return ERR_PTR(-EOPNOTSUPP
);
163 static int xsk_map_update_elem(struct bpf_map
*map
, void *key
, void *value
,
166 struct xsk_map
*m
= container_of(map
, struct xsk_map
, map
);
167 u32 i
= *(u32
*)key
, fd
= *(u32
*)value
;
168 struct xdp_sock
*xs
, *old_xs
;
172 if (unlikely(map_flags
> BPF_EXIST
))
174 if (unlikely(i
>= m
->map
.max_entries
))
176 if (unlikely(map_flags
== BPF_NOEXIST
))
179 sock
= sockfd_lookup(fd
, &err
);
183 if (sock
->sk
->sk_family
!= PF_XDP
) {
188 xs
= (struct xdp_sock
*)sock
->sk
;
190 if (!xsk_is_setup_for_bpf_map(xs
)) {
197 old_xs
= xchg(&m
->xsk_map
[i
], xs
);
199 sock_put((struct sock
*)old_xs
);
205 static int xsk_map_delete_elem(struct bpf_map
*map
, void *key
)
207 struct xsk_map
*m
= container_of(map
, struct xsk_map
, map
);
208 struct xdp_sock
*old_xs
;
211 if (k
>= map
->max_entries
)
214 old_xs
= xchg(&m
->xsk_map
[k
], NULL
);
216 sock_put((struct sock
*)old_xs
);
221 const struct bpf_map_ops xsk_map_ops
= {
222 .map_alloc
= xsk_map_alloc
,
223 .map_free
= xsk_map_free
,
224 .map_get_next_key
= xsk_map_get_next_key
,
225 .map_lookup_elem
= xsk_map_lookup_elem
,
226 .map_lookup_elem_sys_only
= xsk_map_lookup_elem_sys_only
,
227 .map_update_elem
= xsk_map_update_elem
,
228 .map_delete_elem
= xsk_map_delete_elem
,
229 .map_check_btf
= map_check_no_btf
,