/** * Copyright © 2019 IBM Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "user_header.hpp" #include "json_utils.hpp" #include "pel_types.hpp" #include "pel_values.hpp" #include "severity.hpp" #include #include namespace openpower { namespace pels { namespace pv = openpower::pels::pel_values; using namespace phosphor::logging; void UserHeader::unflatten(Stream& stream) { stream >> _header >> _eventSubsystem >> _eventScope >> _eventSeverity >> _eventType >> _reserved4Byte1 >> _problemDomain >> _problemVector >> _actionFlags >> _states; } void UserHeader::flatten(Stream& stream) const { stream << _header << _eventSubsystem << _eventScope << _eventSeverity << _eventType << _reserved4Byte1 << _problemDomain << _problemVector << _actionFlags << _states; } UserHeader::UserHeader(const message::Entry& entry, phosphor::logging::Entry::Level severity, const AdditionalData& additionalData, const DataInterfaceBase& dataIface) { _header.id = static_cast(SectionID::userHeader); _header.size = UserHeader::flattenedSize(); _header.version = userHeaderVersion; _header.subType = 0; _header.componentID = static_cast(ComponentID::phosphorLogging); _eventSubsystem = entry.subsystem; _eventScope = entry.eventScope.value_or( static_cast(EventScope::entirePlatform)); // Get the severity from the registry if it's there, otherwise get it // from the OpenBMC event log severity value. if (!entry.severity) { _eventSeverity = convertOBMCSeverityToPEL(severity); } else { // Find the severity possibly dependent on the system type. auto sev = getSeverity(entry.severity.value(), dataIface); if (sev) { _eventSeverity = *sev; } else { // Either someone screwed up the message registry // or getSystemNames failed. std::string types; log( "Failed finding the severity in the message registry", phosphor::logging::entry("ERROR=%s", entry.name.c_str())); // Have to choose something, just use informational. _eventSeverity = 0; } } // Convert Critical error (0x50) to Critical Error-System Termination // (0x51), if the AdditionalData is set to SYSTEM_TERM auto sevLevel = additionalData.getValue("SEVERITY_DETAIL"); if ((_eventSeverity & 0xF0) == 0x50) { if (sevLevel.value_or("") == "SYSTEM_TERM") { // Change to Critical Error, System Termination _eventSeverity = 0x51; } } // TODO: ibm-dev/dev/#1144 Handle manufacturing sev & action flags if (entry.eventType) { _eventType = *entry.eventType; } else { // There are different default event types for info errors // vs non info ones. auto sevType = static_cast(_eventSeverity & 0xF0); _eventType = (sevType == SeverityType::nonError) ? static_cast(EventType::miscInformational) : static_cast(EventType::notApplicable); } _reserved4Byte1 = 0; // No uses for problem domain or vector _problemDomain = 0; _problemVector = 0; // These will be set in pel_rules::check() if they're still // at the default value. _actionFlags = entry.actionFlags.value_or(actionFlagsDefault); _states = 0; _valid = true; } UserHeader::UserHeader(Stream& pel) { try { unflatten(pel); validate(); } catch (const std::exception& e) { log("Cannot unflatten user header", entry("ERROR=%s", e.what())); _valid = false; } } void UserHeader::validate() { bool failed = false; if (header().id != static_cast(SectionID::userHeader)) { log("Invalid user header section ID", entry("ID=0x%X", header().id)); failed = true; } if (header().version != userHeaderVersion) { log("Invalid user header version", entry("VERSION=0x%X", header().version)); failed = true; } _valid = (failed) ? false : true; } std::optional UserHeader::getJSON() const { std::string severity; std::string subsystem; std::string eventScope; std::string eventType; std::vector actionFlags; severity = pv::getValue(_eventSeverity, pel_values::severityValues); subsystem = pv::getValue(_eventSubsystem, pel_values::subsystemValues); eventScope = pv::getValue(_eventScope, pel_values::eventScopeValues); eventType = pv::getValue(_eventType, pel_values::eventTypeValues); actionFlags = pv::getValuesBitwise(_actionFlags, pel_values::actionFlagsValues); std::string hostState{"Invalid"}; auto iter = pv::transmissionStates.find( static_cast(hostTransmissionState())); if (iter != pv::transmissionStates.end()) { hostState = iter->second; } std::string uh; jsonInsert(uh, pv::sectionVer, getNumberString("%d", userHeaderVersion), 1); jsonInsert(uh, pv::subSection, getNumberString("%d", _header.subType), 1); jsonInsert(uh, "Log Committed by", getNumberString("0x%X", _header.componentID), 1); jsonInsert(uh, "Subsystem", subsystem, 1); jsonInsert(uh, "Event Scope", eventScope, 1); jsonInsert(uh, "Event Severity", severity, 1); jsonInsert(uh, "Event Type", eventType, 1); jsonInsertArray(uh, "Action Flags", actionFlags, 1); jsonInsert(uh, "Host Transmission", hostState, 1); uh.erase(uh.size() - 2); return uh; } std::optional UserHeader::getSeverity( const std::vector& severities, const DataInterfaceBase& dataIface) const { const uint8_t* s = nullptr; std::vector systemNames; // getSystemNames makes D-Bus calls, so only call it if we // know we'll need it because there is a system name in the sev list if (std::any_of(severities.begin(), severities.end(), [](const auto& sev) { return !sev.system.empty(); })) { try { systemNames = dataIface.getSystemNames(); } catch (const std::exception& e) { log("Failed trying to look up system names on D-Bus", entry("ERROR=%s", e.what())); return std::nullopt; } } // Find the severity to use for this system type, or use the default // entry (where no system type is specified). for (const auto& sev : severities) { if (std::find(systemNames.begin(), systemNames.end(), sev.system) != systemNames.end()) { s = &sev.severity; break; } else if (sev.system.empty()) { s = &sev.severity; } } if (s) { return *s; } return std::nullopt; } } // namespace pels } // namespace openpower