@@ -366,6 +366,51 @@ void init_network(const char* iface, int domain) {
366366 close (s );
367367}
368368
369+ // Preload networking modules that may not be built-in on all distros (e.g., Ubuntu).
370+ // On kernels where these are built-in (=y), the probe call is a harmless no-op.
371+ // Must only be called when MODULES is defined (caller is responsible for the guard).
372+ void preload_networking_modules () {
373+ const char * modules [] = {
374+ "hv_netvsc" , // Hyper-V network driver
375+ "hv_sock" , // Hyper-V vsocket support
376+ "bridge" , // Linux bridge support
377+ "veth" , // Virtual ethernet pairs
378+ "nf_conntrack" , // Connection tracking for NAT/masquerading
379+ "br_netfilter" , // Bridge netfilter for iptables
380+ NULL
381+ };
382+
383+ if (k_ctx == NULL ) {
384+ k_ctx = kmod_new (NULL , NULL );
385+ if (k_ctx == NULL ) {
386+ dmesgWarn ("preload_networking_modules: failed to create kmod context\n" );
387+ return ;
388+ }
389+ }
390+
391+ kmod_load_resources (k_ctx );
392+
393+ for (int i = 0 ; modules [i ] != NULL ; i ++ ) {
394+ struct kmod_module * mod = NULL ;
395+ int err = kmod_module_new_from_name (k_ctx , modules [i ], & mod );
396+ if (err < 0 )
397+ continue ;
398+
399+ err = kmod_module_probe_insert_module (mod , KMOD_PROBE_IGNORE_LOADED , NULL , NULL , NULL , NULL );
400+ char msg [256 ];
401+ const char * status = (err == 0 || err == - EEXIST ) ? "ok"
402+ : (err == - ENOENT ) ? "not found (may be built-in)"
403+ : "failed" ;
404+ snprintf (msg , sizeof (msg ), "preload module %s: %s (err=%d)\n" , modules [i ], status , err );
405+ if (err == 0 || err == - EEXIST || err == - ENOENT )
406+ dmesgInfo (msg );
407+ else
408+ dmesgWarn (msg );
409+
410+ kmod_module_unref (mod );
411+ }
412+ }
413+
369414// inject boot-time entropy after reading it from a vsock port
370415void init_entropy (int port ) {
371416 int s = openvsock (VMADDR_CID_HOST , port );
@@ -507,7 +552,8 @@ int load_module(struct kmod_ctx* ctx, const char* module_path) {
507552 return err ;
508553 }
509554
510- err = kmod_module_probe_insert_module (mod , 0 , NULL , NULL , NULL , NULL );
555+ // Use probe_insert_module for automatic dependency resolution
556+ err = kmod_module_probe_insert_module (mod , KMOD_PROBE_APPLY_BLACKLIST | KMOD_PROBE_IGNORE_LOADED , NULL , NULL , NULL , NULL );
511557 if (err < 0 ) {
512558 kmod_module_unref (mod );
513559 return err ;
@@ -549,10 +595,14 @@ int parse_tree_entry(const char* fpath, const struct stat* sb, int typeflag) {
549595 // print warning if we fail to load the module, but don't fail fn so
550596 // we keep trying to load the rest of the modules.
551597 result = load_module (k_ctx , fpath );
598+ char msg [512 ];
552599 if (result != 0 ) {
553- warn2 ("failed to load module" , fpath );
600+ snprintf (msg , sizeof (msg ), "failed to load module %s (error %d)\n" , fpath , result );
601+ dmesgWarn (msg );
602+ } else {
603+ snprintf (msg , sizeof (msg ), "loaded module: %s\n" , fpath );
604+ dmesgInfo (msg );
554605 }
555- dmesgInfo (fpath );
556606 return 0 ;
557607}
558608
@@ -777,12 +827,21 @@ int main(int argc, char** argv) {
777827 init_network ("lo" , AF_INET6 );
778828
779829#ifdef MODULES
830+ // Preload networking modules by name before the general ftw()-based scan.
831+ // On Ubuntu, hv_netvsc and hv_sock are loadable (=m) not built-in (=y),
832+ // and load_all_modules() may not resolve them reliably by path alone.
833+ // Without hv_netvsc: hot-added NICs timeout. Without hv_sock: vsock fails.
834+ preload_networking_modules ();
835+
780836#ifdef DEBUG
781837 printf ("loading modules\n" );
782838#endif
783839 load_all_modules ();
784840#endif
785841
842+ // Initialize entropy after module loading: on distros where hv_sock is a
843+ // loadable module (e.g., Ubuntu), the vsock transport used by init_entropy
844+ // is not available until the module is loaded above.
786845 if (entropy_port != 0 ) {
787846 init_entropy (entropy_port );
788847 }
0 commit comments