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 0 : #define PROVIDER_CNT ( 3UL)
20 0 : #define FEAT_CNT_MAX (16UL)
21 0 : #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 0 : fd_auto_driver_rq_t const * supported_drivers ) {
88 : /* Check for driver requirements. */
89 0 : if( !supported_drivers[0].name ) return 1;
90 :
91 0 : for( ulong i=0UL; i<NET_DRIVER_CNT_MAX; i++ ) {
92 0 : fd_auto_driver_rq_t const * req = &supported_drivers[ i ];
93 0 : if( !req->name ) return 0;
94 :
95 0 : 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 0 : if( req->max_linux_major > 0UL ) {
99 0 : if( info->linux_major>req->max_linux_major ||
100 0 : ( info->linux_major==req->max_linux_major &&
101 0 : info->linux_minor>req->max_linux_minor ) ) continue;
102 0 : }
103 :
104 0 : if( info->linux_major>req->min_linux_major ||
105 0 : ( info->linux_major==req->min_linux_major &&
106 0 : info->linux_minor>=req->min_linux_minor ) ) return 1;
107 0 : }
108 0 : }
109 :
110 0 : return 0;
111 0 : }
112 :
113 : /* XDP checks/apply */
114 :
115 : static int
116 : xdp_check( fd_config_t const * config,
117 0 : fd_auto_info_t const * info FD_PARAM_UNUSED ) {
118 0 : if( strcmp( config->net.provider, "auto" ) ) return 0;
119 0 : return 1;
120 0 : }
121 :
122 : static void
123 0 : xdp_apply( fd_config_t * config ) {
124 0 : fd_memcpy( config->net.provider, "xdp", 4 );
125 0 : }
126 :
127 : static int
128 0 : is_xdp_listen_gre_auto( fd_config_t * config ) {
129 0 : if( 2!=config->net.xdp.listen_gre ) return 0;
130 : /* Set to default */
131 0 : config->net.xdp.listen_gre = 0;
132 0 : return 1;
133 0 : }
134 :
135 : static int
136 : xdp_listen_gre_check( fd_config_t const * config FD_PARAM_UNUSED,
137 0 : fd_auto_info_t const * info ) {
138 0 : return info->is_using_gre;
139 0 : }
140 :
141 : static void
142 0 : xdp_listen_gre_apply( fd_config_t * config ) {
143 0 : config->net.xdp.listen_gre = 1;
144 0 : }
145 :
146 : static int
147 0 : is_xdp_rss_queue_mode_auto( fd_config_t * config ) {
148 0 : if( strcmp( config->net.xdp.rss_queue_mode, "auto" ) ) return 0;
149 : /* Set to default */
150 0 : fd_memcpy( config->net.xdp.rss_queue_mode, "simple", 7 );
151 0 : return 1;
152 0 : }
153 :
154 : static int
155 : xdp_rss_queue_mode_check( fd_config_t const * config,
156 0 : fd_auto_info_t const * info ) {
157 0 : if( 1==config->net.xdp.listen_gre ) {
158 0 : static fd_auto_driver_rq_t const gre_rss_drivers[ NET_DRIVER_CNT_MAX ] = {
159 0 : { "mlx5_core", 0, 0, 0, 0 }
160 0 : };
161 :
162 0 : if( 0==fd_auto_check_driver( info, gre_rss_drivers ) ) return 0;
163 0 : }
164 0 : return 1;
165 0 : }
166 :
167 : static void
168 0 : xdp_rss_queue_mode_apply( fd_config_t * config ) {
169 0 : fd_memcpy( config->net.xdp.rss_queue_mode, "auto", 5 );
170 0 : }
171 :
172 : static int
173 0 : is_xdp_native_bond_auto( fd_config_t * config ) {
174 0 : if( 2!=config->net.xdp.native_bond ) return 0;
175 : /* Set to default */
176 0 : config->net.xdp.native_bond = 0;
177 0 : return 1;
178 0 : }
179 :
180 : static int
181 : xdp_native_bond_check( fd_config_t const * config,
182 0 : fd_auto_info_t const * info ) {
183 0 : if( !info->is_bonded_if ) return 0;
184 0 : if( !info->is_lacp_if ) return 0;
185 :
186 0 : 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 0 : if( 0!=config->layout.net_tile_count%info->bonded_if_slave_count ) return 0;
190 :
191 0 : return 1;
192 0 : }
193 :
194 : static void
195 0 : xdp_native_bond_apply( fd_config_t * config ) {
196 0 : config->net.xdp.native_bond = 1;
197 0 : }
198 :
199 : static int
200 0 : is_xdp_mode_auto( fd_config_t * config ) {
201 0 : if( strcmp( config->net.xdp.xdp_mode, "auto" ) ) return 0;
202 : /* Set to default */
203 0 : fd_memcpy( config->net.xdp.xdp_mode, "skb", 4 );
204 0 : return 1;
205 0 : }
206 :
207 : static int
208 : xdp_drv_check( fd_config_t const * config,
209 0 : fd_auto_info_t const * info ) {
210 0 : if( info->is_virtual_if &&
211 0 : !config->net.xdp.native_bond ) return 0;
212 0 : return 1;
213 0 : }
214 :
215 : static void
216 0 : xdp_drv_apply( fd_config_t * config ) {
217 0 : fd_memcpy( config->net.xdp.xdp_mode, "drv", 4 );
218 0 : }
219 :
220 : static int
221 0 : is_xdp_prefbusy_auto( fd_config_t * config ) {
222 0 : if( strcmp( config->net.xdp.poll_mode, "auto" ) ) return 0;
223 : /* Set to default */
224 0 : fd_memcpy( config->net.xdp.poll_mode, "softirq", 8 );
225 0 : return 1;
226 0 : }
227 :
228 : static int
229 : xdp_prefbusy_check( fd_config_t const * config,
230 0 : fd_auto_info_t const * info FD_PARAM_UNUSED ) {
231 0 : if( strcmp( config->net.xdp.xdp_mode, "drv") ) return 0;
232 0 : return 1;
233 0 : }
234 :
235 : static void
236 0 : xdp_prefbusy_apply( fd_config_t * config ) {
237 0 : fd_memcpy( config->net.xdp.poll_mode, "prefbusy", 9 );
238 0 : }
239 :
240 : static int
241 0 : is_xdp_zc_auto( fd_config_t * config ) {
242 0 : if( 2!=config->net.xdp.xdp_zero_copy ) return 0;
243 : /* Set to default */
244 0 : config->net.xdp.xdp_zero_copy = 0;
245 0 : return 1;
246 0 : }
247 :
248 : static int
249 : xdp_zc_check( fd_config_t const * config,
250 0 : fd_auto_info_t const * info FD_PARAM_UNUSED ) {
251 0 : if( strcmp( config->net.xdp.xdp_mode, "drv") ) return 0;
252 0 : return 1;
253 0 : }
254 :
255 : static void
256 0 : xdp_zc_apply( fd_config_t * config ) {
257 0 : config->net.xdp.xdp_zero_copy = 1;
258 0 : }
259 :
260 : /* mlx5 tile checks/apply */
261 : static int
262 : mlx5_check( fd_config_t const * config,
263 0 : fd_auto_info_t const * info ) {
264 0 : if( strcmp( config->net.provider, "auto" ) ) return 0;
265 0 : if( !info->has_mlx5_rdma_port ) return 0;
266 0 : if( !info->has_uverbs && !info->has_uverbs_module ) return 0;
267 0 : return 1;
268 0 : }
269 :
270 : static void
271 0 : mlx5_apply( fd_config_t * config ) {
272 0 : fd_memcpy( config->net.provider, "mlx5", 5 );
273 0 : }
274 :
275 : /* iavf tile checks/apply */
276 : static int
277 : iavf_check( fd_config_t const * config,
278 0 : fd_auto_info_t const * info ) {
279 0 : if( 0!=strcmp( config->net.provider, "auto" ) ) return 0;
280 :
281 0 : if( !info->iavf_pf_checks_passed ) return 0;
282 0 : if( !info->has_vfio && !info->has_vfio_module ) return 0;
283 :
284 0 : 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 0 : static fd_auto_driver_rq_t const iavf_lacp_drivers[ NET_DRIVER_CNT_MAX ] = {
289 0 : { "ice", 6, 5, 0, 0 },
290 0 : { "i40e", 5, 14, 0, 0 }
291 0 : };
292 0 : if( 0==fd_auto_check_driver( info, iavf_lacp_drivers ) ) return 0;
293 0 : }
294 :
295 0 : return 1;
296 0 : }
297 :
298 : static void
299 0 : iavf_apply( fd_config_t * config ) {
300 0 : fd_memcpy( config->net.provider, "iavf", 5 );
301 0 : }
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 0 : scrape_system( fd_auto_info_t * info ) {
384 0 : struct utsname utsname;
385 0 : 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 0 : char const * cur = utsname.release;
398 0 : char * end = NULL;
399 :
400 0 : ulong major = strtoul( cur, &end, 10 );
401 0 : 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 0 : ulong minor = 0UL;
408 0 : if( FD_LIKELY( end[0]=='.' ) ) {
409 0 : cur = end+1;
410 0 : minor = strtoul( cur, &end, 10 );
411 0 : if( FD_UNLIKELY( end==cur ) ) minor = 0UL; /* tolerate "6." */
412 0 : }
413 :
414 0 : info->linux_major = major;
415 0 : info->linux_minor = minor;
416 0 : }
417 :
418 : static int
419 0 : scrape_is_using_gre( void ) {
420 0 : fd_netlink_t netlink[1];
421 0 : if( FD_UNLIKELY( !fd_netlink_init( netlink, 42U ) ) ) return 1;
422 :
423 0 : ulong netdev_tbl_footprint = fd_netdev_tbl_footprint( NETDEV_MAX, BOND_MASTER_MAX );
424 0 : void * netdev_tbl_mem = aligned_alloc( FD_NETDEV_TBL_ALIGN, netdev_tbl_footprint );
425 0 : 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 0 : fd_netdev_tbl_join_t netdev_tbl[1];
432 0 : FD_TEST( fd_netdev_tbl_new( netdev_tbl_mem, NETDEV_MAX, BOND_MASTER_MAX ) );
433 0 : FD_TEST( fd_netdev_tbl_join( netdev_tbl, netdev_tbl_mem ) );
434 :
435 0 : int err = fd_netdev_netlink_load_table( netdev_tbl, netlink );
436 0 : fd_netlink_fini( netlink );
437 0 : 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 0 : int is_using_gre = 0;
445 0 : for( ushort i=0U; i<netdev_tbl->hdr->dev_cnt; i++ ) {
446 0 : if( netdev_tbl->dev_tbl[ i ].dev_type==ARPHRD_IPGRE ) {
447 0 : is_using_gre = 1;
448 0 : break;
449 0 : }
450 0 : }
451 0 : free( netdev_tbl_mem );
452 0 : return is_using_gre;
453 0 : }
454 :
455 : static void
456 : scrape_networking( fd_auto_info_t * info,
457 0 : char const * if_name ) {
458 0 : info->is_using_gre = scrape_is_using_gre();
459 :
460 : /* Check for virtual interface */
461 0 : char path[ PATH_MAX ];
462 0 : FD_TEST( fd_cstr_printf_check( path, PATH_MAX, NULL, "/sys/class/net/%s/device", if_name ) );
463 0 : info->is_virtual_if = ( -1==access( path, F_OK ) );
464 :
465 : /* Check for bond */
466 0 : info->is_bonded_if = !!fd_bonding_is_master( if_name );
467 0 : if( info->is_bonded_if ) {
468 0 : info->bonded_if_slave_count = (uint)fd_bonding_slave_cnt( if_name );
469 0 : info->is_lacp_if = !!fd_bonding_is_lacp( if_name );
470 0 : }
471 :
472 0 : fd_net_get_driver( info->driver, sizeof(info->driver), if_name );
473 :
474 0 : if( !strcmp( info->driver, "mlx5_core" ) ) {
475 0 : char rdma_name[ FD_MLX5_RDMA_NAME_MAX ];
476 0 : uint rdma_port;
477 0 : info->has_mlx5_rdma_port = fd_mlx5_rdma_dev_find( rdma_name, &rdma_port, if_name );
478 0 : info->has_uverbs = fd_mlx5_uverbs_avail();
479 0 : }
480 0 : }
481 :
482 : static int
483 0 : scrape_iavf_pfs( char const * if_name ) {
484 0 : char members[ FD_IAVF_MEMBER_MAX ][ IF_NAMESIZE ];
485 0 : ulong member_cnt;
486 0 : 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 0 : fd_auto_scrape_info( fd_config_t const * config ) {
519 0 : fd_auto_info_t info = {0};
520 :
521 0 : scrape_system ( &info );
522 0 : scrape_networking( &info, config->net.interface );
523 :
524 0 : if( !strcmp( config->net.provider, "auto" ) &&
525 0 : info.has_mlx5_rdma_port &&
526 0 : !info.has_uverbs ) {
527 0 : info.has_uverbs_module = 0==fd_sys_util_modprobe( "ib_uverbs", 1 );
528 0 : }
529 :
530 0 : if( 0==strcmp( config->net.provider, "auto" ) ) {
531 0 : info.iavf_pf_checks_passed = scrape_iavf_pfs( config->net.interface );
532 0 : 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 0 : }
540 :
541 0 : return info;
542 0 : }
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 0 : fd_auto_info_t const * info ) {
550 : /* Providers are in order of priority with first being the highest */
551 0 : int const is_provider_auto = !strcmp( config->net.provider, "auto" );
552 0 : int is_provider_set = 0;
553 0 : for( ulong p=0UL; p<PROVIDER_CNT; p++ ) {
554 0 : fd_auto_provider_t const * provider = &NET_PROVIDERS[p];
555 :
556 : /* Check provider requirements */
557 0 : int const is_explicit_provider = !is_provider_auto && !strcmp( config->net.provider, provider->name );
558 0 : int is_chosen_provider = !is_provider_set &&
559 0 : ( is_explicit_provider ||
560 0 : ( is_provider_auto &&
561 0 : ( !provider->check || provider->check( config, info ) ) &&
562 0 : fd_auto_check_driver( info, provider->supported_drivers ) ) );
563 0 : if( is_chosen_provider ) {
564 0 : is_provider_set = 1;
565 0 : if( is_provider_auto ) {
566 0 : 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 0 : provider->apply( config );
570 0 : }
571 0 : }
572 :
573 0 : for( ulong f=0UL; f<FEAT_CNT_MAX; f++ ) {
574 0 : fd_auto_feat_t const * feat = &provider->feats[f];
575 0 : 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 0 : if( !feat->is_feat_auto( config ) ) continue;
580 :
581 0 : if( !is_chosen_provider ) continue;
582 :
583 : /* Feature's driver/Linux version requirements */
584 0 : if( !fd_auto_check_driver( info, feat->supported_drivers ) ) continue;
585 :
586 : /* Feature's other requirements */
587 0 : if( feat->check && !feat->check( config, info ) ) continue;
588 :
589 0 : 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 0 : feat->apply( config );
593 0 : }
594 0 : }
595 0 : }
596 :
597 : void
598 0 : fd_auto_net( fd_config_t * config ) {
599 0 : fd_auto_info_t info = fd_auto_scrape_info( config );
600 0 : fd_auto_net_apply( config, &info );
601 :
602 0 : fd_cstr_printf( config->auto_config_log, sizeof(config->auto_config_log), NULL,
603 0 : "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 0 : config->net.provider,
605 0 : config->net.xdp.xdp_mode,
606 0 : config->net.xdp.poll_mode,
607 0 : config->net.xdp.xdp_zero_copy,
608 0 : config->net.xdp.native_bond,
609 0 : config->net.xdp.listen_gre,
610 0 : config->net.xdp.rss_queue_mode,
611 0 : info.driver[0] ? info.driver : "unknown",
612 0 : info.linux_major, info.linux_minor,
613 0 : info.is_using_gre,
614 0 : info.is_virtual_if,
615 0 : info.is_bonded_if,
616 0 : info.is_lacp_if,
617 0 : info.bonded_if_slave_count,
618 0 : config->layout.net_tile_count );
619 0 : }
|