LCOV - code coverage report
Current view: top level - app/fddev/configure - netns.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 77 0.0 %
Date: 2024-11-13 11:58:15 Functions: 0 6 0.0 %

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

Generated by: LCOV version 1.14