1 /**
2  * Copyright © 2019 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "user_header.hpp"
17 
18 #include "json_utils.hpp"
19 #include "pel_types.hpp"
20 #include "pel_values.hpp"
21 #include "severity.hpp"
22 
23 #include <iostream>
24 #include <phosphor-logging/log.hpp>
25 
26 namespace openpower
27 {
28 namespace pels
29 {
30 
31 namespace pv = openpower::pels::pel_values;
32 using namespace phosphor::logging;
33 
34 void UserHeader::unflatten(Stream& stream)
35 {
36     stream >> _header >> _eventSubsystem >> _eventScope >> _eventSeverity >>
37         _eventType >> _reserved4Byte1 >> _problemDomain >> _problemVector >>
38         _actionFlags >> _states;
39 }
40 
41 void UserHeader::flatten(Stream& stream) const
42 {
43     stream << _header << _eventSubsystem << _eventScope << _eventSeverity
44            << _eventType << _reserved4Byte1 << _problemDomain << _problemVector
45            << _actionFlags << _states;
46 }
47 
48 UserHeader::UserHeader(const message::Entry& entry,
49                        phosphor::logging::Entry::Level severity,
50                        const DataInterfaceBase& dataIface)
51 {
52     _header.id = static_cast<uint16_t>(SectionID::userHeader);
53     _header.size = UserHeader::flattenedSize();
54     _header.version = userHeaderVersion;
55     _header.subType = 0;
56     _header.componentID = static_cast<uint16_t>(ComponentID::phosphorLogging);
57 
58     _eventSubsystem = entry.subsystem;
59 
60     _eventScope = entry.eventScope.value_or(
61         static_cast<uint8_t>(EventScope::entirePlatform));
62 
63     // Get the severity from the registry if it's there, otherwise get it
64     // from the OpenBMC event log severity value.
65     if (!entry.severity)
66     {
67         _eventSeverity = convertOBMCSeverityToPEL(severity);
68     }
69     else
70     {
71         // Find the severity possibly dependent on the system type.
72         auto sev = getSeverity(entry.severity.value(), dataIface);
73         if (sev)
74         {
75             _eventSeverity = *sev;
76         }
77         else
78         {
79             // Either someone  screwed up the message registry
80             // or getSystemNames failed.
81             std::string types;
82             log<level::ERR>(
83                 "Failed finding the severity in the message registry",
84                 phosphor::logging::entry("ERROR=%s", entry.name.c_str()));
85 
86             // Have to choose something, just use informational.
87             _eventSeverity = 0;
88         }
89     }
90 
91     // TODO: ibm-dev/dev/#1144 Handle manufacturing sev & action flags
92 
93     if (entry.eventType)
94     {
95         _eventType = *entry.eventType;
96     }
97     else
98     {
99         // There are different default event types for info errors
100         // vs non info ones.
101         auto sevType = static_cast<SeverityType>(_eventSeverity & 0xF0);
102 
103         _eventType = (sevType == SeverityType::nonError)
104                          ? static_cast<uint8_t>(EventType::miscInformational)
105                          : static_cast<uint8_t>(EventType::notApplicable);
106     }
107 
108     _reserved4Byte1 = 0;
109 
110     // No uses for problem domain or vector
111     _problemDomain = 0;
112     _problemVector = 0;
113 
114     // These will be set in pel_rules::check() if they're still
115     // at the default value.
116     _actionFlags = entry.actionFlags.value_or(actionFlagsDefault);
117 
118     _states = 0;
119 
120     _valid = true;
121 }
122 
123 UserHeader::UserHeader(Stream& pel)
124 {
125     try
126     {
127         unflatten(pel);
128         validate();
129     }
130     catch (const std::exception& e)
131     {
132         log<level::ERR>("Cannot unflatten user header",
133                         entry("ERROR=%s", e.what()));
134         _valid = false;
135     }
136 }
137 
138 void UserHeader::validate()
139 {
140     bool failed = false;
141     if (header().id != static_cast<uint16_t>(SectionID::userHeader))
142     {
143         log<level::ERR>("Invalid user header section ID",
144                         entry("ID=0x%X", header().id));
145         failed = true;
146     }
147 
148     if (header().version != userHeaderVersion)
149     {
150         log<level::ERR>("Invalid user header version",
151                         entry("VERSION=0x%X", header().version));
152         failed = true;
153     }
154 
155     _valid = (failed) ? false : true;
156 }
157 
158 std::optional<std::string> UserHeader::getJSON() const
159 {
160     std::string severity;
161     std::string subsystem;
162     std::string eventScope;
163     std::string eventType;
164     std::vector<std::string> actionFlags;
165     severity = pv::getValue(_eventSeverity, pel_values::severityValues);
166     subsystem = pv::getValue(_eventSubsystem, pel_values::subsystemValues);
167     eventScope = pv::getValue(_eventScope, pel_values::eventScopeValues);
168     eventType = pv::getValue(_eventType, pel_values::eventTypeValues);
169     actionFlags =
170         pv::getValuesBitwise(_actionFlags, pel_values::actionFlagsValues);
171 
172     std::string hostState{"Invalid"};
173     auto iter = pv::transmissionStates.find(
174         static_cast<TransmissionState>(hostTransmissionState()));
175     if (iter != pv::transmissionStates.end())
176     {
177         hostState = iter->second;
178     }
179 
180     std::string uh;
181     jsonInsert(uh, pv::sectionVer, getNumberString("%d", userHeaderVersion), 1);
182     jsonInsert(uh, pv::subSection, getNumberString("%d", _header.subType), 1);
183     jsonInsert(uh, "Log Committed by",
184                getNumberString("0x%X", _header.componentID), 1);
185     jsonInsert(uh, "Subsystem", subsystem, 1);
186     jsonInsert(uh, "Event Scope", eventScope, 1);
187     jsonInsert(uh, "Event Severity", severity, 1);
188     jsonInsert(uh, "Event Type", eventType, 1);
189     jsonInsertArray(uh, "Action Flags", actionFlags, 1);
190     jsonInsert(uh, "Host Transmission", hostState, 1);
191     uh.erase(uh.size() - 2);
192     return uh;
193 }
194 
195 std::optional<uint8_t> UserHeader::getSeverity(
196     const std::vector<message::RegistrySeverity>& severities,
197     const DataInterfaceBase& dataIface) const
198 {
199     const uint8_t* s = nullptr;
200     std::vector<std::string> systemNames;
201 
202     // getSystemNames makes D-Bus calls, so only call it if we
203     // know we'll need it because there is a system name in the sev list
204     if (std::any_of(severities.begin(), severities.end(),
205                     [](const auto& sev) { return !sev.system.empty(); }))
206     {
207         try
208         {
209             systemNames = dataIface.getSystemNames();
210         }
211         catch (const std::exception& e)
212         {
213             log<level::ERR>("Failed trying to look up system names on D-Bus",
214                             entry("ERROR=%s", e.what()));
215             return std::nullopt;
216         }
217     }
218 
219     // Find the severity to use for this system type, or use the default
220     // entry (where no system type is specified).
221     for (const auto& sev : severities)
222     {
223         if (std::find(systemNames.begin(), systemNames.end(), sev.system) !=
224             systemNames.end())
225         {
226             s = &sev.severity;
227             break;
228         }
229         else if (sev.system.empty())
230         {
231             s = &sev.severity;
232         }
233     }
234 
235     if (s)
236     {
237         return *s;
238     }
239 
240     return std::nullopt;
241 }
242 
243 } // namespace pels
244 } // namespace openpower
245