2019-05-28 20:10:09 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2017-11-05 06:22:30 +03:00
/* Copyright (C) 2017 Cavium, Inc.
*/
# include <linux/bpf.h>
# include <linux/netlink.h>
# include <linux/rtnetlink.h>
# include <assert.h>
# include <errno.h>
# include <signal.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/socket.h>
# include <unistd.h>
2018-05-15 08:35:02 +03:00
# include <bpf/bpf.h>
2017-11-05 06:22:30 +03:00
# include <arpa/inet.h>
# include <fcntl.h>
# include <poll.h>
# include <net/if.h>
# include <netdb.h>
# include <sys/ioctl.h>
# include <sys/syscall.h>
# include "bpf_util.h"
2020-01-20 16:06:49 +03:00
# include <bpf/libbpf.h>
2019-02-02 00:42:28 +03:00
# include <libgen.h>
2022-03-16 10:13:23 +03:00
# include <getopt.h>
2022-04-05 17:15:14 +03:00
# include <pthread.h>
2022-03-16 10:13:23 +03:00
# include "xdp_sample_user.h"
# include "xdp_router_ipv4.skel.h"
2017-11-05 06:22:30 +03:00
2022-03-16 10:13:23 +03:00
static const char * __doc__ =
" XDP IPv4 router implementation \n "
" Usage: xdp_router_ipv4 <IFNAME-0> ... <IFNAME-N> \n " ;
static char buf [ 8192 ] ;
2019-02-02 00:42:25 +03:00
static int lpm_map_fd ;
static int arp_table_map_fd ;
static int exact_match_map_fd ;
static int tx_port_map_fd ;
2017-11-05 06:22:30 +03:00
2022-04-05 17:15:14 +03:00
static bool routes_thread_exit ;
static int interval = 5 ;
2022-03-16 10:13:23 +03:00
static int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_MAP_CNT |
SAMPLE_DEVMAP_XMIT_CNT_MULTI | SAMPLE_EXCEPTION_CNT ;
2017-11-05 06:22:30 +03:00
2022-03-16 10:13:23 +03:00
DEFINE_SAMPLE_INIT ( xdp_router_ipv4 ) ;
2017-11-05 06:22:30 +03:00
2022-03-16 10:13:23 +03:00
static const struct option long_options [ ] = {
{ " help " , no_argument , NULL , ' h ' } ,
{ " skb-mode " , no_argument , NULL , ' S ' } ,
{ " force " , no_argument , NULL , ' F ' } ,
{ " interval " , required_argument , NULL , ' i ' } ,
{ " verbose " , no_argument , NULL , ' v ' } ,
{ " stats " , no_argument , NULL , ' s ' } ,
{ }
} ;
2017-11-05 06:22:30 +03:00
2022-03-16 10:13:23 +03:00
static int get_route_table ( int rtm_family ) ;
2017-11-05 06:22:30 +03:00
static int recv_msg ( struct sockaddr_nl sock_addr , int sock )
{
struct nlmsghdr * nh ;
int len , nll = 0 ;
char * buf_ptr ;
buf_ptr = buf ;
while ( 1 ) {
len = recv ( sock , buf_ptr , sizeof ( buf ) - nll , 0 ) ;
if ( len < 0 )
return len ;
nh = ( struct nlmsghdr * ) buf_ptr ;
if ( nh - > nlmsg_type = = NLMSG_DONE )
break ;
buf_ptr + = len ;
nll + = len ;
if ( ( sock_addr . nl_groups & RTMGRP_NEIGH ) = = RTMGRP_NEIGH )
break ;
if ( ( sock_addr . nl_groups & RTMGRP_IPV4_ROUTE ) = = RTMGRP_IPV4_ROUTE )
break ;
}
return nll ;
}
/* Function to parse the route entry returned by netlink
* Updates the route entry related map entries
*/
static void read_route ( struct nlmsghdr * nh , int nll )
{
char dsts [ 24 ] , gws [ 24 ] , ifs [ 16 ] , dsts_len [ 24 ] , metrics [ 24 ] ;
struct bpf_lpm_trie_key * prefix_key ;
struct rtattr * rt_attr ;
struct rtmsg * rt_msg ;
int rtm_family ;
int rtl ;
int i ;
struct route_table {
int dst_len , iface , metric ;
__be32 dst , gw ;
__be64 mac ;
} route ;
struct arp_table {
__be64 mac ;
__be32 dst ;
} ;
struct direct_map {
struct arp_table arp ;
int ifindex ;
__be64 mac ;
} direct_entry ;
memset ( & route , 0 , sizeof ( route ) ) ;
for ( ; NLMSG_OK ( nh , nll ) ; nh = NLMSG_NEXT ( nh , nll ) ) {
rt_msg = ( struct rtmsg * ) NLMSG_DATA ( nh ) ;
rtm_family = rt_msg - > rtm_family ;
if ( rtm_family = = AF_INET )
if ( rt_msg - > rtm_table ! = RT_TABLE_MAIN )
continue ;
rt_attr = ( struct rtattr * ) RTM_RTA ( rt_msg ) ;
rtl = RTM_PAYLOAD ( nh ) ;
for ( ; RTA_OK ( rt_attr , rtl ) ; rt_attr = RTA_NEXT ( rt_attr , rtl ) ) {
switch ( rt_attr - > rta_type ) {
case NDA_DST :
sprintf ( dsts , " %u " ,
( * ( ( __be32 * ) RTA_DATA ( rt_attr ) ) ) ) ;
break ;
case RTA_GATEWAY :
sprintf ( gws , " %u " ,
* ( ( __be32 * ) RTA_DATA ( rt_attr ) ) ) ;
break ;
case RTA_OIF :
sprintf ( ifs , " %u " ,
* ( ( int * ) RTA_DATA ( rt_attr ) ) ) ;
break ;
case RTA_METRICS :
sprintf ( metrics , " %u " ,
* ( ( int * ) RTA_DATA ( rt_attr ) ) ) ;
default :
break ;
}
}
sprintf ( dsts_len , " %d " , rt_msg - > rtm_dst_len ) ;
route . dst = atoi ( dsts ) ;
route . dst_len = atoi ( dsts_len ) ;
route . gw = atoi ( gws ) ;
route . iface = atoi ( ifs ) ;
route . metric = atoi ( metrics ) ;
2022-03-16 10:13:23 +03:00
assert ( get_mac_addr ( route . iface , & route . mac ) = = 0 ) ;
2019-02-02 00:42:25 +03:00
assert ( bpf_map_update_elem ( tx_port_map_fd ,
& route . iface , & route . iface , 0 ) = = 0 ) ;
2017-11-05 06:22:30 +03:00
if ( rtm_family = = AF_INET ) {
struct trie_value {
__u8 prefix [ 4 ] ;
__be64 value ;
int ifindex ;
int metric ;
__be32 gw ;
} * prefix_value ;
2022-11-22 05:32:56 +03:00
prefix_key = alloca ( sizeof ( * prefix_key ) + 4 ) ;
2017-11-05 06:22:30 +03:00
prefix_value = alloca ( sizeof ( * prefix_value ) ) ;
prefix_key - > prefixlen = 32 ;
prefix_key - > prefixlen = route . dst_len ;
direct_entry . mac = route . mac & 0xffffffffffff ;
direct_entry . ifindex = route . iface ;
direct_entry . arp . mac = 0 ;
direct_entry . arp . dst = 0 ;
if ( route . dst_len = = 32 ) {
2017-11-14 09:12:03 +03:00
if ( nh - > nlmsg_type = = RTM_DELROUTE ) {
2019-02-02 00:42:25 +03:00
assert ( bpf_map_delete_elem ( exact_match_map_fd ,
& route . dst ) = = 0 ) ;
2017-11-14 09:12:03 +03:00
} else {
2019-02-02 00:42:25 +03:00
if ( bpf_map_lookup_elem ( arp_table_map_fd ,
& route . dst ,
& direct_entry . arp . mac ) = = 0 )
2017-11-05 06:22:30 +03:00
direct_entry . arp . dst = route . dst ;
2019-02-02 00:42:25 +03:00
assert ( bpf_map_update_elem ( exact_match_map_fd ,
& route . dst ,
& direct_entry , 0 ) = = 0 ) ;
2017-11-14 09:12:03 +03:00
}
2017-11-05 06:22:30 +03:00
}
for ( i = 0 ; i < 4 ; i + + )
prefix_key - > data [ i ] = ( route . dst > > i * 8 ) & 0xff ;
2019-02-02 00:42:25 +03:00
if ( bpf_map_lookup_elem ( lpm_map_fd , prefix_key ,
2017-11-05 06:22:30 +03:00
prefix_value ) < 0 ) {
for ( i = 0 ; i < 4 ; i + + )
prefix_value - > prefix [ i ] = prefix_key - > data [ i ] ;
prefix_value - > value = route . mac & 0xffffffffffff ;
prefix_value - > ifindex = route . iface ;
prefix_value - > gw = route . gw ;
prefix_value - > metric = route . metric ;
2019-02-02 00:42:25 +03:00
assert ( bpf_map_update_elem ( lpm_map_fd ,
2017-11-05 06:22:30 +03:00
prefix_key ,
prefix_value , 0
) = = 0 ) ;
} else {
if ( nh - > nlmsg_type = = RTM_DELROUTE ) {
2019-02-02 00:42:25 +03:00
assert ( bpf_map_delete_elem ( lpm_map_fd ,
2017-11-05 06:22:30 +03:00
prefix_key
) = = 0 ) ;
/* Rereading the route table to check if
* there is an entry with the same
* prefix but a different metric as the
2022-09-27 22:25:27 +03:00
* deleted entry .
2017-11-05 06:22:30 +03:00
*/
get_route_table ( AF_INET ) ;
} else if ( prefix_key - > data [ 0 ] = =
prefix_value - > prefix [ 0 ] & &
prefix_key - > data [ 1 ] = =
prefix_value - > prefix [ 1 ] & &
prefix_key - > data [ 2 ] = =
prefix_value - > prefix [ 2 ] & &
prefix_key - > data [ 3 ] = =
prefix_value - > prefix [ 3 ] & &
route . metric > = prefix_value - > metric ) {
continue ;
} else {
for ( i = 0 ; i < 4 ; i + + )
prefix_value - > prefix [ i ] =
prefix_key - > data [ i ] ;
prefix_value - > value =
route . mac & 0xffffffffffff ;
prefix_value - > ifindex = route . iface ;
prefix_value - > gw = route . gw ;
prefix_value - > metric = route . metric ;
2019-02-02 00:42:25 +03:00
assert ( bpf_map_update_elem ( lpm_map_fd ,
2017-11-05 06:22:30 +03:00
prefix_key ,
prefix_value ,
0 ) = = 0 ) ;
}
}
}
memset ( & route , 0 , sizeof ( route ) ) ;
memset ( dsts , 0 , sizeof ( dsts ) ) ;
memset ( dsts_len , 0 , sizeof ( dsts_len ) ) ;
memset ( gws , 0 , sizeof ( gws ) ) ;
memset ( ifs , 0 , sizeof ( ifs ) ) ;
memset ( & route , 0 , sizeof ( route ) ) ;
}
}
/* Function to read the existing route table when the process is launched*/
static int get_route_table ( int rtm_family )
{
struct sockaddr_nl sa ;
struct nlmsghdr * nh ;
int sock , seq = 0 ;
struct msghdr msg ;
struct iovec iov ;
int ret = 0 ;
int nll ;
struct {
struct nlmsghdr nl ;
struct rtmsg rt ;
char buf [ 8192 ] ;
} req ;
sock = socket ( AF_NETLINK , SOCK_RAW , NETLINK_ROUTE ) ;
if ( sock < 0 ) {
2022-03-16 10:13:23 +03:00
fprintf ( stderr , " open netlink socket: %s \n " , strerror ( errno ) ) ;
return - errno ;
2017-11-05 06:22:30 +03:00
}
memset ( & sa , 0 , sizeof ( sa ) ) ;
sa . nl_family = AF_NETLINK ;
if ( bind ( sock , ( struct sockaddr * ) & sa , sizeof ( sa ) ) < 0 ) {
2022-03-16 10:13:23 +03:00
fprintf ( stderr , " bind netlink socket: %s \n " , strerror ( errno ) ) ;
ret = - errno ;
2017-11-05 06:22:30 +03:00
goto cleanup ;
}
memset ( & req , 0 , sizeof ( req ) ) ;
req . nl . nlmsg_len = NLMSG_LENGTH ( sizeof ( struct rtmsg ) ) ;
req . nl . nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP ;
req . nl . nlmsg_type = RTM_GETROUTE ;
req . rt . rtm_family = rtm_family ;
req . rt . rtm_table = RT_TABLE_MAIN ;
req . nl . nlmsg_pid = 0 ;
req . nl . nlmsg_seq = + + seq ;
memset ( & msg , 0 , sizeof ( msg ) ) ;
iov . iov_base = ( void * ) & req . nl ;
iov . iov_len = req . nl . nlmsg_len ;
msg . msg_iov = & iov ;
msg . msg_iovlen = 1 ;
ret = sendmsg ( sock , & msg , 0 ) ;
if ( ret < 0 ) {
2022-03-16 10:13:23 +03:00
fprintf ( stderr , " send to netlink: %s \n " , strerror ( errno ) ) ;
ret = - errno ;
2017-11-05 06:22:30 +03:00
goto cleanup ;
}
memset ( buf , 0 , sizeof ( buf ) ) ;
nll = recv_msg ( sa , sock ) ;
if ( nll < 0 ) {
2022-03-16 10:13:23 +03:00
fprintf ( stderr , " recv from netlink: %s \n " , strerror ( nll ) ) ;
ret = nll ;
2017-11-05 06:22:30 +03:00
goto cleanup ;
}
nh = ( struct nlmsghdr * ) buf ;
read_route ( nh , nll ) ;
cleanup :
close ( sock ) ;
return ret ;
}
/* Function to parse the arp entry returned by netlink
* Updates the arp entry related map entries
*/
static void read_arp ( struct nlmsghdr * nh , int nll )
{
struct rtattr * rt_attr ;
char dsts [ 24 ] , mac [ 24 ] ;
struct ndmsg * rt_msg ;
int rtl , ndm_family ;
struct arp_table {
__be64 mac ;
__be32 dst ;
} arp_entry ;
struct direct_map {
struct arp_table arp ;
int ifindex ;
__be64 mac ;
} direct_entry ;
for ( ; NLMSG_OK ( nh , nll ) ; nh = NLMSG_NEXT ( nh , nll ) ) {
rt_msg = ( struct ndmsg * ) NLMSG_DATA ( nh ) ;
rt_attr = ( struct rtattr * ) RTM_RTA ( rt_msg ) ;
ndm_family = rt_msg - > ndm_family ;
rtl = RTM_PAYLOAD ( nh ) ;
for ( ; RTA_OK ( rt_attr , rtl ) ; rt_attr = RTA_NEXT ( rt_attr , rtl ) ) {
switch ( rt_attr - > rta_type ) {
case NDA_DST :
sprintf ( dsts , " %u " ,
* ( ( __be32 * ) RTA_DATA ( rt_attr ) ) ) ;
break ;
case NDA_LLADDR :
sprintf ( mac , " %lld " ,
* ( ( __be64 * ) RTA_DATA ( rt_attr ) ) ) ;
break ;
default :
break ;
}
}
arp_entry . dst = atoi ( dsts ) ;
arp_entry . mac = atol ( mac ) ;
2021-09-19 11:03:05 +03:00
2017-11-05 06:22:30 +03:00
if ( ndm_family = = AF_INET ) {
2019-02-02 00:42:25 +03:00
if ( bpf_map_lookup_elem ( exact_match_map_fd ,
& arp_entry . dst ,
2017-11-05 06:22:30 +03:00
& direct_entry ) = = 0 ) {
if ( nh - > nlmsg_type = = RTM_DELNEIGH ) {
direct_entry . arp . dst = 0 ;
direct_entry . arp . mac = 0 ;
} else if ( nh - > nlmsg_type = = RTM_NEWNEIGH ) {
direct_entry . arp . dst = arp_entry . dst ;
direct_entry . arp . mac = arp_entry . mac ;
}
2019-02-02 00:42:25 +03:00
assert ( bpf_map_update_elem ( exact_match_map_fd ,
2017-11-05 06:22:30 +03:00
& arp_entry . dst ,
& direct_entry , 0
) = = 0 ) ;
memset ( & direct_entry , 0 , sizeof ( direct_entry ) ) ;
}
if ( nh - > nlmsg_type = = RTM_DELNEIGH ) {
2019-02-02 00:42:25 +03:00
assert ( bpf_map_delete_elem ( arp_table_map_fd ,
& arp_entry . dst ) = = 0 ) ;
2017-11-05 06:22:30 +03:00
} else if ( nh - > nlmsg_type = = RTM_NEWNEIGH ) {
2019-02-02 00:42:25 +03:00
assert ( bpf_map_update_elem ( arp_table_map_fd ,
2017-11-05 06:22:30 +03:00
& arp_entry . dst ,
& arp_entry . mac , 0
) = = 0 ) ;
}
}
memset ( & arp_entry , 0 , sizeof ( arp_entry ) ) ;
memset ( dsts , 0 , sizeof ( dsts ) ) ;
}
}
/* Function to read the existing arp table when the process is launched*/
static int get_arp_table ( int rtm_family )
{
struct sockaddr_nl sa ;
struct nlmsghdr * nh ;
int sock , seq = 0 ;
struct msghdr msg ;
struct iovec iov ;
int ret = 0 ;
int nll ;
struct {
struct nlmsghdr nl ;
struct ndmsg rt ;
char buf [ 8192 ] ;
} req ;
sock = socket ( AF_NETLINK , SOCK_RAW , NETLINK_ROUTE ) ;
if ( sock < 0 ) {
2022-03-16 10:13:23 +03:00
fprintf ( stderr , " open netlink socket: %s \n " , strerror ( errno ) ) ;
return - errno ;
2017-11-05 06:22:30 +03:00
}
memset ( & sa , 0 , sizeof ( sa ) ) ;
sa . nl_family = AF_NETLINK ;
if ( bind ( sock , ( struct sockaddr * ) & sa , sizeof ( sa ) ) < 0 ) {
2022-03-16 10:13:23 +03:00
fprintf ( stderr , " bind netlink socket: %s \n " , strerror ( errno ) ) ;
ret = - errno ;
2017-11-05 06:22:30 +03:00
goto cleanup ;
}
memset ( & req , 0 , sizeof ( req ) ) ;
req . nl . nlmsg_len = NLMSG_LENGTH ( sizeof ( struct rtmsg ) ) ;
req . nl . nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP ;
req . nl . nlmsg_type = RTM_GETNEIGH ;
req . rt . ndm_state = NUD_REACHABLE ;
req . rt . ndm_family = rtm_family ;
req . nl . nlmsg_pid = 0 ;
req . nl . nlmsg_seq = + + seq ;
memset ( & msg , 0 , sizeof ( msg ) ) ;
iov . iov_base = ( void * ) & req . nl ;
iov . iov_len = req . nl . nlmsg_len ;
msg . msg_iov = & iov ;
msg . msg_iovlen = 1 ;
ret = sendmsg ( sock , & msg , 0 ) ;
if ( ret < 0 ) {
2022-03-16 10:13:23 +03:00
fprintf ( stderr , " send to netlink: %s \n " , strerror ( errno ) ) ;
ret = - errno ;
2017-11-05 06:22:30 +03:00
goto cleanup ;
}
memset ( buf , 0 , sizeof ( buf ) ) ;
nll = recv_msg ( sa , sock ) ;
if ( nll < 0 ) {
2022-03-16 10:13:23 +03:00
fprintf ( stderr , " recv from netlink: %s \n " , strerror ( nll ) ) ;
ret = nll ;
2017-11-05 06:22:30 +03:00
goto cleanup ;
}
nh = ( struct nlmsghdr * ) buf ;
read_arp ( nh , nll ) ;
cleanup :
close ( sock ) ;
return ret ;
}
/* Function to keep track and update changes in route and arp table
* Give regular statistics of packets forwarded
*/
2022-04-05 17:15:14 +03:00
static void * monitor_routes_thread ( void * arg )
2017-11-05 06:22:30 +03:00
{
struct pollfd fds_route , fds_arp ;
struct sockaddr_nl la , lr ;
2022-03-16 10:13:23 +03:00
int sock , sock_arp , nll ;
2017-11-05 06:22:30 +03:00
struct nlmsghdr * nh ;
sock = socket ( AF_NETLINK , SOCK_RAW , NETLINK_ROUTE ) ;
if ( sock < 0 ) {
2022-03-16 10:13:23 +03:00
fprintf ( stderr , " open netlink socket: %s \n " , strerror ( errno ) ) ;
2022-04-05 17:15:14 +03:00
return NULL ;
2017-11-05 06:22:30 +03:00
}
fcntl ( sock , F_SETFL , O_NONBLOCK ) ;
memset ( & lr , 0 , sizeof ( lr ) ) ;
lr . nl_family = AF_NETLINK ;
lr . nl_groups = RTMGRP_IPV6_ROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_NOTIFY ;
if ( bind ( sock , ( struct sockaddr * ) & lr , sizeof ( lr ) ) < 0 ) {
2022-03-16 10:13:23 +03:00
fprintf ( stderr , " bind netlink socket: %s \n " , strerror ( errno ) ) ;
close ( sock ) ;
2022-04-05 17:15:14 +03:00
return NULL ;
2017-11-05 06:22:30 +03:00
}
2022-03-16 10:13:23 +03:00
2017-11-05 06:22:30 +03:00
fds_route . fd = sock ;
fds_route . events = POLL_IN ;
sock_arp = socket ( AF_NETLINK , SOCK_RAW , NETLINK_ROUTE ) ;
if ( sock_arp < 0 ) {
2022-03-16 10:13:23 +03:00
fprintf ( stderr , " open netlink socket: %s \n " , strerror ( errno ) ) ;
close ( sock ) ;
2022-04-05 17:15:14 +03:00
return NULL ;
2017-11-05 06:22:30 +03:00
}
fcntl ( sock_arp , F_SETFL , O_NONBLOCK ) ;
memset ( & la , 0 , sizeof ( la ) ) ;
la . nl_family = AF_NETLINK ;
la . nl_groups = RTMGRP_NEIGH | RTMGRP_NOTIFY ;
if ( bind ( sock_arp , ( struct sockaddr * ) & la , sizeof ( la ) ) < 0 ) {
2022-03-16 10:13:23 +03:00
fprintf ( stderr , " bind netlink socket: %s \n " , strerror ( errno ) ) ;
2017-11-05 06:22:30 +03:00
goto cleanup ;
}
2022-03-16 10:13:23 +03:00
2017-11-05 06:22:30 +03:00
fds_arp . fd = sock_arp ;
fds_arp . events = POLL_IN ;
2022-04-05 17:15:14 +03:00
/* dump route and arp tables */
if ( get_arp_table ( AF_INET ) < 0 ) {
fprintf ( stderr , " Failed reading arp table \n " ) ;
goto cleanup ;
}
2017-11-05 06:22:30 +03:00
2022-04-05 17:15:14 +03:00
if ( get_route_table ( AF_INET ) < 0 ) {
fprintf ( stderr , " Failed reading route table \n " ) ;
goto cleanup ;
2022-03-16 10:13:23 +03:00
}
2017-11-05 06:22:30 +03:00
2022-04-05 17:15:14 +03:00
while ( ! routes_thread_exit ) {
memset ( buf , 0 , sizeof ( buf ) ) ;
if ( poll ( & fds_route , 1 , 3 ) = = POLL_IN ) {
nll = recv_msg ( lr , sock ) ;
if ( nll < 0 ) {
fprintf ( stderr , " recv from netlink: %s \n " ,
strerror ( nll ) ) ;
goto cleanup ;
}
nh = ( struct nlmsghdr * ) buf ;
read_route ( nh , nll ) ;
2017-11-05 06:22:30 +03:00
}
2022-04-05 17:15:14 +03:00
memset ( buf , 0 , sizeof ( buf ) ) ;
if ( poll ( & fds_arp , 1 , 3 ) = = POLL_IN ) {
nll = recv_msg ( la , sock_arp ) ;
if ( nll < 0 ) {
fprintf ( stderr , " recv from netlink: %s \n " ,
strerror ( nll ) ) ;
goto cleanup ;
}
nh = ( struct nlmsghdr * ) buf ;
read_arp ( nh , nll ) ;
}
sleep ( interval ) ;
2022-03-16 10:13:23 +03:00
}
2017-11-05 06:22:30 +03:00
cleanup :
2022-03-16 10:13:23 +03:00
close ( sock_arp ) ;
2017-11-05 06:22:30 +03:00
close ( sock ) ;
2022-04-05 17:15:14 +03:00
return NULL ;
2017-11-05 06:22:30 +03:00
}
2022-03-16 10:13:23 +03:00
static void usage ( char * argv [ ] , const struct option * long_options ,
const char * doc , int mask , bool error ,
struct bpf_object * obj )
2019-02-02 00:42:28 +03:00
{
2022-03-16 10:13:23 +03:00
sample_usage ( argv , long_options , doc , mask , error ) ;
2019-02-02 00:42:28 +03:00
}
2022-03-16 10:13:23 +03:00
int main ( int argc , char * * argv )
2017-11-05 06:22:30 +03:00
{
2022-03-16 10:13:23 +03:00
bool error = true , generic = false , force = false ;
2022-04-05 17:15:14 +03:00
int opt , ret = EXIT_FAIL_BPF ;
2022-03-16 10:13:23 +03:00
struct xdp_router_ipv4 * skel ;
int i , total_ifindex = argc - 1 ;
char * * ifname_list = argv + 1 ;
2022-04-05 17:15:14 +03:00
pthread_t routes_thread ;
2022-03-16 10:13:23 +03:00
int longindex = 0 ;
if ( libbpf_set_strict_mode ( LIBBPF_STRICT_ALL ) < 0 ) {
fprintf ( stderr , " Failed to set libbpf strict mode: %s \n " ,
strerror ( errno ) ) ;
goto end ;
}
skel = xdp_router_ipv4__open ( ) ;
if ( ! skel ) {
fprintf ( stderr , " Failed to xdp_router_ipv4__open: %s \n " ,
strerror ( errno ) ) ;
goto end ;
}
ret = sample_init_pre_load ( skel ) ;
if ( ret < 0 ) {
fprintf ( stderr , " Failed to sample_init_pre_load: %s \n " ,
strerror ( - ret ) ) ;
ret = EXIT_FAIL_BPF ;
goto end_destroy ;
}
ret = xdp_router_ipv4__load ( skel ) ;
if ( ret < 0 ) {
fprintf ( stderr , " Failed to xdp_router_ipv4__load: %s \n " ,
strerror ( errno ) ) ;
goto end_destroy ;
}
ret = sample_init ( skel , mask ) ;
if ( ret < 0 ) {
fprintf ( stderr , " Failed to initialize sample: %s \n " , strerror ( - ret ) ) ;
ret = EXIT_FAIL ;
goto end_destroy ;
}
while ( ( opt = getopt_long ( argc , argv , " si:SFvh " ,
long_options , & longindex ) ) ! = - 1 ) {
2019-02-02 00:42:28 +03:00
switch ( opt ) {
2022-03-16 10:13:23 +03:00
case ' s ' :
mask | = SAMPLE_REDIRECT_MAP_CNT ;
total_ifindex - - ;
ifname_list + + ;
break ;
case ' i ' :
interval = strtoul ( optarg , NULL , 0 ) ;
total_ifindex - = 2 ;
ifname_list + = 2 ;
break ;
2019-02-02 00:42:28 +03:00
case ' S ' :
2022-03-16 10:13:23 +03:00
generic = true ;
2019-02-02 00:42:28 +03:00
total_ifindex - - ;
ifname_list + + ;
break ;
case ' F ' :
2022-03-16 10:13:23 +03:00
force = true ;
total_ifindex - - ;
ifname_list + + ;
break ;
case ' v ' :
sample_switch_mode ( ) ;
2019-02-02 00:42:28 +03:00
total_ifindex - - ;
ifname_list + + ;
break ;
2022-03-16 10:13:23 +03:00
case ' h ' :
error = false ;
2019-02-02 00:42:28 +03:00
default :
2022-03-16 10:13:23 +03:00
usage ( argv , long_options , __doc__ , mask , error , skel - > obj ) ;
goto end_destroy ;
2019-02-02 00:42:28 +03:00
}
2017-11-05 06:22:30 +03:00
}
2019-02-02 00:42:28 +03:00
2022-03-16 10:13:23 +03:00
ret = EXIT_FAIL_OPTION ;
if ( optind = = argc ) {
usage ( argv , long_options , __doc__ , mask , true , skel - > obj ) ;
goto end_destroy ;
2017-11-05 06:22:30 +03:00
}
2019-02-02 00:42:25 +03:00
2022-03-16 10:13:23 +03:00
lpm_map_fd = bpf_map__fd ( skel - > maps . lpm_map ) ;
if ( lpm_map_fd < 0 ) {
fprintf ( stderr , " Failed loading lpm_map %s \n " ,
strerror ( - lpm_map_fd ) ) ;
goto end_destroy ;
2017-11-05 06:22:30 +03:00
}
2022-03-16 10:13:23 +03:00
arp_table_map_fd = bpf_map__fd ( skel - > maps . arp_table ) ;
if ( arp_table_map_fd < 0 ) {
fprintf ( stderr , " Failed loading arp_table_map_fd %s \n " ,
strerror ( - arp_table_map_fd ) ) ;
goto end_destroy ;
}
exact_match_map_fd = bpf_map__fd ( skel - > maps . exact_match ) ;
if ( exact_match_map_fd < 0 ) {
fprintf ( stderr , " Failed loading exact_match_map_fd %s \n " ,
strerror ( - exact_match_map_fd ) ) ;
goto end_destroy ;
}
tx_port_map_fd = bpf_map__fd ( skel - > maps . tx_port ) ;
if ( tx_port_map_fd < 0 ) {
fprintf ( stderr , " Failed loading tx_port_map_fd %s \n " ,
strerror ( - tx_port_map_fd ) ) ;
goto end_destroy ;
2019-02-02 00:42:25 +03:00
}
2022-03-16 10:13:23 +03:00
ret = EXIT_FAIL_XDP ;
2017-11-05 06:22:30 +03:00
for ( i = 0 ; i < total_ifindex ; i + + ) {
2022-03-16 10:13:23 +03:00
int index = if_nametoindex ( ifname_list [ i ] ) ;
if ( ! index ) {
fprintf ( stderr , " Interface %s not found %s \n " ,
ifname_list [ i ] , strerror ( - tx_port_map_fd ) ) ;
goto end_destroy ;
2017-11-05 06:22:30 +03:00
}
2022-03-16 10:13:23 +03:00
if ( sample_install_xdp ( skel - > progs . xdp_router_ipv4_prog ,
index , generic , force ) < 0 )
goto end_destroy ;
2017-11-05 06:22:30 +03:00
}
2022-04-05 17:15:14 +03:00
ret = pthread_create ( & routes_thread , NULL , monitor_routes_thread , NULL ) ;
if ( ret ) {
fprintf ( stderr , " Failed creating routes_thread: %s \n " , strerror ( - ret ) ) ;
ret = EXIT_FAIL ;
2022-03-16 10:13:23 +03:00
goto end_destroy ;
}
2017-11-05 06:22:30 +03:00
2022-04-05 17:15:14 +03:00
ret = sample_run ( interval , NULL , NULL ) ;
routes_thread_exit = true ;
2017-11-05 06:22:30 +03:00
2022-03-16 10:13:23 +03:00
if ( ret < 0 ) {
fprintf ( stderr , " Failed during sample run: %s \n " , strerror ( - ret ) ) ;
ret = EXIT_FAIL ;
2022-04-05 17:15:14 +03:00
goto end_thread_wait ;
2017-11-05 06:22:30 +03:00
}
2022-03-16 10:13:23 +03:00
ret = EXIT_OK ;
2017-11-05 06:22:30 +03:00
2022-04-05 17:15:14 +03:00
end_thread_wait :
pthread_join ( routes_thread , NULL ) ;
2022-03-16 10:13:23 +03:00
end_destroy :
xdp_router_ipv4__destroy ( skel ) ;
end :
sample_exit ( ret ) ;
2017-11-05 06:22:30 +03:00
}