diff options
Diffstat (limited to 'python/vyos/utils/kernel.py')
-rw-r--r-- | python/vyos/utils/kernel.py | 77 |
1 files changed, 76 insertions, 1 deletions
diff --git a/python/vyos/utils/kernel.py b/python/vyos/utils/kernel.py index 1f3bbdffe..847f80108 100644 --- a/python/vyos/utils/kernel.py +++ b/python/vyos/utils/kernel.py @@ -1,4 +1,4 @@ -# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -36,3 +36,78 @@ def unload_kmod(k_mod): if os.path.exists(f'/sys/module/{module}'): if call(f'rmmod {module}') != 0: raise ConfigError(f'Unloading Kernel module {module} failed') + +def list_loaded_modules(): + """ Returns the list of currently loaded kernel modules """ + from os import listdir + return listdir('/sys/module/') + +def get_module_data(module: str): + """ Retrieves information about a module """ + from os import listdir + from os.path import isfile, dirname, basename, join + from vyos.utils.file import read_file + + def _get_file(path): + # Some files inside some modules are not readable at all, + # we just skip them. + try: + return read_file(path) + except PermissionError: + return None + + mod_path = join('/sys/module', module) + mod_data = {"name": module, "fields": {}, "parameters": {}} + + for f in listdir(mod_path): + if f in ["sections", "notes", "uevent"]: + # The uevent file is not readable + # and module build info and memory layout + # in notes and sections generally aren't useful + # for anything but kernel debugging. + pass + elif f == "drivers": + # Drivers are dir symlinks, + # we just list them + drivers = listdir(join(mod_path, f)) + if drivers: + mod_data["drivers"] = drivers + elif f == "holders": + # Holders (module that use this one) + # are always symlink to other modules. + # We only need the list. + holders = listdir(join(mod_path, f)) + if holders: + mod_data["holders"] = holders + elif f == "parameters": + # Many modules keep their configuration + # in the "parameters" subdir. + ppath = join(mod_path, "parameters") + ps = listdir(ppath) + for p in ps: + data = _get_file(join(ppath, p)) + if data: + mod_data["parameters"][p] = data + else: + # Everything else... + # There are standard fields like refcount and initstate, + # but many modules also keep custom information or settings + # in top-level fields. + # For now we don't separate well-known and custom fields. + if isfile(join(mod_path, f)): + data = _get_file(join(mod_path, f)) + if data: + mod_data["fields"][f] = data + else: + raise RuntimeError(f"Unexpected directory inside module {module}: {f}") + + return mod_data + +def lsmod(): + """ Returns information about all loaded modules. + Like lsmod(8), but more detailed. + """ + mods_data = [] + for m in list_loaded_modules(): + mods_data.append(get_module_data(m)) + return mods_data |