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