LCOV - code coverage report
Current view: top level - app/shared_dev/commands/configure - netns.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 88 0.0 %
Date: 2025-03-20 12:08:36 Functions: 0 6 0.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : #include "../../../shared/commands/configure/configure.h"
       3             : 
       4             : #include <errno.h>
       5             : #include <sys/stat.h>
       6             : 
       7           0 : #define NAME "netns"
       8             : 
       9             : static int
      10           0 : enabled( config_t const * config ) {
      11           0 :   return config->development.netns.enabled;
      12           0 : }
      13             : 
      14             : static void
      15             : init_perm( fd_cap_chk_t *   chk,
      16           0 :            config_t const * config FD_PARAM_UNUSED ) {
      17           0 :   fd_cap_chk_root( chk, NAME, "create and enter network namespaces" );
      18           0 : }
      19             : 
      20             : static void
      21             : fini_perm( fd_cap_chk_t *   chk,
      22           0 :            config_t const * config FD_PARAM_UNUSED ) {
      23           0 :   fd_cap_chk_root( chk, NAME, "remove network namespaces" );
      24           0 : }
      25             : 
      26             : /* RUN() executes the given string and formatting arguments as a
      27             :    subprocess, and waits for the child to complete.  If the child does
      28             :    not exit successfully with code 0, the calling program is aborted. */
      29             : 
      30           0 : #define RUN(...) do {                                                  \
      31           0 :     char cmd[ 4096 ];                                                  \
      32           0 :     FD_TEST( fd_cstr_printf_check( cmd,                                \
      33           0 :                                    sizeof(cmd),                        \
      34           0 :                                    NULL,                               \
      35           0 :                                    __VA_ARGS__ ) );                    \
      36           0 :     int ret = system( cmd );                                           \
      37           0 :     if( FD_UNLIKELY( ret ) )                                           \
      38           0 :       FD_LOG_ERR(( "running command `%s` failed exit code=%d (%i-%s)", \
      39           0 :                    cmd,                                                \
      40           0 :                    ret,                                                \
      41           0 :                    errno,                                              \
      42           0 :                    fd_io_strerror( errno ) ));                         \
      43           0 :   } while( 0 )
      44             : 
      45             : static void
      46           0 : init( config_t const * config ) {
      47           0 :   uint tiles              = config->layout.net_tile_count;
      48           0 :   const char * interface0 = config->development.netns.interface0;
      49           0 :   const char * interface1 = config->development.netns.interface1;
      50             : 
      51           0 :   RUN( "ip netns add %s", interface0 );
      52           0 :   RUN( "ip netns add %s", interface1 );
      53           0 :   RUN( "ip link add dev %s netns %s type veth peer name %s netns %s numrxqueues %u numtxqueues %u",
      54           0 :         interface0, interface0, interface1, interface1, tiles, tiles );
      55           0 :   RUN( "ip netns exec %s ip link set dev %s address %s",
      56           0 :        interface0, interface0, config->development.netns.interface0_mac );
      57           0 :   RUN( "ip netns exec %s ip link set dev %s address %s",
      58           0 :        interface1, interface1, config->development.netns.interface1_mac );
      59           0 :   RUN( "ip netns exec %s ip address add %s/30 dev %s scope link",
      60           0 :        interface0, config->development.netns.interface0_addr, interface0 );
      61           0 :   RUN( "ip netns exec %s ip address add %s/30 dev %s scope link",
      62           0 :        interface1, config->development.netns.interface1_addr, interface1 );
      63           0 :   RUN( "ip netns exec %s ip link set dev %s up", interface0, interface0 );
      64           0 :   RUN( "ip netns exec %s ip link set dev %s up", interface1, interface1 );
      65             : 
      66             :   /* we need one channel for both TX and RX on the NIC for each QUIC
      67             :      tile, but the virtual interfaces default to one channel total */
      68           0 :   RUN( "nsenter --net=/var/run/netns/%s ethtool --set-channels %s rx %u tx %u",
      69           0 :        interface0, interface0, tiles, tiles );
      70           0 :   RUN( "nsenter --net=/var/run/netns/%s ethtool --set-channels %s rx %u tx %u",
      71           0 :        interface1, interface1, tiles, tiles );
      72             : 
      73             :   /* UDP segmentation is a kernel feature that batches multiple UDP
      74             :      packets into one in the kernel before splitting them later when
      75             :      dispatching. this feature is broken with network namespaces so we
      76             :      disable it. otherwise, we would see very large packets that don't
      77             :      decrypt. need on both tx and rx sides */
      78           0 :   RUN( "nsenter --net=/var/run/netns/%s ethtool -K %s tx-udp-segmentation off",
      79           0 :        interface0, interface0 );
      80           0 :   RUN( "nsenter --net=/var/run/netns/%s ethtool -K %s tx-udp-segmentation off",
      81           0 :        interface1, interface1 );
      82             : 
      83             :   /* generic segmentation offload and TX GRE segmentation are similar
      84             :      things on the tx side that also get messed up under netns in
      85             :      unknown ways */
      86           0 :   RUN( "nsenter --net=/var/run/netns/%s ethtool -K %s generic-segmentation-offload off",
      87           0 :        interface0, interface0 );
      88           0 :   RUN( "nsenter --net=/var/run/netns/%s ethtool -K %s generic-segmentation-offload off",
      89           0 :        interface1, interface1 );
      90           0 :   RUN( "nsenter --net=/var/run/netns/%s ethtool -K %s tx-gre-segmentation off",
      91           0 :        interface0, interface0 );
      92           0 :   RUN( "nsenter --net=/var/run/netns/%s ethtool -K %s tx-gre-segmentation off",
      93           0 :        interface1, interface1 );
      94           0 : }
      95             : 
      96             : static void
      97             : fini( config_t const * config,
      98           0 :       int              pre_init FD_PARAM_UNUSED ) {
      99           0 :   const char * interface0 = config->development.netns.interface0;
     100           0 :   const char * interface1 = config->development.netns.interface1;
     101             : 
     102           0 :   char cmd[ 256 ];
     103           0 :   FD_TEST( fd_cstr_printf_check( cmd, sizeof(cmd), NULL, "ip link del dev %s", interface0 ) );
     104           0 :   int status3 = system( cmd ); // Destroys interface1 as well, no need to check failure
     105           0 :   if( FD_UNLIKELY( status3 ) ) FD_LOG_DEBUG(( "ip link del dev %s failed", interface0 ));
     106             : 
     107           0 :   FD_TEST( fd_cstr_printf_check( cmd, sizeof(cmd), NULL, "ip netns delete %s", interface0 ) );
     108           0 :   int status1 = system( cmd );
     109           0 :   FD_TEST( fd_cstr_printf_check( cmd, sizeof(cmd), NULL, "ip netns delete %s", interface1 ) );
     110           0 :   int status2 = system( cmd );
     111             : 
     112             :   /* if neither of them was present, we wouldn't get to the undo step so make sure we were
     113             :      able to delete whatever is there */
     114           0 :   if( FD_UNLIKELY( status1 && status2 ) ) FD_LOG_ERR(( "failed to delete network namespaces" ));
     115           0 : }
     116             : 
     117             : static configure_result_t
     118           0 : check( config_t const * config ) {
     119           0 :   const char * interface0 = config->development.netns.interface0;
     120           0 :   const char * interface1 = config->development.netns.interface1;
     121             : 
     122           0 :   char path[ PATH_MAX ];
     123           0 :   FD_TEST( fd_cstr_printf_check( path, sizeof(path), NULL, "/var/run/netns/%s", interface0 ) );
     124             : 
     125           0 :   struct stat st;
     126           0 :   int result1 = stat( path, &st );
     127           0 :   if( FD_UNLIKELY( result1 && errno != ENOENT ) ) PARTIALLY_CONFIGURED( "netns `%s` cannot be read", interface0 );
     128             : 
     129           0 :   FD_TEST( fd_cstr_printf_check( path, sizeof(path), NULL, "/var/run/netns/%s", interface1 ) );
     130           0 :   int result2 = stat( path, &st );
     131           0 :   if( FD_UNLIKELY( result2 && errno != ENOENT ) ) PARTIALLY_CONFIGURED( "netns `%s` cannot be read", interface1 );
     132             : 
     133           0 :   if( FD_UNLIKELY( result1 && result2 ) ) NOT_CONFIGURED( "netns `%s` and `%s` do not exist", interface0, interface1 );
     134           0 :   else if( FD_UNLIKELY( result1 ) ) NOT_CONFIGURED( "netns `%s` does not exist", interface0 );
     135           0 :   else if( FD_UNLIKELY( result2 ) ) NOT_CONFIGURED( "netns `%s` does not exist", interface1 );
     136             : 
     137             :   /* todo: use `ip netns exec`,  `ip link show` to verify the
     138             :      configuration is correct TODO: Check the ethtool stuff is correct
     139             :      as well */
     140           0 :   CONFIGURE_OK();
     141           0 : }
     142             : 
     143             : configure_stage_t fd_cfg_stage_netns = {
     144             :   .name            = NAME,
     145             :   .always_recreate = 0,
     146             :   .enabled         = enabled,
     147             :   .init_perm       = init_perm,
     148             :   .fini_perm       = fini_perm,
     149             :   .init            = init,
     150             :   .fini            = fini,
     151             :   .check           = check,
     152             : };
     153             : 
     154             : #undef NAME

Generated by: LCOV version 1.14