Skip to content

Commit bd8ba4e

Browse files
committed
init: preload networking modules for Ubuntu support
On Ubuntu, hv_netvsc, hv_sock, bridge, and other networking modules are loadable (=m) rather than built-in (=y). The existing ftw()-based load_all_modules() may not resolve them reliably by path alone. Add preload_networking_modules() to load critical modules by name before the general module scan. Also enable KMOD=1 in the default Makefile and improve module load logging with structured messages. Without hv_netvsc: hot-added NICs timeout waiting for sysfs net interface. Without hv_sock: vsock-based entropy and GCS communication fail. Signed-off-by: Jie Chen <jiechen3@microsoft.com>
1 parent ce35a2a commit bd8ba4e

2 files changed

Lines changed: 63 additions & 4 deletions

File tree

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ include Makefile.bootfiles
33
# C settings
44

55
# enable loading kernel modules in init
6-
KMOD:=0
6+
KMOD:=1
77

88
CFLAGS:=-O2 -Wall
99
LDFLAGS:=-static -s #strip C binaries

init/init.c

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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
370415
void 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

Comments
 (0)