Line data Source code
1 : #include "fd_auto_net.h"
2 : #include "../platform/fd_sys_util.h"
3 : #include "commands/configure/fd_ethtool_ioctl.h"
4 : #include "../../disco/net/fd_linux_bond.h"
5 : #include "../../disco/net/fd_net_tile.h"
6 : #include "../../disco/net/iavf/fd_iavf.h"
7 : #include "../../disco/net/mlx5/fd_mlx5.h"
8 : #include "../../disco/netlink/fd_netlink_tile.h"
9 : #include "../../waltz/mib/fd_netdev_netlink.h"
10 :
11 : #include <stdlib.h> /* strtoul */
12 : #include <limits.h>
13 : #include <errno.h>
14 : #include <string.h>
15 : #include <unistd.h>
16 : #include <sys/utsname.h>
17 : #include <linux/if_arp.h>
18 :
19 384 : #define PROVIDER_CNT ( 3UL)
20 864 : #define FEAT_CNT_MAX (16UL)
21 561 : #define NET_DRIVER_CNT_MAX (16UL)
22 :
23 : struct fd_auto_info {
24 : /* System */
25 : ulong linux_major;
26 : ulong linux_minor;
27 :
28 : /* Networking */
29 : char driver[ NAME_SZ ];
30 : uint is_virtual_if:1;
31 : uint is_bonded_if:1;
32 : uint is_lacp_if:1;
33 : uint bonded_if_slave_count;
34 : int is_using_gre;
35 : int has_mlx5_rdma_port;
36 : int has_uverbs;
37 : int has_uverbs_module;
38 : int iavf_pf_checks_passed;
39 : int has_vfio;
40 : int has_vfio_module;
41 : };
42 : typedef struct fd_auto_info fd_auto_info_t;
43 :
44 : struct fd_auto_driver_rq {
45 : char const * name;
46 : ulong min_linux_major;
47 : ulong min_linux_minor;
48 :
49 : /* 0 = no max linux version */
50 : ulong max_linux_major;
51 : ulong max_linux_minor;
52 : };
53 : typedef struct fd_auto_driver_rq fd_auto_driver_rq_t;
54 :
55 : struct fd_auto_feat {
56 : char const * name;
57 : /* supported_drivers is for unconditional driver requirements.
58 : For conditional driver requirements leave this empty and call
59 : fd_auto_check_driver() inside the check() callback
60 : (like xdp_rss_queue_mode_check() does). */
61 : fd_auto_driver_rq_t supported_drivers[ NET_DRIVER_CNT_MAX ];
62 :
63 : /* is_feat_auto() checks if feature is auto and sets the default */
64 : int (*is_feat_auto)( fd_config_t * config );
65 : int (*check )( fd_config_t const * config,
66 : fd_auto_info_t const * info );
67 : void (*apply )( fd_config_t * config );
68 : };
69 : typedef struct fd_auto_feat fd_auto_feat_t;
70 :
71 : struct fd_auto_provider {
72 : char const * name;
73 : /* Later features observe earlier features updates to config,
74 : so the order is important. e.g. ZC checks xdp_mode is DRV
75 : so DRV needs to come before ZC in the feats ordering. */
76 : fd_auto_feat_t feats [ FEAT_CNT_MAX ];
77 : fd_auto_driver_rq_t supported_drivers[ NET_DRIVER_CNT_MAX ];
78 :
79 : int (*check)( fd_config_t const * config,
80 : fd_auto_info_t const * info );
81 : void (*apply)( fd_config_t * config );
82 : };
83 : typedef struct fd_auto_provider fd_auto_provider_t;
84 :
85 : static int
86 : fd_auto_check_driver( fd_auto_info_t const * info,
87 405 : fd_auto_driver_rq_t const * supported_drivers ) {
88 : /* Check for driver requirements. */
89 405 : if( !supported_drivers[0].name ) return 1;
90 :
91 561 : for( ulong i=0UL; i<NET_DRIVER_CNT_MAX; i++ ) {
92 561 : fd_auto_driver_rq_t const * req = &supported_drivers[ i ];
93 561 : if( !req->name ) return 0;
94 :
95 438 : if( 0==strcmp( info->driver, req->name ) ) {
96 : /* Check system linux version is within bounds of min and max
97 : of what this driver req requires. */
98 225 : if( req->max_linux_major > 0UL ) {
99 30 : if( info->linux_major>req->max_linux_major ||
100 30 : ( info->linux_major==req->max_linux_major &&
101 24 : info->linux_minor>req->max_linux_minor ) ) continue;
102 30 : }
103 :
104 201 : if( info->linux_major>req->min_linux_major ||
105 201 : ( info->linux_major==req->min_linux_major &&
106 153 : info->linux_minor>=req->min_linux_minor ) ) return 1;
107 201 : }
108 438 : }
109 :
110 0 : return 0;
111 276 : }
112 :
113 : /* XDP checks/apply */
114 :
115 : static int
116 : xdp_check( fd_config_t const * config,
117 27 : fd_auto_info_t const * info FD_PARAM_UNUSED ) {
118 27 : if( strcmp( config->net.provider, "auto" ) ) return 0;
119 27 : return 1;
120 27 : }
121 :
122 : static void
123 27 : xdp_apply( fd_config_t * config ) {
124 27 : fd_memcpy( config->net.provider, "xdp", 4 );
125 27 : }
126 :
127 : static int
128 96 : is_xdp_listen_gre_auto( fd_config_t * config ) {
129 96 : if( 2!=config->net.xdp.listen_gre ) return 0;
130 : /* Set to default */
131 93 : config->net.xdp.listen_gre = 0;
132 93 : return 1;
133 96 : }
134 :
135 : static int
136 : xdp_listen_gre_check( fd_config_t const * config FD_PARAM_UNUSED,
137 51 : fd_auto_info_t const * info ) {
138 51 : return info->is_using_gre;
139 51 : }
140 :
141 : static void
142 6 : xdp_listen_gre_apply( fd_config_t * config ) {
143 6 : config->net.xdp.listen_gre = 1;
144 6 : }
145 :
146 : static int
147 96 : is_xdp_rss_queue_mode_auto( fd_config_t * config ) {
148 96 : if( strcmp( config->net.xdp.rss_queue_mode, "auto" ) ) return 0;
149 : /* Set to default */
150 93 : fd_memcpy( config->net.xdp.rss_queue_mode, "simple", 7 );
151 93 : return 1;
152 96 : }
153 :
154 : static int
155 : xdp_rss_queue_mode_check( fd_config_t const * config,
156 51 : fd_auto_info_t const * info ) {
157 51 : if( 1==config->net.xdp.listen_gre ) {
158 6 : static fd_auto_driver_rq_t const gre_rss_drivers[ NET_DRIVER_CNT_MAX ] = {
159 6 : { "mlx5_core", 0, 0, 0, 0 }
160 6 : };
161 :
162 6 : if( 0==fd_auto_check_driver( info, gre_rss_drivers ) ) return 0;
163 6 : }
164 48 : return 1;
165 51 : }
166 :
167 : static void
168 48 : xdp_rss_queue_mode_apply( fd_config_t * config ) {
169 48 : fd_memcpy( config->net.xdp.rss_queue_mode, "auto", 5 );
170 48 : }
171 :
172 : static int
173 96 : is_xdp_native_bond_auto( fd_config_t * config ) {
174 96 : if( 2!=config->net.xdp.native_bond ) return 0;
175 : /* Set to default */
176 96 : config->net.xdp.native_bond = 0;
177 96 : return 1;
178 96 : }
179 :
180 : static int
181 : xdp_native_bond_check( fd_config_t const * config,
182 27 : fd_auto_info_t const * info ) {
183 27 : if( !info->is_bonded_if ) return 0;
184 6 : if( !info->is_lacp_if ) return 0;
185 :
186 3 : if( 0==info->bonded_if_slave_count || info->bonded_if_slave_count>FD_NET_BOND_SLAVE_MAX ) return 0;
187 :
188 : /* net_tile_count must be a multiple of the bonded interface's slave count */
189 3 : if( 0!=config->layout.net_tile_count%info->bonded_if_slave_count ) return 0;
190 :
191 3 : return 1;
192 3 : }
193 :
194 : static void
195 3 : xdp_native_bond_apply( fd_config_t * config ) {
196 3 : config->net.xdp.native_bond = 1;
197 3 : }
198 :
199 : static int
200 96 : is_xdp_mode_auto( fd_config_t * config ) {
201 96 : if( strcmp( config->net.xdp.xdp_mode, "auto" ) ) return 0;
202 : /* Set to default */
203 96 : fd_memcpy( config->net.xdp.xdp_mode, "skb", 4 );
204 96 : return 1;
205 96 : }
206 :
207 : static int
208 : xdp_drv_check( fd_config_t const * config,
209 27 : fd_auto_info_t const * info ) {
210 27 : if( info->is_virtual_if &&
211 27 : !config->net.xdp.native_bond ) return 0;
212 24 : return 1;
213 27 : }
214 :
215 : static void
216 24 : xdp_drv_apply( fd_config_t * config ) {
217 24 : fd_memcpy( config->net.xdp.xdp_mode, "drv", 4 );
218 24 : }
219 :
220 : static int
221 96 : is_xdp_prefbusy_auto( fd_config_t * config ) {
222 96 : if( strcmp( config->net.xdp.poll_mode, "auto" ) ) return 0;
223 : /* Set to default */
224 96 : fd_memcpy( config->net.xdp.poll_mode, "softirq", 8 );
225 96 : return 1;
226 96 : }
227 :
228 : static int
229 : xdp_prefbusy_check( fd_config_t const * config,
230 27 : fd_auto_info_t const * info FD_PARAM_UNUSED ) {
231 27 : if( strcmp( config->net.xdp.xdp_mode, "drv") ) return 0;
232 24 : return 1;
233 27 : }
234 :
235 : static void
236 24 : xdp_prefbusy_apply( fd_config_t * config ) {
237 24 : fd_memcpy( config->net.xdp.poll_mode, "prefbusy", 9 );
238 24 : }
239 :
240 : static int
241 96 : is_xdp_zc_auto( fd_config_t * config ) {
242 96 : if( 2!=config->net.xdp.xdp_zero_copy ) return 0;
243 : /* Set to default */
244 96 : config->net.xdp.xdp_zero_copy = 0;
245 96 : return 1;
246 96 : }
247 :
248 : static int
249 : xdp_zc_check( fd_config_t const * config,
250 24 : fd_auto_info_t const * info FD_PARAM_UNUSED ) {
251 24 : if( strcmp( config->net.xdp.xdp_mode, "drv") ) return 0;
252 21 : return 1;
253 24 : }
254 :
255 : static void
256 21 : xdp_zc_apply( fd_config_t * config ) {
257 21 : config->net.xdp.xdp_zero_copy = 1;
258 21 : }
259 :
260 : /* mlx5 tile checks/apply */
261 : static int
262 : mlx5_check( fd_config_t const * config,
263 63 : fd_auto_info_t const * info ) {
264 63 : if( strcmp( config->net.provider, "auto" ) ) return 0;
265 63 : if( !info->has_mlx5_rdma_port ) return 0;
266 21 : if( !info->has_uverbs && !info->has_uverbs_module ) return 0;
267 18 : return 1;
268 21 : }
269 :
270 : static void
271 18 : mlx5_apply( fd_config_t * config ) {
272 18 : fd_memcpy( config->net.provider, "mlx5", 5 );
273 18 : }
274 :
275 : /* iavf tile checks/apply */
276 : static int
277 : iavf_check( fd_config_t const * config,
278 45 : fd_auto_info_t const * info ) {
279 45 : if( 0!=strcmp( config->net.provider, "auto" ) ) return 0;
280 :
281 45 : if( !info->iavf_pf_checks_passed ) return 0;
282 30 : if( !info->has_vfio && !info->has_vfio_module ) return 0;
283 :
284 27 : if( info->is_bonded_if ) {
285 : /* Linux ice driver started allowing LACP bonds in combination with
286 : SR-IOV from Linux v6.5.
287 : https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1c769b1a303f7a3b447fc7244340b77823bdbfdc */
288 15 : static fd_auto_driver_rq_t const iavf_lacp_drivers[ NET_DRIVER_CNT_MAX ] = {
289 15 : { "ice", 6, 5, 0, 0 },
290 15 : { "i40e", 5, 14, 0, 0 }
291 15 : };
292 15 : if( 0==fd_auto_check_driver( info, iavf_lacp_drivers ) ) return 0;
293 15 : }
294 :
295 21 : return 1;
296 27 : }
297 :
298 : static void
299 18 : iavf_apply( fd_config_t * config ) {
300 18 : fd_memcpy( config->net.provider, "iavf", 5 );
301 18 : }
302 :
303 : /* Each feature's supported Linux version matrix per driver decided
304 : based on fd-linux-version-testbed test results. */
305 : static const fd_auto_provider_t NET_PROVIDERS[] = {
306 : {
307 : .name = "mlx5",
308 : .supported_drivers = { { "mlx5_core", 5, 14, 0, 0 } },
309 : .check = mlx5_check,
310 : .apply = mlx5_apply
311 : },
312 : {
313 : .name = "iavf",
314 : .supported_drivers = {
315 : { "ice", 5, 14, 0, 0 },
316 : { "i40e", 5, 14, 0, 0 }
317 : },
318 : .check = iavf_check,
319 : .apply = iavf_apply
320 : },
321 : {
322 : .name = "xdp",
323 : .check = xdp_check,
324 : .apply = xdp_apply,
325 : .feats = {
326 : {
327 : .name = "Listen GRE",
328 : .is_feat_auto = is_xdp_listen_gre_auto,
329 : .check = xdp_listen_gre_check,
330 : .apply = xdp_listen_gre_apply
331 : },
332 : {
333 : .name = "RSS Queue Mode",
334 : .is_feat_auto = is_xdp_rss_queue_mode_auto,
335 : .check = xdp_rss_queue_mode_check,
336 : .apply = xdp_rss_queue_mode_apply
337 : },
338 : {
339 : .name = "Native Bond",
340 : .supported_drivers = {
341 : { "mlx5_core", 5, 15, 0, 0 },
342 : { "i40e", 5, 15, 0, 0 },
343 : },
344 : .is_feat_auto = is_xdp_native_bond_auto,
345 : .check = xdp_native_bond_check,
346 : .apply = xdp_native_bond_apply
347 : },
348 : {
349 : .name = "DRV",
350 : .supported_drivers = {
351 : { "mlx5_core", 5, 15, 6, 3 },
352 : { "mlx5_core", 6, 5, 0, 0 },
353 : { "i40e", 5, 19, 0, 0 }
354 : },
355 : .is_feat_auto = is_xdp_mode_auto,
356 : .check = xdp_drv_check,
357 : .apply = xdp_drv_apply,
358 : },
359 : {
360 : .name = "Prefbusy",
361 : .supported_drivers = {
362 : { "mlx5_core", 5, 15, 0, 0 },
363 : { "i40e", 5, 15, 0, 0 }
364 : },
365 : .is_feat_auto = is_xdp_prefbusy_auto,
366 : .check = xdp_prefbusy_check,
367 : .apply = xdp_prefbusy_apply
368 : },
369 : {
370 : .name = "Zero Copy",
371 : .supported_drivers = {
372 : { "mlx5_core", 6, 1, 0, 0 }
373 : },
374 : .is_feat_auto = is_xdp_zc_auto,
375 : .check = xdp_zc_check,
376 : .apply = xdp_zc_apply
377 : }
378 : }
379 : }
380 : };
381 :
382 : static void
383 9 : scrape_system( fd_auto_info_t * info ) {
384 9 : struct utsname utsname;
385 9 : if( FD_UNLIKELY( -1==uname( &utsname ) ) ) {
386 0 : FD_LOG_WARNING(( "uname() failed (%i-%s), auto config skipping kernel version detection",
387 0 : errno, fd_io_strerror( errno ) ));
388 0 : return;
389 0 : }
390 :
391 : /* utsname.release is typically "major.minor.patch-distrojunk",
392 : e.g. "6.8.0-45-generic" or "5.14.0-362.8.1.el9_3.x86_64". We
393 : only care about major.minor. A missing ".minor" is treated as
394 : minor 0. An unparseable release leaves {0,0}, which fails all
395 : version requirements (fail-soft). */
396 :
397 9 : char const * cur = utsname.release;
398 9 : char * end = NULL;
399 :
400 9 : ulong major = strtoul( cur, &end, 10 );
401 9 : if( FD_UNLIKELY( end==cur ) ) {
402 0 : FD_LOG_WARNING(( "unrecognized kernel release `%s`, auto config skipping kernel version detection",
403 0 : utsname.release ));
404 0 : return;
405 0 : }
406 :
407 9 : ulong minor = 0UL;
408 9 : if( FD_LIKELY( end[0]=='.' ) ) {
409 9 : cur = end+1;
410 9 : minor = strtoul( cur, &end, 10 );
411 9 : if( FD_UNLIKELY( end==cur ) ) minor = 0UL; /* tolerate "6." */
412 9 : }
413 :
414 9 : info->linux_major = major;
415 9 : info->linux_minor = minor;
416 9 : }
417 :
418 : static int
419 9 : scrape_is_using_gre( void ) {
420 9 : fd_netlink_t netlink[1];
421 9 : if( FD_UNLIKELY( !fd_netlink_init( netlink, 42U ) ) ) return 1;
422 :
423 9 : ulong netdev_tbl_footprint = fd_netdev_tbl_footprint( NETDEV_MAX, BOND_MASTER_MAX );
424 9 : void * netdev_tbl_mem = aligned_alloc( FD_NETDEV_TBL_ALIGN, netdev_tbl_footprint );
425 9 : if( FD_UNLIKELY( !netdev_tbl_mem ) ) {
426 0 : fd_netlink_fini( netlink );
427 0 : FD_LOG_WARNING(( "failed to allocate network interface table for GRE auto detection" ));
428 0 : return 1;
429 0 : }
430 :
431 9 : fd_netdev_tbl_join_t netdev_tbl[1];
432 9 : FD_TEST( fd_netdev_tbl_new( netdev_tbl_mem, NETDEV_MAX, BOND_MASTER_MAX ) );
433 9 : FD_TEST( fd_netdev_tbl_join( netdev_tbl, netdev_tbl_mem ) );
434 :
435 9 : int err = fd_netdev_netlink_load_table( netdev_tbl, netlink );
436 9 : fd_netlink_fini( netlink );
437 9 : if( FD_UNLIKELY( err ) ) {
438 0 : FD_LOG_WARNING(( "failed to load network interfaces for GRE auto detection (%i-%s)",
439 0 : err, fd_io_strerror( err ) ));
440 0 : free( netdev_tbl_mem );
441 0 : return 1;
442 0 : }
443 :
444 9 : int is_using_gre = 0;
445 72 : for( ushort i=0U; i<netdev_tbl->hdr->dev_cnt; i++ ) {
446 63 : if( netdev_tbl->dev_tbl[ i ].dev_type==ARPHRD_IPGRE ) {
447 0 : is_using_gre = 1;
448 0 : break;
449 0 : }
450 63 : }
451 9 : free( netdev_tbl_mem );
452 9 : return is_using_gre;
453 9 : }
454 :
455 : static void
456 : scrape_networking( fd_auto_info_t * info,
457 9 : char const * if_name ) {
458 9 : info->is_using_gre = scrape_is_using_gre();
459 :
460 : /* Check for virtual interface */
461 9 : char path[ PATH_MAX ];
462 9 : FD_TEST( fd_cstr_printf_check( path, PATH_MAX, NULL, "/sys/class/net/%s/device", if_name ) );
463 9 : info->is_virtual_if = ( -1==access( path, F_OK ) );
464 :
465 : /* Check for bond */
466 9 : info->is_bonded_if = !!fd_bonding_is_master( if_name );
467 9 : if( info->is_bonded_if ) {
468 9 : info->bonded_if_slave_count = (uint)fd_bonding_slave_cnt( if_name );
469 9 : info->is_lacp_if = !!fd_bonding_is_lacp( if_name );
470 9 : }
471 :
472 9 : fd_net_get_driver( info->driver, sizeof(info->driver), if_name );
473 :
474 9 : if( !strcmp( info->driver, "mlx5_core" ) ) {
475 9 : char rdma_name[ FD_MLX5_RDMA_NAME_MAX ];
476 9 : uint rdma_port;
477 9 : info->has_mlx5_rdma_port = fd_mlx5_rdma_dev_find( rdma_name, &rdma_port, if_name );
478 9 : info->has_uverbs = fd_mlx5_uverbs_avail();
479 9 : }
480 9 : }
481 :
482 : static int
483 9 : scrape_iavf_pfs( char const * if_name ) {
484 9 : char members[ FD_IAVF_MEMBER_MAX ][ IF_NAMESIZE ];
485 9 : ulong member_cnt;
486 9 : if( FD_UNLIKELY( -1==fd_iavf_member_interfaces( if_name, members, &member_cnt ) ) ) return 0;
487 :
488 : /* Each PF needs ARI, an IOMMU, PCIe resources for VFs and ntuple filtering */
489 0 : for( ulong i=0UL; i<member_cnt; i++ ) {
490 0 : uint numvfs;
491 0 : if( FD_UNLIKELY( -1==fd_iavf_iommu_check( members[i], NULL ) ) ) return 0;
492 0 : if( FD_UNLIKELY( -1==fd_iavf_ari_check( members[i] ) ) ) return 0;
493 0 : if( FD_UNLIKELY( -1==fd_iavf_numvfs_get( members[i], &numvfs ) ) ) return 0;
494 0 : if( FD_UNLIKELY( 0==numvfs && -1==fd_iavf_sriov_resources_check( members[i] ) ) ) return 0;
495 0 : if( 0!=numvfs ) {
496 0 : char vf_pci[ FD_IAVF_PCI_ADDR_SZ ];
497 0 : fd_iavf_pci_info_t pci;
498 0 : if( FD_UNLIKELY( -1==fd_iavf_get_last_vf( members[i], NULL, vf_pci, 1 ) ) ) return 0;
499 0 : if( FD_UNLIKELY( -1==fd_iavf_pci_probe( &pci, vf_pci ) ) ) return 0;
500 0 : if( 0!=strcmp( pci.driver, "vfio-pci" ) ) return 0;
501 0 : }
502 :
503 0 : fd_ethtool_ioctl_t ioc;
504 0 : if( FD_UNLIKELY( NULL==fd_ethtool_ioctl_init( &ioc, members[i] ) ) ) return 0;
505 :
506 : /* Only select IAVF automatically if ntuple filtering is enabled */
507 0 : int ntuple_enabled;
508 0 : int err = fd_ethtool_ioctl_feature_test( &ioc, FD_ETHTOOL_FEATURE_NTUPLE, &ntuple_enabled );
509 0 : fd_ethtool_ioctl_fini( &ioc );
510 :
511 0 : if( FD_UNLIKELY( 0!=err ) ) return 0;
512 0 : if( FD_UNLIKELY( !ntuple_enabled ) ) return 0;
513 0 : }
514 0 : return 1;
515 0 : }
516 :
517 : static fd_auto_info_t
518 9 : fd_auto_scrape_info( fd_config_t const * config ) {
519 9 : fd_auto_info_t info = {0};
520 :
521 9 : scrape_system ( &info );
522 9 : scrape_networking( &info, config->net.interface );
523 :
524 9 : if( !strcmp( config->net.provider, "auto" ) &&
525 9 : info.has_mlx5_rdma_port &&
526 9 : !info.has_uverbs ) {
527 0 : info.has_uverbs_module = 0==fd_sys_util_modprobe( "ib_uverbs", 1 );
528 0 : }
529 :
530 9 : if( 0==strcmp( config->net.provider, "auto" ) ) {
531 9 : info.iavf_pf_checks_passed = scrape_iavf_pfs( config->net.interface );
532 9 : if( info.iavf_pf_checks_passed ) {
533 0 : if( fd_iavf_vfio_avail() ) {
534 0 : info.has_vfio = 0==fd_iavf_vfio_api_check( NULL );
535 0 : } else {
536 0 : info.has_vfio_module = 0==fd_sys_util_modprobe( "vfio-pci", 1 );
537 0 : }
538 0 : }
539 9 : }
540 :
541 9 : return info;
542 9 : }
543 :
544 : /* fd_auto_net_apply resolves any "auto" fields in the networking
545 : configuration. The resulting configuration is optimized for the system
546 : but won't always maximally optimize, this is to reduce risk of failures. */
547 : static void
548 : fd_auto_net_apply( fd_config_t * config,
549 96 : fd_auto_info_t const * info ) {
550 : /* Providers are in order of priority with first being the highest */
551 96 : int const is_provider_auto = !strcmp( config->net.provider, "auto" );
552 96 : int is_provider_set = 0;
553 384 : for( ulong p=0UL; p<PROVIDER_CNT; p++ ) {
554 288 : fd_auto_provider_t const * provider = &NET_PROVIDERS[p];
555 :
556 : /* Check provider requirements */
557 288 : int const is_explicit_provider = !is_provider_auto && !strcmp( config->net.provider, provider->name );
558 288 : int is_chosen_provider = !is_provider_set &&
559 288 : ( is_explicit_provider ||
560 228 : ( is_provider_auto &&
561 198 : ( !provider->check || provider->check( config, info ) ) &&
562 198 : fd_auto_check_driver( info, provider->supported_drivers ) ) );
563 288 : if( is_chosen_provider ) {
564 93 : is_provider_set = 1;
565 93 : if( is_provider_auto ) {
566 63 : if( FD_UNLIKELY( !provider->apply ) ) {
567 0 : FD_LOG_ERR(( "Applying auto configure net provider %s failed since no apply function was found.", provider->name ));
568 0 : }
569 63 : provider->apply( config );
570 63 : }
571 93 : }
572 :
573 864 : for( ulong f=0UL; f<FEAT_CNT_MAX; f++ ) {
574 864 : fd_auto_feat_t const * feat = &provider->feats[f];
575 864 : if( !feat->name ) break;
576 :
577 : /* Checks feature is set to "auto", if so replaces "auto" with
578 : default and goes onto the next checks */
579 576 : if( !feat->is_feat_auto( config ) ) continue;
580 :
581 570 : if( !is_chosen_provider ) continue;
582 :
583 : /* Feature's driver/Linux version requirements */
584 318 : if( !fd_auto_check_driver( info, feat->supported_drivers ) ) continue;
585 :
586 : /* Feature's other requirements */
587 207 : if( feat->check && !feat->check( config, info ) ) continue;
588 :
589 126 : if( FD_UNLIKELY( !feat->apply ) ) {
590 0 : FD_LOG_ERR(( "Applying auto configure net feature %s failed since no apply function was found.", feat->name ));
591 0 : }
592 126 : feat->apply( config );
593 126 : }
594 288 : }
595 96 : }
596 :
597 : void
598 9 : fd_auto_net( fd_config_t * config ) {
599 9 : fd_auto_info_t info = fd_auto_scrape_info( config );
600 9 : fd_auto_net_apply( config, &info );
601 :
602 9 : fd_cstr_printf( config->auto_config_log, sizeof(config->auto_config_log), NULL,
603 9 : "network auto configure system info: provider=%s xdp_mode=%s poll_mode=%s zero_copy=%d native_bond=%d listen_gre=%d rss_queue_mode=%s (driver=%s kernel=%lu.%lu gre=%d virtual_if=%d bonded_if=%d lacp_if=%d slaves=%u, net_tile_cnt=%u)",
604 9 : config->net.provider,
605 9 : config->net.xdp.xdp_mode,
606 9 : config->net.xdp.poll_mode,
607 9 : config->net.xdp.xdp_zero_copy,
608 9 : config->net.xdp.native_bond,
609 9 : config->net.xdp.listen_gre,
610 9 : config->net.xdp.rss_queue_mode,
611 9 : info.driver[0] ? info.driver : "unknown",
612 9 : info.linux_major, info.linux_minor,
613 9 : info.is_using_gre,
614 9 : info.is_virtual_if,
615 9 : info.is_bonded_if,
616 9 : info.is_lacp_if,
617 9 : info.bonded_if_slave_count,
618 9 : config->layout.net_tile_count );
619 9 : }
|