2019-02-21 10:21:26 +01:00
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
/*
* AF_XDP user - space access library .
*
* Copyright ( c ) 2018 - 2019 Intel Corporation .
*
* Author ( s ) : Magnus Karlsson < magnus . karlsson @ intel . com >
*/
# include <errno.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <arpa/inet.h>
# include <asm/barrier.h>
# include <linux/compiler.h>
# include <linux/ethtool.h>
# include <linux/filter.h>
# include <linux/if_ether.h>
# include <linux/if_packet.h>
# include <linux/if_xdp.h>
2020-09-14 15:32:10 -07:00
# include <linux/kernel.h>
2020-08-28 10:26:27 +02:00
# include <linux/list.h>
2019-02-21 10:21:26 +01:00
# include <linux/sockios.h>
# include <net/if.h>
# include <sys/ioctl.h>
# include <sys/mman.h>
# include <sys/socket.h>
# include <sys/types.h>
# include "bpf.h"
# include "libbpf.h"
2019-05-15 20:39:27 -07:00
# include "libbpf_internal.h"
2019-02-21 10:21:26 +01:00
# include "xsk.h"
# ifndef SOL_XDP
# define SOL_XDP 283
# endif
# ifndef AF_XDP
# define AF_XDP 44
# endif
# ifndef PF_XDP
# define PF_XDP AF_XDP
# endif
2021-01-22 11:53:51 +01:00
enum xsk_prog {
XSK_PROG_FALLBACK ,
XSK_PROG_REDIRECT_FLAGS ,
} ;
2019-02-21 10:21:26 +01:00
struct xsk_umem {
2020-08-28 10:26:27 +02:00
struct xsk_ring_prod * fill_save ;
struct xsk_ring_cons * comp_save ;
2019-02-21 10:21:26 +01:00
char * umem_area ;
struct xsk_umem_config config ;
int fd ;
int refcount ;
2020-08-28 10:26:27 +02:00
struct list_head ctx_list ;
2021-03-31 06:12:18 +00:00
bool rx_ring_setup_done ;
bool tx_ring_setup_done ;
2020-08-28 10:26:27 +02:00
} ;
struct xsk_ctx {
struct xsk_ring_prod * fill ;
struct xsk_ring_cons * comp ;
__u32 queue_id ;
struct xsk_umem * umem ;
int refcount ;
int ifindex ;
struct list_head list ;
int prog_fd ;
int xsks_map_fd ;
char ifname [ IFNAMSIZ ] ;
2019-02-21 10:21:26 +01:00
} ;
struct xsk_socket {
struct xsk_ring_cons * rx ;
struct xsk_ring_prod * tx ;
__u64 outstanding_tx ;
2020-08-28 10:26:27 +02:00
struct xsk_ctx * ctx ;
2019-02-21 10:21:26 +01:00
struct xsk_socket_config config ;
int fd ;
} ;
struct xsk_nl_info {
bool xdp_prog_attached ;
int ifindex ;
int fd ;
} ;
2019-10-25 11:17:15 +02:00
/* Up until and including Linux 5.3 */
struct xdp_ring_offset_v1 {
__u64 producer ;
__u64 consumer ;
__u64 desc ;
} ;
/* Up until and including Linux 5.3 */
struct xdp_mmap_offsets_v1 {
struct xdp_ring_offset_v1 rx ;
struct xdp_ring_offset_v1 tx ;
struct xdp_ring_offset_v1 fr ;
struct xdp_ring_offset_v1 cr ;
} ;
2019-02-21 10:21:26 +01:00
int xsk_umem__fd ( const struct xsk_umem * umem )
{
return umem ? umem - > fd : - EINVAL ;
}
int xsk_socket__fd ( const struct xsk_socket * xsk )
{
return xsk ? xsk - > fd : - EINVAL ;
}
static bool xsk_page_aligned ( void * buffer )
{
unsigned long addr = ( unsigned long ) buffer ;
return ! ( addr & ( getpagesize ( ) - 1 ) ) ;
}
static void xsk_set_umem_config ( struct xsk_umem_config * cfg ,
const struct xsk_umem_config * usr_cfg )
{
if ( ! usr_cfg ) {
cfg - > fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS ;
cfg - > comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS ;
cfg - > frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE ;
cfg - > frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM ;
2019-08-27 02:25:27 +00:00
cfg - > flags = XSK_UMEM__DEFAULT_FLAGS ;
2019-02-21 10:21:26 +01:00
return ;
}
cfg - > fill_size = usr_cfg - > fill_size ;
cfg - > comp_size = usr_cfg - > comp_size ;
cfg - > frame_size = usr_cfg - > frame_size ;
cfg - > frame_headroom = usr_cfg - > frame_headroom ;
2019-08-27 02:25:27 +00:00
cfg - > flags = usr_cfg - > flags ;
2019-02-21 10:21:26 +01:00
}
2019-03-12 09:59:45 +01:00
static int xsk_set_xdp_socket_config ( struct xsk_socket_config * cfg ,
const struct xsk_socket_config * usr_cfg )
2019-02-21 10:21:26 +01:00
{
if ( ! usr_cfg ) {
cfg - > rx_size = XSK_RING_CONS__DEFAULT_NUM_DESCS ;
cfg - > tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS ;
cfg - > libbpf_flags = 0 ;
cfg - > xdp_flags = 0 ;
cfg - > bind_flags = 0 ;
2019-03-12 09:59:45 +01:00
return 0 ;
2019-02-21 10:21:26 +01:00
}
2019-03-12 09:59:45 +01:00
if ( usr_cfg - > libbpf_flags & ~ XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD )
return - EINVAL ;
2019-02-21 10:21:26 +01:00
cfg - > rx_size = usr_cfg - > rx_size ;
cfg - > tx_size = usr_cfg - > tx_size ;
cfg - > libbpf_flags = usr_cfg - > libbpf_flags ;
cfg - > xdp_flags = usr_cfg - > xdp_flags ;
cfg - > bind_flags = usr_cfg - > bind_flags ;
2019-03-12 09:59:45 +01:00
return 0 ;
2019-02-21 10:21:26 +01:00
}
2019-10-25 11:17:15 +02:00
static void xsk_mmap_offsets_v1 ( struct xdp_mmap_offsets * off )
{
struct xdp_mmap_offsets_v1 off_v1 ;
/* getsockopt on a kernel <= 5.3 has no flags fields.
* Copy over the offsets to the correct places in the > = 5.4 format
* and put the flags where they would have been on that kernel .
*/
memcpy ( & off_v1 , off , sizeof ( off_v1 ) ) ;
off - > rx . producer = off_v1 . rx . producer ;
off - > rx . consumer = off_v1 . rx . consumer ;
off - > rx . desc = off_v1 . rx . desc ;
2019-10-28 22:59:53 -07:00
off - > rx . flags = off_v1 . rx . consumer + sizeof ( __u32 ) ;
2019-10-25 11:17:15 +02:00
off - > tx . producer = off_v1 . tx . producer ;
off - > tx . consumer = off_v1 . tx . consumer ;
off - > tx . desc = off_v1 . tx . desc ;
2019-10-28 22:59:53 -07:00
off - > tx . flags = off_v1 . tx . consumer + sizeof ( __u32 ) ;
2019-10-25 11:17:15 +02:00
off - > fr . producer = off_v1 . fr . producer ;
off - > fr . consumer = off_v1 . fr . consumer ;
off - > fr . desc = off_v1 . fr . desc ;
2019-10-28 22:59:53 -07:00
off - > fr . flags = off_v1 . fr . consumer + sizeof ( __u32 ) ;
2019-10-25 11:17:15 +02:00
off - > cr . producer = off_v1 . cr . producer ;
off - > cr . consumer = off_v1 . cr . consumer ;
off - > cr . desc = off_v1 . cr . desc ;
2019-10-28 22:59:53 -07:00
off - > cr . flags = off_v1 . cr . consumer + sizeof ( __u32 ) ;
2019-10-25 11:17:15 +02:00
}
static int xsk_get_mmap_offsets ( int fd , struct xdp_mmap_offsets * off )
{
socklen_t optlen ;
int err ;
optlen = sizeof ( * off ) ;
err = getsockopt ( fd , SOL_XDP , XDP_MMAP_OFFSETS , off , & optlen ) ;
if ( err )
return err ;
if ( optlen = = sizeof ( * off ) )
return 0 ;
if ( optlen = = sizeof ( struct xdp_mmap_offsets_v1 ) ) {
xsk_mmap_offsets_v1 ( off ) ;
return 0 ;
}
return - EINVAL ;
}
2020-08-28 10:26:27 +02:00
static int xsk_create_umem_rings ( struct xsk_umem * umem , int fd ,
struct xsk_ring_prod * fill ,
struct xsk_ring_cons * comp )
{
struct xdp_mmap_offsets off ;
void * map ;
int err ;
err = setsockopt ( fd , SOL_XDP , XDP_UMEM_FILL_RING ,
& umem - > config . fill_size ,
sizeof ( umem - > config . fill_size ) ) ;
if ( err )
return - errno ;
err = setsockopt ( fd , SOL_XDP , XDP_UMEM_COMPLETION_RING ,
& umem - > config . comp_size ,
sizeof ( umem - > config . comp_size ) ) ;
if ( err )
return - errno ;
err = xsk_get_mmap_offsets ( fd , & off ) ;
if ( err )
return - errno ;
map = mmap ( NULL , off . fr . desc + umem - > config . fill_size * sizeof ( __u64 ) ,
PROT_READ | PROT_WRITE , MAP_SHARED | MAP_POPULATE , fd ,
XDP_UMEM_PGOFF_FILL_RING ) ;
if ( map = = MAP_FAILED )
return - errno ;
fill - > mask = umem - > config . fill_size - 1 ;
fill - > size = umem - > config . fill_size ;
fill - > producer = map + off . fr . producer ;
fill - > consumer = map + off . fr . consumer ;
fill - > flags = map + off . fr . flags ;
fill - > ring = map + off . fr . desc ;
fill - > cached_cons = umem - > config . fill_size ;
map = mmap ( NULL , off . cr . desc + umem - > config . comp_size * sizeof ( __u64 ) ,
PROT_READ | PROT_WRITE , MAP_SHARED | MAP_POPULATE , fd ,
XDP_UMEM_PGOFF_COMPLETION_RING ) ;
if ( map = = MAP_FAILED ) {
err = - errno ;
goto out_mmap ;
}
comp - > mask = umem - > config . comp_size - 1 ;
comp - > size = umem - > config . comp_size ;
comp - > producer = map + off . cr . producer ;
comp - > consumer = map + off . cr . consumer ;
comp - > flags = map + off . cr . flags ;
comp - > ring = map + off . cr . desc ;
return 0 ;
out_mmap :
munmap ( map , off . fr . desc + umem - > config . fill_size * sizeof ( __u64 ) ) ;
return err ;
}
2019-08-27 02:25:27 +00:00
int xsk_umem__create_v0_0_4 ( struct xsk_umem * * umem_ptr , void * umem_area ,
__u64 size , struct xsk_ring_prod * fill ,
struct xsk_ring_cons * comp ,
const struct xsk_umem_config * usr_config )
2019-02-21 10:21:26 +01:00
{
struct xdp_umem_reg mr ;
struct xsk_umem * umem ;
int err ;
if ( ! umem_area | | ! umem_ptr | | ! fill | | ! comp )
return - EFAULT ;
if ( ! size & & ! xsk_page_aligned ( umem_area ) )
return - EINVAL ;
umem = calloc ( 1 , sizeof ( * umem ) ) ;
if ( ! umem )
return - ENOMEM ;
umem - > fd = socket ( AF_XDP , SOCK_RAW , 0 ) ;
if ( umem - > fd < 0 ) {
err = - errno ;
goto out_umem_alloc ;
}
umem - > umem_area = umem_area ;
2020-08-28 10:26:27 +02:00
INIT_LIST_HEAD ( & umem - > ctx_list ) ;
2019-02-21 10:21:26 +01:00
xsk_set_umem_config ( & umem - > config , usr_config ) ;
2019-10-09 18:49:29 +02:00
memset ( & mr , 0 , sizeof ( mr ) ) ;
2019-02-21 10:21:26 +01:00
mr . addr = ( uintptr_t ) umem_area ;
mr . len = size ;
mr . chunk_size = umem - > config . frame_size ;
mr . headroom = umem - > config . frame_headroom ;
2019-08-27 02:25:27 +00:00
mr . flags = umem - > config . flags ;
2019-02-21 10:21:26 +01:00
err = setsockopt ( umem - > fd , SOL_XDP , XDP_UMEM_REG , & mr , sizeof ( mr ) ) ;
if ( err ) {
err = - errno ;
goto out_socket ;
}
2020-08-28 10:26:27 +02:00
err = xsk_create_umem_rings ( umem , umem - > fd , fill , comp ) ;
if ( err )
2019-02-21 10:21:26 +01:00
goto out_socket ;
2020-08-28 10:26:27 +02:00
umem - > fill_save = fill ;
umem - > comp_save = comp ;
2019-02-21 10:21:26 +01:00
* umem_ptr = umem ;
return 0 ;
out_socket :
close ( umem - > fd ) ;
out_umem_alloc :
free ( umem ) ;
return err ;
}
2019-08-27 02:25:27 +00:00
struct xsk_umem_config_v1 {
__u32 fill_size ;
__u32 comp_size ;
__u32 frame_size ;
__u32 frame_headroom ;
} ;
int xsk_umem__create_v0_0_2 ( struct xsk_umem * * umem_ptr , void * umem_area ,
__u64 size , struct xsk_ring_prod * fill ,
struct xsk_ring_cons * comp ,
const struct xsk_umem_config * usr_config )
{
struct xsk_umem_config config ;
memcpy ( & config , usr_config , sizeof ( struct xsk_umem_config_v1 ) ) ;
config . flags = 0 ;
return xsk_umem__create_v0_0_4 ( umem_ptr , umem_area , size , fill , comp ,
& config ) ;
}
libbpf: handle symbol versioning properly for libbpf.a
bcc uses libbpf repo as a submodule. It brings in libbpf source
code and builds everything together to produce shared libraries.
With latest libbpf, I got the following errors:
/bin/ld: libbcc_bpf.so.0.10.0: version node not found for symbol xsk_umem__create@LIBBPF_0.0.2
/bin/ld: failed to set dynamic section sizes: Bad value
collect2: error: ld returned 1 exit status
make[2]: *** [src/cc/libbcc_bpf.so.0.10.0] Error 1
In xsk.c, we have
asm(".symver xsk_umem__create_v0_0_2, xsk_umem__create@LIBBPF_0.0.2");
asm(".symver xsk_umem__create_v0_0_4, xsk_umem__create@@LIBBPF_0.0.4");
The linker thinks the built is for LIBBPF but cannot find proper version
LIBBPF_0.0.2/4, so emit errors.
I also confirmed that using libbpf.a to produce a shared library also
has issues:
-bash-4.4$ cat t.c
extern void *xsk_umem__create;
void * test() { return xsk_umem__create; }
-bash-4.4$ gcc -c -fPIC t.c
-bash-4.4$ gcc -shared t.o libbpf.a -o t.so
/bin/ld: t.so: version node not found for symbol xsk_umem__create@LIBBPF_0.0.2
/bin/ld: failed to set dynamic section sizes: Bad value
collect2: error: ld returned 1 exit status
-bash-4.4$
Symbol versioning does happens in commonly used libraries, e.g., elfutils
and glibc. For static libraries, for a versioned symbol, the old definitions
will be ignored, and the symbol will be an alias to the latest definition.
For example, glibc sched_setaffinity is versioned.
-bash-4.4$ readelf -s /usr/lib64/libc.so.6 | grep sched_setaffinity
756: 000000000013d3d0 13 FUNC GLOBAL DEFAULT 13 sched_setaffinity@GLIBC_2.3.3
757: 00000000000e2e70 455 FUNC GLOBAL DEFAULT 13 sched_setaffinity@@GLIBC_2.3.4
1800: 0000000000000000 0 FILE LOCAL DEFAULT ABS sched_setaffinity.c
4228: 00000000000e2e70 455 FUNC LOCAL DEFAULT 13 __sched_setaffinity_new
4648: 000000000013d3d0 13 FUNC LOCAL DEFAULT 13 __sched_setaffinity_old
7338: 000000000013d3d0 13 FUNC GLOBAL DEFAULT 13 sched_setaffinity@GLIBC_2
7380: 00000000000e2e70 455 FUNC GLOBAL DEFAULT 13 sched_setaffinity@@GLIBC_
-bash-4.4$
For static library, the definition of sched_setaffinity aliases to the new definition.
-bash-4.4$ readelf -s /usr/lib64/libc.a | grep sched_setaffinity
File: /usr/lib64/libc.a(sched_setaffinity.o)
8: 0000000000000000 455 FUNC GLOBAL DEFAULT 1 __sched_setaffinity_new
12: 0000000000000000 455 FUNC WEAK DEFAULT 1 sched_setaffinity
For both elfutils and glibc, additional macros are used to control different handling
of symbol versioning w.r.t static and shared libraries.
For elfutils, the macro is SYMBOL_VERSIONING
(https://sourceware.org/git/?p=elfutils.git;a=blob;f=lib/eu-config.h).
For glibc, the macro is SHARED
(https://sourceware.org/git/?p=glibc.git;a=blob;f=include/shlib-compat.h;hb=refs/heads/master)
This patch used SHARED as the macro name. After this patch, the libbpf.a has
-bash-4.4$ readelf -s libbpf.a | grep xsk_umem__create
372: 0000000000017145 1190 FUNC GLOBAL DEFAULT 1 xsk_umem__create_v0_0_4
405: 0000000000017145 1190 FUNC GLOBAL DEFAULT 1 xsk_umem__create
499: 00000000000175eb 103 FUNC GLOBAL DEFAULT 1 xsk_umem__create_v0_0_2
-bash-4.4$
No versioned symbols for xsk_umem__create.
The libbpf.a can be used to build a shared library succesfully.
-bash-4.4$ cat t.c
extern void *xsk_umem__create;
void * test() { return xsk_umem__create; }
-bash-4.4$ gcc -c -fPIC t.c
-bash-4.4$ gcc -shared t.o libbpf.a -o t.so
-bash-4.4$
Fixes: 10d30e301732 ("libbpf: add flags to umem config")
Cc: Kevin Laatz <kevin.laatz@intel.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Andrii Nakryiko <andriin@fb.com>
Acked-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-09-30 14:02:03 -07:00
COMPAT_VERSION ( xsk_umem__create_v0_0_2 , xsk_umem__create , LIBBPF_0 .0 .2 )
DEFAULT_VERSION ( xsk_umem__create_v0_0_4 , xsk_umem__create , LIBBPF_0 .0 .4 )
2019-08-27 02:25:27 +00:00
2021-01-22 11:53:51 +01:00
static enum xsk_prog get_xsk_prog ( void )
{
enum xsk_prog detected = XSK_PROG_FALLBACK ;
struct bpf_load_program_attr prog_attr ;
struct bpf_create_map_attr map_attr ;
__u32 size_out , retval , duration ;
char data_in = 0 , data_out ;
struct bpf_insn insns [ ] = {
BPF_LD_MAP_FD ( BPF_REG_1 , 0 ) ,
BPF_MOV64_IMM ( BPF_REG_2 , 0 ) ,
BPF_MOV64_IMM ( BPF_REG_3 , XDP_PASS ) ,
BPF_EMIT_CALL ( BPF_FUNC_redirect_map ) ,
BPF_EXIT_INSN ( ) ,
} ;
int prog_fd , map_fd , ret ;
memset ( & map_attr , 0 , sizeof ( map_attr ) ) ;
map_attr . map_type = BPF_MAP_TYPE_XSKMAP ;
map_attr . key_size = sizeof ( int ) ;
map_attr . value_size = sizeof ( int ) ;
map_attr . max_entries = 1 ;
map_fd = bpf_create_map_xattr ( & map_attr ) ;
if ( map_fd < 0 )
return detected ;
insns [ 0 ] . imm = map_fd ;
memset ( & prog_attr , 0 , sizeof ( prog_attr ) ) ;
prog_attr . prog_type = BPF_PROG_TYPE_XDP ;
prog_attr . insns = insns ;
prog_attr . insns_cnt = ARRAY_SIZE ( insns ) ;
prog_attr . license = " GPL " ;
prog_fd = bpf_load_program_xattr ( & prog_attr , NULL , 0 ) ;
if ( prog_fd < 0 ) {
close ( map_fd ) ;
return detected ;
}
ret = bpf_prog_test_run ( prog_fd , 0 , & data_in , 1 , & data_out , & size_out , & retval , & duration ) ;
if ( ! ret & & retval = = XDP_PASS )
detected = XSK_PROG_REDIRECT_FLAGS ;
close ( prog_fd ) ;
close ( map_fd ) ;
return detected ;
}
2019-02-21 10:21:26 +01:00
static int xsk_load_xdp_prog ( struct xsk_socket * xsk )
{
2019-04-10 08:54:16 +02:00
static const int log_buf_size = 16 * 1024 ;
2020-08-28 10:26:27 +02:00
struct xsk_ctx * ctx = xsk - > ctx ;
2019-04-10 08:54:16 +02:00
char log_buf [ log_buf_size ] ;
2019-02-21 10:21:26 +01:00
int err , prog_fd ;
2021-01-22 11:53:51 +01:00
/* This is the fallback C-program:
2019-02-21 10:21:26 +01:00
* SEC ( " xdp_sock " ) int xdp_sock_prog ( struct xdp_md * ctx )
* {
2019-10-22 09:22:06 +02:00
* int ret , index = ctx - > rx_queue_index ;
2019-02-21 10:21:26 +01:00
*
* // A set entry here means that the correspnding queue_id
* // has an active AF_XDP socket bound to it.
2019-10-22 09:22:06 +02:00
* ret = bpf_redirect_map ( & xsks_map , index , XDP_PASS ) ;
* if ( ret > 0 )
* return ret ;
*
* // Fallback for pre-5.3 kernels, not supporting default
* // action in the flags parameter.
2019-06-06 13:59:43 -07:00
* if ( bpf_map_lookup_elem ( & xsks_map , & index ) )
2019-02-21 10:21:26 +01:00
* return bpf_redirect_map ( & xsks_map , index , 0 ) ;
* return XDP_PASS ;
* }
*/
struct bpf_insn prog [ ] = {
2019-10-22 09:22:06 +02:00
/* r2 = *(u32 *)(r1 + 16) */
BPF_LDX_MEM ( BPF_W , BPF_REG_2 , BPF_REG_1 , 16 ) ,
/* *(u32 *)(r10 - 4) = r2 */
BPF_STX_MEM ( BPF_W , BPF_REG_10 , BPF_REG_2 , - 4 ) ,
/* r1 = xskmap[] */
2020-08-28 10:26:27 +02:00
BPF_LD_MAP_FD ( BPF_REG_1 , ctx - > xsks_map_fd ) ,
2019-10-22 09:22:06 +02:00
/* r3 = XDP_PASS */
BPF_MOV64_IMM ( BPF_REG_3 , 2 ) ,
/* call bpf_redirect_map */
BPF_EMIT_CALL ( BPF_FUNC_redirect_map ) ,
/* if w0 != 0 goto pc+13 */
BPF_JMP32_IMM ( BPF_JSGT , BPF_REG_0 , 0 , 13 ) ,
/* r2 = r10 */
2019-02-21 10:21:26 +01:00
BPF_MOV64_REG ( BPF_REG_2 , BPF_REG_10 ) ,
2019-10-22 09:22:06 +02:00
/* r2 += -4 */
2019-02-21 10:21:26 +01:00
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_2 , - 4 ) ,
2019-10-22 09:22:06 +02:00
/* r1 = xskmap[] */
2020-08-28 10:26:27 +02:00
BPF_LD_MAP_FD ( BPF_REG_1 , ctx - > xsks_map_fd ) ,
2019-10-22 09:22:06 +02:00
/* call bpf_map_lookup_elem */
2019-02-21 10:21:26 +01:00
BPF_EMIT_CALL ( BPF_FUNC_map_lookup_elem ) ,
2019-10-22 09:22:06 +02:00
/* r1 = r0 */
2019-02-21 10:21:26 +01:00
BPF_MOV64_REG ( BPF_REG_1 , BPF_REG_0 ) ,
2019-10-22 09:22:06 +02:00
/* r0 = XDP_PASS */
BPF_MOV64_IMM ( BPF_REG_0 , 2 ) ,
/* if r1 == 0 goto pc+5 */
2019-02-21 10:21:26 +01:00
BPF_JMP_IMM ( BPF_JEQ , BPF_REG_1 , 0 , 5 ) ,
/* r2 = *(u32 *)(r10 - 4) */
BPF_LDX_MEM ( BPF_W , BPF_REG_2 , BPF_REG_10 , - 4 ) ,
2019-10-22 09:22:06 +02:00
/* r1 = xskmap[] */
2020-08-28 10:26:27 +02:00
BPF_LD_MAP_FD ( BPF_REG_1 , ctx - > xsks_map_fd ) ,
2019-10-22 09:22:06 +02:00
/* r3 = 0 */
BPF_MOV64_IMM ( BPF_REG_3 , 0 ) ,
/* call bpf_redirect_map */
2019-02-21 10:21:26 +01:00
BPF_EMIT_CALL ( BPF_FUNC_redirect_map ) ,
/* The jumps are to this instruction */
BPF_EXIT_INSN ( ) ,
} ;
2021-01-22 11:53:51 +01:00
/* This is the post-5.3 kernel C-program:
* SEC ( " xdp_sock " ) int xdp_sock_prog ( struct xdp_md * ctx )
* {
* return bpf_redirect_map ( & xsks_map , ctx - > rx_queue_index , XDP_PASS ) ;
* }
*/
struct bpf_insn prog_redirect_flags [ ] = {
/* r2 = *(u32 *)(r1 + 16) */
BPF_LDX_MEM ( BPF_W , BPF_REG_2 , BPF_REG_1 , 16 ) ,
/* r1 = xskmap[] */
BPF_LD_MAP_FD ( BPF_REG_1 , ctx - > xsks_map_fd ) ,
/* r3 = XDP_PASS */
BPF_MOV64_IMM ( BPF_REG_3 , 2 ) ,
/* call bpf_redirect_map */
BPF_EMIT_CALL ( BPF_FUNC_redirect_map ) ,
BPF_EXIT_INSN ( ) ,
} ;
size_t insns_cnt [ ] = { sizeof ( prog ) / sizeof ( struct bpf_insn ) ,
sizeof ( prog_redirect_flags ) / sizeof ( struct bpf_insn ) ,
} ;
struct bpf_insn * progs [ ] = { prog , prog_redirect_flags } ;
enum xsk_prog option = get_xsk_prog ( ) ;
prog_fd = bpf_load_program ( BPF_PROG_TYPE_XDP , progs [ option ] , insns_cnt [ option ] ,
2019-04-10 08:54:16 +02:00
" LGPL-2.1 or BSD-2-Clause " , 0 , log_buf ,
log_buf_size ) ;
2019-02-21 10:21:26 +01:00
if ( prog_fd < 0 ) {
2019-10-21 13:55:32 +08:00
pr_warn ( " BPF log buffer: \n %s " , log_buf ) ;
2019-02-21 10:21:26 +01:00
return prog_fd ;
}
2020-08-28 10:26:27 +02:00
err = bpf_set_link_xdp_fd ( xsk - > ctx - > ifindex , prog_fd ,
xsk - > config . xdp_flags ) ;
2019-02-21 10:21:26 +01:00
if ( err ) {
close ( prog_fd ) ;
return err ;
}
2020-08-28 10:26:27 +02:00
ctx - > prog_fd = prog_fd ;
2019-02-21 10:21:26 +01:00
return 0 ;
}
static int xsk_get_max_queues ( struct xsk_socket * xsk )
{
2019-07-23 15:08:10 +03:00
struct ethtool_channels channels = { . cmd = ETHTOOL_GCHANNELS } ;
2020-08-28 10:26:27 +02:00
struct xsk_ctx * ctx = xsk - > ctx ;
2019-07-23 15:08:10 +03:00
struct ifreq ifr = { } ;
2019-02-21 10:21:26 +01:00
int fd , err , ret ;
2021-02-09 14:18:26 -08:00
fd = socket ( AF_LOCAL , SOCK_DGRAM , 0 ) ;
2019-02-21 10:21:26 +01:00
if ( fd < 0 )
return - errno ;
ifr . ifr_data = ( void * ) & channels ;
2020-08-28 10:26:27 +02:00
memcpy ( ifr . ifr_name , ctx - > ifname , IFNAMSIZ - 1 ) ;
2019-07-02 08:16:20 -07:00
ifr . ifr_name [ IFNAMSIZ - 1 ] = ' \0 ' ;
2019-02-21 10:21:26 +01:00
err = ioctl ( fd , SIOCETHTOOL , & ifr ) ;
if ( err & & errno ! = EOPNOTSUPP ) {
ret = - errno ;
goto out ;
}
2019-11-18 16:19:51 -08:00
if ( err ) {
2019-02-21 10:21:26 +01:00
/* If the device says it has no channels, then all traffic
* is sent to a single stream , so max queues = 1.
*/
ret = 1 ;
2019-11-18 16:19:51 -08:00
} else {
/* Take the max of rx, tx, combined. Drivers return
* the number of channels in different ways .
*/
ret = max ( channels . max_rx , channels . max_tx ) ;
ret = max ( ret , ( int ) channels . max_combined ) ;
}
2019-02-21 10:21:26 +01:00
out :
close ( fd ) ;
return ret ;
}
static int xsk_create_bpf_maps ( struct xsk_socket * xsk )
{
2020-08-28 10:26:27 +02:00
struct xsk_ctx * ctx = xsk - > ctx ;
2019-02-21 10:21:26 +01:00
int max_queues ;
int fd ;
max_queues = xsk_get_max_queues ( xsk ) ;
if ( max_queues < 0 )
return max_queues ;
2019-06-06 13:59:43 -07:00
fd = bpf_create_map_name ( BPF_MAP_TYPE_XSKMAP , " xsks_map " ,
2019-02-21 10:21:26 +01:00
sizeof ( int ) , sizeof ( int ) , max_queues , 0 ) ;
if ( fd < 0 )
return fd ;
2020-08-28 10:26:27 +02:00
ctx - > xsks_map_fd = fd ;
2019-02-21 10:21:26 +01:00
return 0 ;
}
static void xsk_delete_bpf_maps ( struct xsk_socket * xsk )
{
2020-08-28 10:26:27 +02:00
struct xsk_ctx * ctx = xsk - > ctx ;
bpf_map_delete_elem ( ctx - > xsks_map_fd , & ctx - > queue_id ) ;
close ( ctx - > xsks_map_fd ) ;
2019-02-21 10:21:26 +01:00
}
2019-04-30 14:45:36 +02:00
static int xsk_lookup_bpf_maps ( struct xsk_socket * xsk )
2019-02-21 10:21:26 +01:00
{
2019-04-30 14:45:36 +02:00
__u32 i , * map_ids , num_maps , prog_len = sizeof ( struct bpf_prog_info ) ;
__u32 map_len = sizeof ( struct bpf_map_info ) ;
2019-02-21 10:21:26 +01:00
struct bpf_prog_info prog_info = { } ;
2020-08-28 10:26:27 +02:00
struct xsk_ctx * ctx = xsk - > ctx ;
2019-02-21 10:21:26 +01:00
struct bpf_map_info map_info ;
2019-04-30 14:45:36 +02:00
int fd , err ;
2019-02-21 10:21:26 +01:00
2020-08-28 10:26:27 +02:00
err = bpf_obj_get_info_by_fd ( ctx - > prog_fd , & prog_info , & prog_len ) ;
2019-02-21 10:21:26 +01:00
if ( err )
return err ;
num_maps = prog_info . nr_map_ids ;
map_ids = calloc ( prog_info . nr_map_ids , sizeof ( * map_ids ) ) ;
if ( ! map_ids )
return - ENOMEM ;
memset ( & prog_info , 0 , prog_len ) ;
prog_info . nr_map_ids = num_maps ;
prog_info . map_ids = ( __u64 ) ( unsigned long ) map_ids ;
2020-08-28 10:26:27 +02:00
err = bpf_obj_get_info_by_fd ( ctx - > prog_fd , & prog_info , & prog_len ) ;
2019-02-21 10:21:26 +01:00
if ( err )
goto out_map_ids ;
2020-08-28 10:26:27 +02:00
ctx - > xsks_map_fd = - 1 ;
2019-02-21 10:21:26 +01:00
2019-06-06 13:59:43 -07:00
for ( i = 0 ; i < prog_info . nr_map_ids ; i + + ) {
2019-02-21 10:21:26 +01:00
fd = bpf_map_get_fd_by_id ( map_ids [ i ] ) ;
2019-04-30 14:45:36 +02:00
if ( fd < 0 )
continue ;
2019-02-21 10:21:26 +01:00
2021-03-03 19:56:36 +01:00
memset ( & map_info , 0 , map_len ) ;
2019-02-21 10:21:26 +01:00
err = bpf_obj_get_info_by_fd ( fd , & map_info , & map_len ) ;
2019-04-30 14:45:36 +02:00
if ( err ) {
close ( fd ) ;
continue ;
}
2019-02-21 10:21:26 +01:00
2021-03-03 19:56:36 +01:00
if ( ! strncmp ( map_info . name , " xsks_map " , sizeof ( map_info . name ) ) ) {
2020-08-28 10:26:27 +02:00
ctx - > xsks_map_fd = fd ;
2021-03-03 19:56:36 +01:00
break ;
2019-02-21 10:21:26 +01:00
}
2019-04-30 14:45:36 +02:00
close ( fd ) ;
2019-02-21 10:21:26 +01:00
}
2019-04-30 14:45:36 +02:00
err = 0 ;
2020-08-28 10:26:27 +02:00
if ( ctx - > xsks_map_fd = = - 1 )
2019-02-21 10:21:26 +01:00
err = - ENOENT ;
out_map_ids :
free ( map_ids ) ;
return err ;
}
2019-04-30 14:45:36 +02:00
static int xsk_set_bpf_maps ( struct xsk_socket * xsk )
{
2020-08-28 10:26:27 +02:00
struct xsk_ctx * ctx = xsk - > ctx ;
return bpf_map_update_elem ( ctx - > xsks_map_fd , & ctx - > queue_id ,
2019-06-06 13:59:43 -07:00
& xsk - > fd , 0 ) ;
2019-04-30 14:45:36 +02:00
}
2020-12-03 10:05:45 +01:00
static int xsk_create_xsk_struct ( int ifindex , struct xsk_socket * xsk )
2019-02-21 10:21:26 +01:00
{
2020-12-03 10:05:45 +01:00
char ifname [ IFNAMSIZ ] ;
struct xsk_ctx * ctx ;
char * interface ;
ctx = calloc ( 1 , sizeof ( * ctx ) ) ;
if ( ! ctx )
return - ENOMEM ;
interface = if_indextoname ( ifindex , & ifname [ 0 ] ) ;
if ( ! interface ) {
free ( ctx ) ;
return - errno ;
}
ctx - > ifindex = ifindex ;
2020-12-03 15:54:39 -08:00
memcpy ( ctx - > ifname , ifname , IFNAMSIZ - 1 ) ;
2020-12-03 10:05:45 +01:00
ctx - > ifname [ IFNAMSIZ - 1 ] = 0 ;
xsk - > ctx = ctx ;
return 0 ;
}
static int __xsk_setup_xdp_prog ( struct xsk_socket * _xdp ,
int * xsks_map_fd )
{
struct xsk_socket * xsk = _xdp ;
2020-08-28 10:26:27 +02:00
struct xsk_ctx * ctx = xsk - > ctx ;
2019-02-21 10:21:26 +01:00
__u32 prog_id = 0 ;
int err ;
2020-08-28 10:26:27 +02:00
err = bpf_get_link_xdp_id ( ctx - > ifindex , & prog_id ,
2019-02-21 10:21:26 +01:00
xsk - > config . xdp_flags ) ;
if ( err )
return err ;
if ( ! prog_id ) {
err = xsk_create_bpf_maps ( xsk ) ;
if ( err )
return err ;
err = xsk_load_xdp_prog ( xsk ) ;
2019-06-06 13:59:43 -07:00
if ( err ) {
2020-12-03 10:05:45 +01:00
goto err_load_xdp_prog ;
2019-06-06 13:59:43 -07:00
}
2019-02-21 10:21:26 +01:00
} else {
2020-08-28 10:26:27 +02:00
ctx - > prog_fd = bpf_prog_get_fd_by_id ( prog_id ) ;
if ( ctx - > prog_fd < 0 )
2019-11-06 21:40:59 -08:00
return - errno ;
2019-04-30 14:45:36 +02:00
err = xsk_lookup_bpf_maps ( xsk ) ;
2019-06-06 13:59:43 -07:00
if ( err ) {
2020-08-28 10:26:27 +02:00
close ( ctx - > prog_fd ) ;
2019-06-06 13:59:43 -07:00
return err ;
}
2019-02-21 10:21:26 +01:00
}
2020-12-03 10:05:45 +01:00
if ( xsk - > rx ) {
2019-11-07 18:47:38 +01:00
err = xsk_set_bpf_maps ( xsk ) ;
2020-12-03 10:05:45 +01:00
if ( err ) {
if ( ! prog_id ) {
goto err_set_bpf_maps ;
} else {
close ( ctx - > prog_fd ) ;
return err ;
}
}
2019-06-06 13:59:43 -07:00
}
2020-12-03 10:05:45 +01:00
if ( xsks_map_fd )
* xsks_map_fd = ctx - > xsks_map_fd ;
2019-02-21 10:21:26 +01:00
return 0 ;
2020-12-03 10:05:45 +01:00
err_set_bpf_maps :
close ( ctx - > prog_fd ) ;
bpf_set_link_xdp_fd ( ctx - > ifindex , - 1 , 0 ) ;
err_load_xdp_prog :
xsk_delete_bpf_maps ( xsk ) ;
return err ;
2019-02-21 10:21:26 +01:00
}
2020-08-28 10:26:27 +02:00
static struct xsk_ctx * xsk_get_ctx ( struct xsk_umem * umem , int ifindex ,
__u32 queue_id )
{
struct xsk_ctx * ctx ;
if ( list_empty ( & umem - > ctx_list ) )
return NULL ;
list_for_each_entry ( ctx , & umem - > ctx_list , list ) {
if ( ctx - > ifindex = = ifindex & & ctx - > queue_id = = queue_id ) {
ctx - > refcount + + ;
return ctx ;
}
}
return NULL ;
}
2021-03-31 06:12:17 +00:00
static void xsk_put_ctx ( struct xsk_ctx * ctx , bool unmap )
2020-08-28 10:26:27 +02:00
{
struct xsk_umem * umem = ctx - > umem ;
struct xdp_mmap_offsets off ;
int err ;
2021-03-31 06:12:17 +00:00
if ( - - ctx - > refcount )
return ;
2020-08-28 10:26:27 +02:00
2021-03-31 06:12:17 +00:00
if ( ! unmap )
goto out_free ;
err = xsk_get_mmap_offsets ( umem - > fd , & off ) ;
if ( err )
goto out_free ;
munmap ( ctx - > fill - > ring - off . fr . desc , off . fr . desc + umem - > config . fill_size *
sizeof ( __u64 ) ) ;
munmap ( ctx - > comp - > ring - off . cr . desc , off . cr . desc + umem - > config . comp_size *
sizeof ( __u64 ) ) ;
out_free :
list_del ( & ctx - > list ) ;
free ( ctx ) ;
2020-08-28 10:26:27 +02:00
}
static struct xsk_ctx * xsk_create_ctx ( struct xsk_socket * xsk ,
struct xsk_umem * umem , int ifindex ,
const char * ifname , __u32 queue_id ,
struct xsk_ring_prod * fill ,
struct xsk_ring_cons * comp )
{
struct xsk_ctx * ctx ;
int err ;
ctx = calloc ( 1 , sizeof ( * ctx ) ) ;
if ( ! ctx )
return NULL ;
if ( ! umem - > fill_save ) {
err = xsk_create_umem_rings ( umem , xsk - > fd , fill , comp ) ;
if ( err ) {
free ( ctx ) ;
return NULL ;
}
} else if ( umem - > fill_save ! = fill | | umem - > comp_save ! = comp ) {
/* Copy over rings to new structs. */
memcpy ( fill , umem - > fill_save , sizeof ( * fill ) ) ;
memcpy ( comp , umem - > comp_save , sizeof ( * comp ) ) ;
}
ctx - > ifindex = ifindex ;
ctx - > refcount = 1 ;
ctx - > umem = umem ;
ctx - > queue_id = queue_id ;
memcpy ( ctx - > ifname , ifname , IFNAMSIZ - 1 ) ;
ctx - > ifname [ IFNAMSIZ - 1 ] = ' \0 ' ;
ctx - > fill = fill ;
ctx - > comp = comp ;
list_add ( & ctx - > list , & umem - > ctx_list ) ;
return ctx ;
}
2020-12-03 10:05:45 +01:00
static void xsk_destroy_xsk_struct ( struct xsk_socket * xsk )
{
free ( xsk - > ctx ) ;
free ( xsk ) ;
}
int xsk_socket__update_xskmap ( struct xsk_socket * xsk , int fd )
{
xsk - > ctx - > xsks_map_fd = fd ;
return xsk_set_bpf_maps ( xsk ) ;
}
int xsk_setup_xdp_prog ( int ifindex , int * xsks_map_fd )
{
struct xsk_socket * xsk ;
int res ;
xsk = calloc ( 1 , sizeof ( * xsk ) ) ;
if ( ! xsk )
return - ENOMEM ;
res = xsk_create_xsk_struct ( ifindex , xsk ) ;
if ( res ) {
free ( xsk ) ;
return - EINVAL ;
}
res = __xsk_setup_xdp_prog ( xsk , xsks_map_fd ) ;
xsk_destroy_xsk_struct ( xsk ) ;
return res ;
}
2020-08-28 10:26:27 +02:00
int xsk_socket__create_shared ( struct xsk_socket * * xsk_ptr ,
const char * ifname ,
__u32 queue_id , struct xsk_umem * umem ,
struct xsk_ring_cons * rx ,
struct xsk_ring_prod * tx ,
struct xsk_ring_prod * fill ,
struct xsk_ring_cons * comp ,
const struct xsk_socket_config * usr_config )
2019-02-21 10:21:26 +01:00
{
2021-04-08 05:20:09 +00:00
bool unmap , rx_setup_done = false , tx_setup_done = false ;
2019-04-30 14:45:35 +02:00
void * rx_map = NULL , * tx_map = NULL ;
2019-02-21 10:21:26 +01:00
struct sockaddr_xdp sxdp = { } ;
struct xdp_mmap_offsets off ;
struct xsk_socket * xsk ;
2020-08-28 10:26:27 +02:00
struct xsk_ctx * ctx ;
int err , ifindex ;
2019-02-21 10:21:26 +01:00
2020-10-07 13:42:26 +02:00
if ( ! umem | | ! xsk_ptr | | ! ( rx | | tx ) )
2019-02-21 10:21:26 +01:00
return - EFAULT ;
2021-04-08 05:20:09 +00:00
unmap = umem - > fill_save ! = fill ;
2019-02-21 10:21:26 +01:00
xsk = calloc ( 1 , sizeof ( * xsk ) ) ;
if ( ! xsk )
return - ENOMEM ;
2019-11-07 18:47:36 +01:00
err = xsk_set_xdp_socket_config ( & xsk - > config , usr_config ) ;
if ( err )
goto out_xsk_alloc ;
2020-08-28 10:26:27 +02:00
xsk - > outstanding_tx = 0 ;
ifindex = if_nametoindex ( ifname ) ;
if ( ! ifindex ) {
err = - errno ;
2019-11-07 18:47:36 +01:00
goto out_xsk_alloc ;
}
2019-02-21 10:21:26 +01:00
if ( umem - > refcount + + > 0 ) {
xsk - > fd = socket ( AF_XDP , SOCK_RAW , 0 ) ;
if ( xsk - > fd < 0 ) {
err = - errno ;
goto out_xsk_alloc ;
}
} else {
xsk - > fd = umem - > fd ;
2021-03-31 06:12:18 +00:00
rx_setup_done = umem - > rx_ring_setup_done ;
tx_setup_done = umem - > tx_ring_setup_done ;
2019-02-21 10:21:26 +01:00
}
2020-08-28 10:26:27 +02:00
ctx = xsk_get_ctx ( umem , ifindex , queue_id ) ;
if ( ! ctx ) {
2020-10-07 13:42:26 +02:00
if ( ! fill | | ! comp ) {
err = - EFAULT ;
goto out_socket ;
}
2020-08-28 10:26:27 +02:00
ctx = xsk_create_ctx ( xsk , umem , ifindex , ifname , queue_id ,
fill , comp ) ;
if ( ! ctx ) {
err = - ENOMEM ;
goto out_socket ;
}
2019-02-21 10:21:26 +01:00
}
2020-08-28 10:26:27 +02:00
xsk - > ctx = ctx ;
2019-02-21 10:21:26 +01:00
2021-03-31 06:12:18 +00:00
if ( rx & & ! rx_setup_done ) {
2019-02-21 10:21:26 +01:00
err = setsockopt ( xsk - > fd , SOL_XDP , XDP_RX_RING ,
& xsk - > config . rx_size ,
sizeof ( xsk - > config . rx_size ) ) ;
if ( err ) {
err = - errno ;
2020-08-28 10:26:27 +02:00
goto out_put_ctx ;
2019-02-21 10:21:26 +01:00
}
2021-03-31 06:12:18 +00:00
if ( xsk - > fd = = umem - > fd )
umem - > rx_ring_setup_done = true ;
2019-02-21 10:21:26 +01:00
}
2021-03-31 06:12:18 +00:00
if ( tx & & ! tx_setup_done ) {
2019-02-21 10:21:26 +01:00
err = setsockopt ( xsk - > fd , SOL_XDP , XDP_TX_RING ,
& xsk - > config . tx_size ,
sizeof ( xsk - > config . tx_size ) ) ;
if ( err ) {
err = - errno ;
2020-08-28 10:26:27 +02:00
goto out_put_ctx ;
2019-02-21 10:21:26 +01:00
}
2021-03-31 06:12:18 +00:00
if ( xsk - > fd = = umem - > fd )
umem - > rx_ring_setup_done = true ;
2019-02-21 10:21:26 +01:00
}
2019-10-25 11:17:15 +02:00
err = xsk_get_mmap_offsets ( xsk - > fd , & off ) ;
2019-02-21 10:21:26 +01:00
if ( err ) {
err = - errno ;
2020-08-28 10:26:27 +02:00
goto out_put_ctx ;
2019-02-21 10:21:26 +01:00
}
if ( rx ) {
2019-08-15 15:13:54 +03:00
rx_map = mmap ( NULL , off . rx . desc +
xsk - > config . rx_size * sizeof ( struct xdp_desc ) ,
PROT_READ | PROT_WRITE , MAP_SHARED | MAP_POPULATE ,
xsk - > fd , XDP_PGOFF_RX_RING ) ;
2019-04-30 14:45:35 +02:00
if ( rx_map = = MAP_FAILED ) {
2019-02-21 10:21:26 +01:00
err = - errno ;
2020-08-28 10:26:27 +02:00
goto out_put_ctx ;
2019-02-21 10:21:26 +01:00
}
rx - > mask = xsk - > config . rx_size - 1 ;
rx - > size = xsk - > config . rx_size ;
2019-04-30 14:45:35 +02:00
rx - > producer = rx_map + off . rx . producer ;
rx - > consumer = rx_map + off . rx . consumer ;
2019-08-14 09:27:20 +02:00
rx - > flags = rx_map + off . rx . flags ;
2019-04-30 14:45:35 +02:00
rx - > ring = rx_map + off . rx . desc ;
2020-03-27 03:24:07 +00:00
rx - > cached_prod = * rx - > producer ;
rx - > cached_cons = * rx - > consumer ;
2019-02-21 10:21:26 +01:00
}
xsk - > rx = rx ;
if ( tx ) {
2019-08-15 15:13:54 +03:00
tx_map = mmap ( NULL , off . tx . desc +
xsk - > config . tx_size * sizeof ( struct xdp_desc ) ,
PROT_READ | PROT_WRITE , MAP_SHARED | MAP_POPULATE ,
xsk - > fd , XDP_PGOFF_TX_RING ) ;
2019-04-30 14:45:35 +02:00
if ( tx_map = = MAP_FAILED ) {
2019-02-21 10:21:26 +01:00
err = - errno ;
goto out_mmap_rx ;
}
tx - > mask = xsk - > config . tx_size - 1 ;
tx - > size = xsk - > config . tx_size ;
2019-04-30 14:45:35 +02:00
tx - > producer = tx_map + off . tx . producer ;
tx - > consumer = tx_map + off . tx . consumer ;
2019-08-14 09:27:20 +02:00
tx - > flags = tx_map + off . tx . flags ;
2019-04-30 14:45:35 +02:00
tx - > ring = tx_map + off . tx . desc ;
2020-03-27 03:24:07 +00:00
tx - > cached_prod = * tx - > producer ;
/* cached_cons is r->size bigger than the real consumer pointer
* See xsk_prod_nb_free
*/
tx - > cached_cons = * tx - > consumer + xsk - > config . tx_size ;
2019-02-21 10:21:26 +01:00
}
xsk - > tx = tx ;
sxdp . sxdp_family = PF_XDP ;
2020-08-28 10:26:27 +02:00
sxdp . sxdp_ifindex = ctx - > ifindex ;
sxdp . sxdp_queue_id = ctx - > queue_id ;
2019-11-07 18:47:36 +01:00
if ( umem - > refcount > 1 ) {
2020-08-28 10:26:27 +02:00
sxdp . sxdp_flags | = XDP_SHARED_UMEM ;
2019-11-07 18:47:36 +01:00
sxdp . sxdp_shared_umem_fd = umem - > fd ;
} else {
sxdp . sxdp_flags = xsk - > config . bind_flags ;
}
2019-02-21 10:21:26 +01:00
err = bind ( xsk - > fd , ( struct sockaddr * ) & sxdp , sizeof ( sxdp ) ) ;
if ( err ) {
err = - errno ;
goto out_mmap_tx ;
}
2020-08-28 10:26:27 +02:00
ctx - > prog_fd = - 1 ;
2019-06-26 17:35:26 +03:00
2019-02-21 10:21:26 +01:00
if ( ! ( xsk - > config . libbpf_flags & XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD ) ) {
2020-12-03 10:05:45 +01:00
err = __xsk_setup_xdp_prog ( xsk , NULL ) ;
2019-02-21 10:21:26 +01:00
if ( err )
goto out_mmap_tx ;
}
* xsk_ptr = xsk ;
2021-03-31 06:12:17 +00:00
umem - > fill_save = NULL ;
umem - > comp_save = NULL ;
2019-02-21 10:21:26 +01:00
return 0 ;
out_mmap_tx :
if ( tx )
2019-04-30 14:45:35 +02:00
munmap ( tx_map , off . tx . desc +
2019-02-21 10:21:26 +01:00
xsk - > config . tx_size * sizeof ( struct xdp_desc ) ) ;
out_mmap_rx :
if ( rx )
2019-04-30 14:45:35 +02:00
munmap ( rx_map , off . rx . desc +
2019-02-21 10:21:26 +01:00
xsk - > config . rx_size * sizeof ( struct xdp_desc ) ) ;
2020-08-28 10:26:27 +02:00
out_put_ctx :
2021-03-31 06:12:17 +00:00
xsk_put_ctx ( ctx , unmap ) ;
2019-02-21 10:21:26 +01:00
out_socket :
if ( - - umem - > refcount )
close ( xsk - > fd ) ;
out_xsk_alloc :
free ( xsk ) ;
return err ;
}
2020-08-28 10:26:27 +02:00
int xsk_socket__create ( struct xsk_socket * * xsk_ptr , const char * ifname ,
__u32 queue_id , struct xsk_umem * umem ,
struct xsk_ring_cons * rx , struct xsk_ring_prod * tx ,
const struct xsk_socket_config * usr_config )
2019-02-21 10:21:26 +01:00
{
2021-03-31 06:12:16 +00:00
if ( ! umem )
return - EFAULT ;
2020-08-28 10:26:27 +02:00
return xsk_socket__create_shared ( xsk_ptr , ifname , queue_id , umem ,
rx , tx , umem - > fill_save ,
umem - > comp_save , usr_config ) ;
}
2019-02-21 10:21:26 +01:00
2020-08-28 10:26:27 +02:00
int xsk_umem__delete ( struct xsk_umem * umem )
{
2019-02-21 10:21:26 +01:00
if ( ! umem )
return 0 ;
if ( umem - > refcount )
return - EBUSY ;
close ( umem - > fd ) ;
free ( umem ) ;
return 0 ;
}
void xsk_socket__delete ( struct xsk_socket * xsk )
{
2019-04-30 14:45:35 +02:00
size_t desc_sz = sizeof ( struct xdp_desc ) ;
2019-02-21 10:21:26 +01:00
struct xdp_mmap_offsets off ;
2020-11-03 10:41:30 +01:00
struct xsk_umem * umem ;
2020-11-03 10:41:29 +01:00
struct xsk_ctx * ctx ;
2019-02-21 10:21:26 +01:00
int err ;
if ( ! xsk )
return ;
2020-11-03 10:41:29 +01:00
ctx = xsk - > ctx ;
2020-11-03 10:41:30 +01:00
umem = ctx - > umem ;
2020-08-28 10:26:27 +02:00
if ( ctx - > prog_fd ! = - 1 ) {
2019-06-06 13:59:43 -07:00
xsk_delete_bpf_maps ( xsk ) ;
2020-08-28 10:26:27 +02:00
close ( ctx - > prog_fd ) ;
2019-06-06 13:59:43 -07:00
}
2019-02-21 10:21:26 +01:00
2019-10-25 11:17:15 +02:00
err = xsk_get_mmap_offsets ( xsk - > fd , & off ) ;
2019-02-21 10:21:26 +01:00
if ( ! err ) {
2019-04-30 14:45:35 +02:00
if ( xsk - > rx ) {
2019-05-06 11:24:43 +02:00
munmap ( xsk - > rx - > ring - off . rx . desc ,
off . rx . desc + xsk - > config . rx_size * desc_sz ) ;
2019-04-30 14:45:35 +02:00
}
if ( xsk - > tx ) {
2019-05-06 11:24:43 +02:00
munmap ( xsk - > tx - > ring - off . tx . desc ,
off . tx . desc + xsk - > config . tx_size * desc_sz ) ;
2019-04-30 14:45:35 +02:00
}
2019-02-21 10:21:26 +01:00
}
2021-03-31 06:12:17 +00:00
xsk_put_ctx ( ctx , true ) ;
2020-08-28 10:26:27 +02:00
2020-11-03 10:41:30 +01:00
umem - > refcount - - ;
2019-02-21 10:21:26 +01:00
/* Do not close an fd that also has an associated umem connected
* to it .
*/
2020-11-03 10:41:30 +01:00
if ( xsk - > fd ! = umem - > fd )
2019-02-21 10:21:26 +01:00
close ( xsk - > fd ) ;
free ( xsk ) ;
}