Repository navigation
Real-BMC robustness: iLO 5 session revocation, iDRAC 8 retry pauses, one-way tags, OEM states (#145 #146 #147 #150) - #152
Conversation
…EM states Fixes four problems found by the lab survey of 2026-10-09 and the Codex review of #148. #146 - HP iLO 5 revokes a session (every command then fails with D4h) 120 s after it opens, and about 60 s after it when a Get Channel Authentication Capabilities or a Set Session Privilege Level is sent during the session. The keep-alive sent Get Channel Authentication Capabilities every 30 s, so the FRU walk (about 60 s on that iLO) failed half the time. The keep-alive is now a Get Device ID, as ipmitool sends, which leaves the session its 120 s. Resending the refused request in the same session never succeeds (61 tries over 22 s), so no same-session retry is added. A Get Sensor Reading refused with any completion code now costs only that sensor (WARN naming the host), not the whole walk. #147 - Dell iDRAC 8 answers C3h for its absent FRUs within 15-200 ms and loses about 1.5% of the replies, which succeed when sent again at once. The connector waited a random pause of up to idleTime (4 s) before every resend. It now resends at once after a lost reply or a C3h; the pause only follows the codes that say the BMC is busy. Every try takes a fresh tag: resending under the tag of a request that was just answered raced with the receiver releasing that tag, and could wait forever. The retry WARN is one line, without a stack trace. #150 - A one-way IPMI message is queued like any request (QueueElement carries a one-way flag), so its tag stays reserved until its reply or its timeout; its reply is dropped and its timeout not reported. The SOL ACK-only packets, which the BMC never acknowledges, keep an unqueued tag (SolMessageHandler.takeTag). Connection.KeepAlive, added in this release cycle, becomes private. #145 - Values the record decoders do not model (OEM or chassis-specific entity IDs, reserved device or sensor types, undefined states) are logged at DEBUG instead of ERROR or WARN. The event/reading types 70h-7Fh are OEM (ReadingType.isOem): their sensors report the raw state bytes, and an OEM sensor with no state asserted reports no state. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 283cdf35f0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // A fresh tag for every try: the request that timed out or was answered left the queue, or is about | ||
| // to, and a reply to the same tag would then be dropped as an orphan | ||
| int tag = asyncConnector.sendMessage(connectionHandle, request, !waitForResponse); |
There was a problem hiding this comment.
Reuse the request tag after a lost reply
When a reply is lost after the BMC has already executed a state-changing command, resending through sendMessage() assigns a new IPMI request sequence number, so the BMC treats it as a new request rather than a duplicate and may execute the operation twice. The existing MessageHandler.retryMessage() contract explicitly preserves the original tag for duplicate detection; the lost-reply path needs equivalent reservation/race handling, while retries after an actual transient response may still require a fresh tag.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
No change for this one: the lost-reply path already resends under a fresh tag on main, so this PR does not change it. Since #140, MessageQueue.processObsoleteMessage() removes a timed-out request and releases its tag before it notifies the listeners, so the retry(tag) that followed found no queued element (MessageHandler.retryMessage() returned -1) and sendMessage() took a new tag. The same happened after a C3h, once the 0-4 s pause had let the receiver remove the answered request. This PR only drops the same-tag resend in the remaining window, when the request was answered but not yet removed, where the resend could wait forever. Keeping the original tag across a lost reply, so that a BMC could recognize a duplicated state-changing command, would mean keeping timed-out requests queued, which #140 removed (#77/#78). That is a separate, pre-existing question and could be its own issue if wanted.
🤖 Addressed by Claude Code
…docs Second review pass on the fixes: - ConnectionTest checks that the keep-alive is queued as a one-way Get Device ID and released by its reply, and that one-way IPMI messages are queued while SOL ACK-only packets are not (it fails without the SolMessageHandler.takeTag override). - The one-way queue test uses a long timeout, so a slow machine cannot release the slot; the no-pause tests use a one-hour idleTime, so a reintroduced pause cannot pass by chance. - upgrading.md attributes the two-minute iDRAC 8 collections to the pauses combined with the 5 s timeout, and states that 1.2.02 did not reserve one-way tags; troubleshooting.md lists the per-sensor WARN and quotes the actual D4h message; the retry Javadoc counts the tries right. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Further lab runs with a dedicated iLO account showed that the D4h comes from sessions deleted by another client of the lab iLO (a management tool that deletes the IPMI sessions every two minutes): the iLO applies the deletion at a whole minute of the session's age, whatever the keep-alive command (a Get Device ID keep-alive session was revoked at 121 s too). The keep-alive stays a Get Device ID, as ipmitool sends, without the claim that Get Channel Authentication Capabilities shortens iLO sessions; troubleshooting describes the revoked-session symptom instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes #145, fixes #147, fixes #150. Refs #146 (see below).
The four real-BMC robustness issues from the lab survey and the Codex review of #148, in one PR as for the earlier clusters. All four touch the request path (connector, message handlers, queue, runners).
#146: HP iLO answers D4h in the middle of a walk
The issue suggested sending the Get SDR again. Low-level probes on the lab iLO (
ilo-hp-ceph, actually an iLO 5, ProLiant Gen10) show that this cannot work:metricshubaccount, sessions were still revoked at whole minutes of their age (61 s, 121.5 s, 182 s), whatever the keep-alive command. That tool probably deletes every session it can see.In this PR:
Connection.KeepAliveand is not needed for the iLO.0xD4on commands that worked earlier in the session).Branch runs on the iLO:
rootaccount: 3 of 4 collections succeeded (12 FRUs, 107 sensors). In the 4th, the session was revoked 62 s into the FRU walk.maincollections had its FRU walk revoked at 61 s.#147: Dell iDRAC 8 collections over two minutes
Probes with transport retries off show:
The cost was the random pause of up to
idleTime(4 s) before every resend, on top of the 5 s timeouts.Fix:
IpmiConnectorresends at once after a lost reply or a C3h. The pause stays for the codes that say the BMC is busy (node busy, out of resources, initialization in progress).FRU walk times with no lost reply in the run:
mainThe remaining time on a lossy iDRAC is the 5 s per-message timeout, which #101 would make configurable. Trade-off: without the pause, the 4 tries of a message cover about 21 s instead of about 27 s on average. Both versions failed one walk during a 50 s outage of an F200.
Not done: giving up a FRU on its first C3h (the issue's second suggestion). Retrying C3h without the pause costs less than 100 ms per FRU, so a special case isn't worth it.
#150: one-way messages hold their tag
MessageHandlerqueues a one-way IPMI message like any request (MessageQueue.add(request, oneWay),QueueElement.isOneWay()). Its tag stays reserved until its reply or its timeout. The reply is dropped and the timeout is not reported. Like any request, it takes one of the 8 slots of the window meanwhile.SolMessageHandler.takeTag): queueing them would fill the SOL window and stall the receive thread, which the review caught.Connection.KeepAlive, a public class added in this unreleased 1.2.03 cycle (Fix the connection and manager lifecycle (#126, #94, #95, #98) #148), becomes a private Get Device ID coder.#145: OEM and reserved codes logged as errors; 70h-7Eh not OEM
EntityId,DeviceType,SensorType,SensorUnit,ChassisType,FruMultiRecordType,ManagementAccessRecordTypeandReadingType. The returned values do not change, so the text output does not change either.70h-7Fhare OEM (Table 42-1,ReadingType.isOem()):name=0xHHLL), wheremainprintedname=Unknown;ReadingType.parseInt(), and sogetStatesAsserted()and the SEL record event, returnsUnknownOEMEventfor these types.Lab regression test (all 40 cards)
Each card ran chassis status (login),
getFrus(),getSensors()and the text conversion, once onmain(fdd1738) and once on this branch:mainonly in the intended OEM states (DDR4_P1_AB_PRS=0x8009instead ofUnknown,Err Reg Pointer=0x8001,vFlash=0x8021), apart from reading drift.Review
A review in six lenses, with an independent verifier per finding, confirmed 17 findings, fixed in this PR: the SOL ACK queueing, the same-tag resend race, idle OEM sensors, and several doc corrections. One correction is pre-existing: the D4h enum constant is spelled
InsufficentPrivilege, notInsufficientPrivilegeas the docs said. A second pass on these fixes confirmed 8 minor findings (tests that could pass by chance or did not pin the one-way routing, doc wording), fixed in the second commit.Found along the way and filed separately: #151, sensor and FRU names that carry the NUL padding of their SDR record (iRMC, iLO, Supermicro).
Tests
mvn verify: 113 tests; checkstyle, PMD, CPD and SpotBugs clean.70h-7Fh, active and idle;🤖 Generated with Claude Code