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
|