Skip to content

[Nexthop][bugfix] platform_manager: tolerate a failed BSP RPM query when the kmods are on disk - #1890

Open
sazeed-nexthop wants to merge 1 commit into
meta:mainfrom
nexthop-ai:sazeed.pm-tolerate-rpm-query-failure
Open

sazeed-nexthop wants to merge 1 commit into
meta:mainfrom
nexthop-ai:sazeed.pm-tolerate-rpm-query-failure

Conversation

@sazeed-nexthop

@sazeed-nexthop sazeed-nexthop commented Oct 31, 2026 •

Copy link
Copy Markdown

Pre-submission checklist

  • I've ran the linters locally and fixed lint errors related to the files I modified in this PR. You can install the linters by running pip install -r requirements-dev.txt && pre-commit install
  • pre-commit run

Summary

Problem

When a switch reboots with its root filesystem full, platform_manager aborts on every start until systemd gives up (StartLimitBurst). With platform_manager down, /run/devmap never appears, so led_service and qsfp_service crash-loop behind it and the box comes up with no platform management and no transceivers until an operator frees disk space by hand.

The abort is avoidable: the BSP kmods are already installed on disk. platform_manager only aborts because it cannot ask the package database whether they are, and it treats "could not ask" as "not installed".

Root cause

  • PkgManager::processAll() calls isRpmInstalled() and, on false, runs processRpms(): unload the kmods, remove installed RPMs, dnf install three times, throw on failure.
  • SystemInterface::isRpmInstalled() runs dnf list <rpm> --installed and returns exitStatus == 0. dnf exits 1 both for "no matching package" and for "rpmdb open failed", so a broken query is indistinguishable from a missing package.
  • rpm's sqlite backend runs a write transaction on open (CREATE TABLE IF NOT EXISTS 'Packages'). Measured on a Wedge800BNHP: rpm -q and dnf list --installed work at 128 KB free on / and die with SIGBUS (exit 135) at 64 KB. On such a boot every attempt in processRpms() also dies, it throws, and Main.cpp aborts via XLOG(FATAL).

Each platform_manager start on such a boot shows the same sequence in the journal: one dnf core (isRpmInstalled), one rpm core (removeInstalledRpms), three dnf cores (the install retries), then platform_manager itself dumps core.

Fix

  • SystemInterface::isRpmInstalled() returns std::optional<bool> and runs rpm -q <name> 2>&1 instead of dnf list --installed. Exit 0 with no error: text is installed; exit 1 with "is not installed" is not installed; anything else (an error: line about the rpmdb, a signal exit, a spawn failure) is unknown. The command goes through PlatformUtils so it can be mocked.
  • PkgManager::processAll() acts on unknown only when the running kernel's kmods.json is already on disk (bspKmodsOnDisk()): set the package_manager.process_rpm_failure counter, log an FBOSS_ALERT (bsp_rpm_query_failed), and proceed as installed, so the kmods it already has get loaded. If processRpms() throws while the kmods are on disk, log bsp_rpm_install_failed and continue instead of aborting. When the kmods are genuinely absent the behaviour is unchanged: the exception propagates and platform_manager aborts as before.
  • pkg_manager links structured_logger (cmake + BUCK).

Not changed: the unload/reload sequence after a real install, and --local_rpm_path handling.

Test Plan

Unit tests (gmock, pkg_manager_test)

  • SystemInterfaceTest.isRpmInstalled: installed, not installed, error: text with exit 1, exit 135 (SIGBUS), spawn failure.
  • PkgManagerTest: EnablePkgMgmntRpmQueryFailsWithKmodsOnDisk (kmods loaded, processRpms() never called), EnablePkgMgmntRpmQueryFailsWithoutKmods (falls through to the existing install path), EnablePkgMgmntInstallFailsWithKmodsOnDisk (continues and loads kmods), EnablePkgMgmntInstallFailsWithoutKmods (still throws).

Built on top of this branch with the OSS cmake build (fboss/oss/scripts/docker-build.py, platform_manager target plus a local-only test executable for the two test files) and run in the build container:

[==========] Running 31 tests from 3 test suites.
[  PASSED  ] 31 tests.

On hardware (Wedge800BNHP, Tomahawk5, kernel 6.11; / filled to 64 KB free with fallocate + dd, then reboot)

before after
platform_manager 5 aborts, systemd gives up active 4 s after start, 0 restarts
BSP kmods loaded 0 40
/run/devmap/xcvrs missing 66
led_service / qsfp_service crash-loop active
platform_manager cores 5 0

Free space stayed at 64 KB for the whole boot, so the rpm query failed exactly as in the stock image; the only difference is that platform_manager now carries on with the kmods it has.

A healthy boot with ample free space is unaffected: rpm -q answers installed and the existing path runs.

🤖 Generated with Claude Code

…kmods are on disk

PkgManager::processAll() asked "is the BSP kmods RPM installed?" with
`dnf list --installed` and treated any non-zero exit as "not installed".
dnf exits 1 both for "no matching package" and for "rpmdb open failed",
and on a root filesystem with <128 KB free it dies with SIGBUS (rpm's
sqlite backend runs a write transaction on open). So a query that merely
failed looked like a missing package: platform_manager unloaded the
working BSP kmods, retried `dnf install` three times against the same
unreadable rpmdb, and aborted via XLOG(FATAL). systemd then gave up after
StartLimitBurst, /run/devmap never appeared, and led_service and
qsfp_service crash-looped behind it.

SystemInterface::isRpmInstalled() now runs `rpm -q <name> 2>&1` and
returns std::optional<bool>: exit 0 without "error:" output is installed,
exit 1 with "is not installed" is not installed, anything else (an
"error:" line about the rpmdb, a signal exit, a spawn failure) is unknown.
The command goes through PlatformUtils so it can be mocked.

PkgManager::processAll() acts on unknown only when the running kernel's
kmods.json is already on disk: it sets package_manager.process_rpm_failure,
logs an FBOSS_ALERT (bsp_rpm_query_failed) and proceeds as installed, so
the kmods it already has get loaded. If processRpms() throws while the
kmods are on disk, it logs bsp_rpm_install_failed and continues instead of
aborting. When the kmods are genuinely absent the behaviour is unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@sazeed-nexthop
sazeed-nexthop requested review from a team as code owners October 31, 2026 09:59
@meta-cla meta-cla Bot added the CLA Signed label Oct 31, 2026
@github-actions github-actions Bot added nexthop project:bugfix FBOSS project: bugfix labels Oct 31, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant