2020-12-03 10:05:46 +01:00
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2017 - 2018 Intel Corporation. */
# include <errno.h>
# include <getopt.h>
# include <libgen.h>
# include <net/if.h>
# include <stdio.h>
# include <stdlib.h>
# include <sys/socket.h>
# include <sys/un.h>
# include <unistd.h>
# include <bpf/bpf.h>
# include <bpf/xsk.h>
# include "xdpsock.h"
2021-12-01 15:28:23 -08:00
/* libbpf APIs for AF_XDP are deprecated starting from v0.7 */
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
2020-12-03 10:05:46 +01:00
static const char * opt_if = " " ;
static struct option long_options [ ] = {
{ " interface " , required_argument , 0 , ' i ' } ,
{ 0 , 0 , 0 , 0 }
} ;
static void usage ( const char * prog )
{
const char * str =
" Usage: %s [OPTIONS] \n "
" Options: \n "
" -i, --interface=n Run on interface n \n "
" \n " ;
fprintf ( stderr , " %s \n " , str ) ;
exit ( 0 ) ;
}
static void parse_command_line ( int argc , char * * argv )
{
int option_index , c ;
opterr = 0 ;
for ( ; ; ) {
c = getopt_long ( argc , argv , " i: " ,
long_options , & option_index ) ;
if ( c = = - 1 )
break ;
switch ( c ) {
case ' i ' :
opt_if = optarg ;
break ;
default :
usage ( basename ( argv [ 0 ] ) ) ;
}
}
}
static int send_xsks_map_fd ( int sock , int fd )
{
char cmsgbuf [ CMSG_SPACE ( sizeof ( int ) ) ] ;
struct msghdr msg ;
struct iovec iov ;
int value = 0 ;
if ( fd = = - 1 ) {
fprintf ( stderr , " Incorrect fd = %d \n " , fd ) ;
return - 1 ;
}
iov . iov_base = & value ;
iov . iov_len = sizeof ( int ) ;
msg . msg_name = NULL ;
msg . msg_namelen = 0 ;
msg . msg_iov = & iov ;
msg . msg_iovlen = 1 ;
msg . msg_flags = 0 ;
msg . msg_control = cmsgbuf ;
msg . msg_controllen = CMSG_LEN ( sizeof ( int ) ) ;
struct cmsghdr * cmsg = CMSG_FIRSTHDR ( & msg ) ;
cmsg - > cmsg_level = SOL_SOCKET ;
cmsg - > cmsg_type = SCM_RIGHTS ;
cmsg - > cmsg_len = CMSG_LEN ( sizeof ( int ) ) ;
* ( int * ) CMSG_DATA ( cmsg ) = fd ;
int ret = sendmsg ( sock , & msg , 0 ) ;
if ( ret = = - 1 ) {
fprintf ( stderr , " Sendmsg failed with %s " , strerror ( errno ) ) ;
return - errno ;
}
return ret ;
}
int
main ( int argc , char * * argv )
{
struct sockaddr_un server ;
int listening = 1 ;
int rval , msgsock ;
int ifindex = 0 ;
int flag = 1 ;
int cmd = 0 ;
int sock ;
int err ;
int xsks_map_fd ;
parse_command_line ( argc , argv ) ;
ifindex = if_nametoindex ( opt_if ) ;
if ( ifindex = = 0 ) {
fprintf ( stderr , " Unable to get ifindex for Interface %s. Reason:%s " ,
opt_if , strerror ( errno ) ) ;
return - errno ;
}
sock = socket ( AF_UNIX , SOCK_STREAM , 0 ) ;
if ( sock < 0 ) {
fprintf ( stderr , " Opening socket stream failed: %s " , strerror ( errno ) ) ;
return - errno ;
}
server . sun_family = AF_UNIX ;
strcpy ( server . sun_path , SOCKET_NAME ) ;
setsockopt ( sock , SOL_SOCKET , SO_REUSEADDR , & flag , sizeof ( int ) ) ;
if ( bind ( sock , ( struct sockaddr * ) & server , sizeof ( struct sockaddr_un ) ) ) {
fprintf ( stderr , " Binding to socket stream failed: %s " , strerror ( errno ) ) ;
return - errno ;
}
listen ( sock , MAX_NUM_OF_CLIENTS ) ;
err = xsk_setup_xdp_prog ( ifindex , & xsks_map_fd ) ;
if ( err ) {
fprintf ( stderr , " Setup of xdp program failed \n " ) ;
goto close_sock ;
}
while ( listening ) {
msgsock = accept ( sock , 0 , 0 ) ;
if ( msgsock = = - 1 ) {
fprintf ( stderr , " Error accepting connection: %s " , strerror ( errno ) ) ;
err = - errno ;
goto close_sock ;
}
err = send_xsks_map_fd ( msgsock , xsks_map_fd ) ;
if ( err < = 0 ) {
fprintf ( stderr , " Error %d sending xsks_map_fd \n " , err ) ;
goto cleanup ;
}
do {
rval = read ( msgsock , & cmd , sizeof ( int ) ) ;
if ( rval < 0 ) {
fprintf ( stderr , " Error reading stream message " ) ;
} else {
if ( cmd ! = CLOSE_CONN )
fprintf ( stderr , " Recv unknown cmd = %d \n " , cmd ) ;
listening = 0 ;
break ;
}
} while ( rval > 0 ) ;
}
close ( msgsock ) ;
close ( sock ) ;
unlink ( SOCKET_NAME ) ;
/* Unset fd for given ifindex */
2022-01-19 22:14:22 -08:00
err = bpf_xdp_detach ( ifindex , 0 , NULL ) ;
2020-12-03 10:05:46 +01:00
if ( err ) {
fprintf ( stderr , " Error when unsetting bpf prog_fd for ifindex(%d) \n " , ifindex ) ;
return err ;
}
return 0 ;
cleanup :
close ( msgsock ) ;
close_sock :
close ( sock ) ;
unlink ( SOCKET_NAME ) ;
return err ;
}