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