1 /*
2 // Copyright (c) 2019 Intel 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
17 #pragma once
18 #include <boost/container/flat_map.hpp>
19 #include <ipmi_to_redfish_hooks.hpp>
20
21 namespace intel_oem::ipmi::sel::redfish_hooks::me
22 {
23 enum class EventSensor
24 {
25 MeFirmwareHealth = 23
26 };
27
28 enum class HealthEventType
29 {
30 FirmwareStatus = 0x00,
31 SmbusLinkFailure = 0x01
32 };
33
34 bool messageHook(const SELData& selData, const std::string& ipmiRaw);
35
36 namespace utils
37 {
38 // Maps event byte to human-readable message
39 using MessageMap = boost::container::flat_map<uint8_t, std::string>;
40 // Function which performs custom decoding for complex structures
41 using ParserFunc = std::function<bool(const SELData& selData, std::string&,
42 std::vector<std::string>&)>;
43 /**
44 * @brief Generic function for parsing IPMI Platform Events
45 *
46 * @param[in] map - maps EventData2 byte of IPMI Platform Event to decoder
47 * @param[in] selData - IPMI Platform Event
48 * @param[out] eventId - resulting Redfish Event ID
49 * @param[out] args - resulting Redfish Event Parameters
50 *
51 * @returns If matching event was found
52 */
genericMessageHook(const boost::container::flat_map<uint8_t,std::pair<std::string,std::optional<std::variant<ParserFunc,MessageMap>>>> & map,const SELData & selData,std::string & eventId,std::vector<std::string> & args)53 static inline bool genericMessageHook(
54 const boost::container::flat_map<
55 uint8_t,
56 std::pair<std::string,
57 std::optional<std::variant<ParserFunc, MessageMap>>>>& map,
58 const SELData& selData, std::string& eventId,
59 std::vector<std::string>& args)
60 {
61 const auto match = map.find(selData.eventData2);
62 if (match == map.end())
63 {
64 return false;
65 }
66
67 eventId = match->second.first;
68
69 auto details = match->second.second;
70 if (details)
71 {
72 if (std::holds_alternative<MessageMap>(*details))
73 {
74 const auto& detailsMap = std::get<MessageMap>(*details);
75 const auto translation = detailsMap.find(selData.eventData3);
76 if (translation == detailsMap.end())
77 {
78 return false;
79 }
80
81 args.push_back(translation->second);
82 }
83 else if (std::holds_alternative<ParserFunc>(*details))
84 {
85 const auto& parser = std::get<ParserFunc>(*details);
86 return parser(selData, eventId, args);
87 }
88 else
89 {
90 return false;
91 }
92 }
93
94 return true;
95 }
96
toHex(uint8_t byte)97 static inline std::string toHex(uint8_t byte)
98 {
99 std::stringstream ss;
100 ss << "0x" << std::hex << std::uppercase << std::setfill('0')
101 << std::setw(2) << static_cast<int>(byte);
102 return ss.str();
103 }
104
105 template <int idx>
106 static inline bool
logByte(const SELData & selData,std::string &,std::vector<std::string> & args,std::function<std::string (uint8_t)> conversion=nullptr)107 logByte(const SELData& selData, std::string& /* unused */,
108 std::vector<std::string>& args,
109 std::function<std::string(uint8_t)> conversion = nullptr)
110 {
111 uint8_t byte;
112 switch (idx)
113 {
114 case 0:
115 byte = selData.offset;
116 break;
117
118 case 1:
119 byte = selData.eventData2;
120 break;
121
122 case 2:
123 byte = selData.eventData3;
124 break;
125
126 default:
127 return false;
128 break;
129 }
130
131 if (conversion)
132 {
133 args.push_back(conversion(byte));
134 }
135 else
136 {
137 args.push_back(std::to_string(byte));
138 }
139
140 return true;
141 }
142
143 template <int idx>
logByteDec(const SELData & selData,std::string & unused,std::vector<std::string> & args)144 static inline bool logByteDec(const SELData& selData, std::string& unused,
145 std::vector<std::string>& args)
146 {
147 return logByte<idx>(selData, unused, args);
148 }
149
150 template <int idx>
logByteHex(const SELData & selData,std::string & unused,std::vector<std::string> & args)151 static inline bool logByteHex(const SELData& selData, std::string& unused,
152 std::vector<std::string>& args)
153 {
154 return logByte<idx>(selData, unused, args, toHex);
155 }
156
storeRedfishEvent(const std::string & ipmiRaw,const std::string & eventId,const std::vector<std::string> & args)157 static inline void storeRedfishEvent(const std::string& ipmiRaw,
158 const std::string& eventId,
159 const std::vector<std::string>& args)
160 {
161 static constexpr std::string_view openBMCMessageRegistryVer = "0.1";
162 std::string messageID =
163 "OpenBMC." + std::string(openBMCMessageRegistryVer) + "." + eventId;
164
165 // Log the Redfish message to the journal with the appropriate metadata
166 std::string journalMsg = "ME Event: " + ipmiRaw;
167 if (args.empty())
168 {
169 phosphor::logging::log<phosphor::logging::level::INFO>(
170 journalMsg.c_str(),
171 phosphor::logging::entry("REDFISH_MESSAGE_ID=%s",
172 messageID.c_str()));
173 }
174 else
175 {
176 std::string argsStr = boost::algorithm::join(args, ",");
177 phosphor::logging::log<phosphor::logging::level::INFO>(
178 journalMsg.c_str(),
179 phosphor::logging::entry("REDFISH_MESSAGE_ID=%s",
180 messageID.c_str()),
181 phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s",
182 argsStr.c_str()));
183 }
184 }
185 } // namespace utils
186 } // namespace intel_oem::ipmi::sel::redfish_hooks::me
187