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