diff options
-rw-r--r-- | extensions/openpower-pels/host_notifier.cpp | 13 | ||||
-rw-r--r-- | extensions/openpower-pels/host_notifier.hpp | 12 | ||||
-rw-r--r-- | test/openpower-pels/host_notifier_test.cpp | 67 |
3 files changed, 92 insertions, 0 deletions
diff --git a/extensions/openpower-pels/host_notifier.cpp b/extensions/openpower-pels/host_notifier.cpp index ca30340..2e132b9 100644 --- a/extensions/openpower-pels/host_notifier.cpp +++ b/extensions/openpower-pels/host_notifier.cpp @@ -419,4 +419,17 @@ void HostNotifier::setHostFull(uint32_t id) } } +void HostNotifier::setBadPEL(uint32_t id) +{ + log<level::ERR>("PEL rejected by the host", entry("PEL_ID=0x%X", id)); + + auto sent = std::find(_sentPELs.begin(), _sentPELs.end(), id); + if (sent != _sentPELs.end()) + { + _sentPELs.erase(sent); + } + + _repo.setPELHostTransState(id, TransmissionState::badPEL); +} + } // namespace openpower::pels diff --git a/extensions/openpower-pels/host_notifier.hpp b/extensions/openpower-pels/host_notifier.hpp index 21bd072..01eac48 100644 --- a/extensions/openpower-pels/host_notifier.hpp +++ b/extensions/openpower-pels/host_notifier.hpp @@ -117,6 +117,18 @@ class HostNotifier */ void setHostFull(uint32_t id); + /** + * @brief Called when the host receives a malformed PEL. + * + * Ideally this will never happen, as the Repository + * class already purges malformed PELs. + * + * The PEL should never be sent up again. + * + * @param[in] id - The PEL ID + */ + void setBadPEL(uint32_t id); + private: /** * @brief This function gets called by the Repository class diff --git a/test/openpower-pels/host_notifier_test.cpp b/test/openpower-pels/host_notifier_test.cpp index cd30e8d..9bab030 100644 --- a/test/openpower-pels/host_notifier_test.cpp +++ b/test/openpower-pels/host_notifier_test.cpp @@ -746,3 +746,70 @@ TEST_F(HostNotifierTest, TestHostFull) EXPECT_EQ(mockHostIface.numCmdsProcessed(), 5); EXPECT_EQ(notifier.queueSize(), 0); } + +// Test when the host says it was send a malformed PEL +TEST_F(HostNotifierTest, TestBadPEL) +{ + MockDataInterface dataIface; + sdeventplus::Event sdEvent{event}; + + { + Repository repo{repoPath}; + + std::unique_ptr<HostInterface> hostIface = + std::make_unique<MockHostInterface>(event, dataIface); + + MockHostInterface& mockHostIface = + reinterpret_cast<MockHostInterface&>(*hostIface); + + HostNotifier notifier{repo, dataIface, std::move(hostIface)}; + + auto send = [&mockHostIface](uint32_t id, uint32_t size) { + return mockHostIface.send(0); + }; + + EXPECT_CALL(mockHostIface, sendNewLogCmd(_, _)) + .WillRepeatedly(Invoke(send)); + + dataIface.changeHostState(true); + + // Add a PEL and dispatch and send it + auto pel = makePEL(); + auto id = pel->id(); + repo.add(pel); + + runEvents(sdEvent, 2); + EXPECT_EQ(mockHostIface.numCmdsProcessed(), 1); + EXPECT_EQ(notifier.queueSize(), 0); + + // The host rejected it. + notifier.setBadPEL(id); + + // Doesn't go back on the queue + EXPECT_EQ(notifier.queueSize(), 0); + + // Check the state was saved in the PEL itself + Repository::LogID i{Repository::LogID::Pel{id}}; + auto data = repo.getPELData(i); + PEL pelFromRepo{*data}; + EXPECT_EQ(pelFromRepo.hostTransmissionState(), + TransmissionState::badPEL); + + dataIface.changeHostState(false); + + // Ensure it doesn't go back on the queue on a power cycle + EXPECT_EQ(notifier.queueSize(), 0); + } + + // Now restore the repo, and make sure it doesn't come back + { + Repository repo{repoPath}; + + std::unique_ptr<HostInterface> hostIface = + std::make_unique<MockHostInterface>(event, dataIface); + + HostNotifier notifier{repo, dataIface, std::move(hostIface)}; + + EXPECT_EQ(notifier.queueSize(), 0); + } +} |