blob: 4bdeda528ae327c4661cbd67e868710af4a5d7f2 [file] [log] [blame]
Tom Joseph250c4752020-04-15 10:32:45 +05301#include "dbus_to_host_effecters.hpp"
2
3#include "libpldm/pdr.h"
4#include "libpldm/platform.h"
5#include "libpldm/requester/pldm.h"
6
7#include <xyz/openbmc_project/Common/error.hpp>
8#include <xyz/openbmc_project/State/OperatingSystem/Status/server.hpp>
9
10#include <fstream>
11#include <iostream>
12
13namespace pldm
14{
15namespace host_effecters
16{
17
18using InternalFailure =
19 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
20
21constexpr auto hostEffecterJson = "dbus_to_host_effecter.json";
22
23void HostEffecterParser::populatePropVals(
24 const Json& dBusValues, std::vector<PropertyValue>& propertyValues,
25 const std::string& propertyType)
26
27{
28 for (const auto& elem : dBusValues)
29 {
30 auto value = jsonEntryToDbusVal(propertyType, elem);
31 propertyValues.emplace_back(value);
32 }
33}
34
35void HostEffecterParser::parseEffecterJson(const std::string& jsonPath)
36{
37 fs::path jsonDir(jsonPath);
38 if (!fs::exists(jsonDir) || fs::is_empty(jsonDir))
39 {
40 std::cerr << "Host Effecter json path does not exist, DIR=" << jsonPath
41 << "\n";
42 return;
43 }
44
45 fs::path jsonFilePath = jsonDir / hostEffecterJson;
46 if (!fs::exists(jsonFilePath))
47 {
48 std::cerr << "json does not exist, PATH=" << jsonFilePath << "\n";
49 throw InternalFailure();
50 }
51
52 std::ifstream jsonFile(jsonFilePath);
53 auto data = Json::parse(jsonFile, nullptr, false);
54 if (data.is_discarded())
55 {
56 std::cerr << "Parsing json file failed, FILE=" << jsonFilePath << "\n";
57 throw InternalFailure();
58 }
59 const Json empty{};
60 const std::vector<Json> emptyList{};
61
62 auto entries = data.value("entries", emptyList);
63 for (const auto& entry : entries)
64 {
65 EffecterInfo effecterInfo;
66 effecterInfo.mctpEid = entry.value("mctp_eid", 0xFF);
67 auto jsonEffecterInfo = entry.value("effecter_info", empty);
68 auto effecterId =
69 jsonEffecterInfo.value("effecterID", PLDM_INVALID_EFFECTER_ID);
70 effecterInfo.containerId = jsonEffecterInfo.value("containerID", 0);
71 effecterInfo.entityType = jsonEffecterInfo.value("entityType", 0);
72 effecterInfo.entityInstance =
73 jsonEffecterInfo.value("entityInstance", 0);
74 effecterInfo.compEffecterCnt =
75 jsonEffecterInfo.value("compositeEffecterCount", 0);
76 auto effecters = entry.value("effecters", emptyList);
77 for (const auto& effecter : effecters)
78 {
79 DBusEffecterMapping dbusInfo{};
80 auto jsonDbusInfo = effecter.value("dbus_info", empty);
81 dbusInfo.dbusMap.objectPath = jsonDbusInfo.value("object_path", "");
82 dbusInfo.dbusMap.interface = jsonDbusInfo.value("interface", "");
83 dbusInfo.dbusMap.propertyName =
84 jsonDbusInfo.value("property_name", "");
85 dbusInfo.dbusMap.propertyType =
86 jsonDbusInfo.value("property_type", "");
87 Json propertyValues = jsonDbusInfo["property_values"];
88
89 populatePropVals(propertyValues, dbusInfo.propertyValues,
90 dbusInfo.dbusMap.propertyType);
91
92 const std::vector<uint8_t> emptyStates{};
93 auto state = effecter.value("state", empty);
94 dbusInfo.state.stateSetId = state.value("id", 0);
95 auto states = state.value("state_values", emptyStates);
96 if (dbusInfo.propertyValues.size() != states.size())
97 {
98 std::cerr << "Number of states do not match with"
99 << " number of D-Bus property values in the json. "
100 << "Object path " << dbusInfo.dbusMap.objectPath
101 << " and property " << dbusInfo.dbusMap.propertyName
102 << " will not be monitored \n";
103 continue;
104 }
105 for (const auto& s : states)
106 {
107 dbusInfo.state.states.emplace_back(s);
108 }
109
110 auto effecterInfoIndex = hostEffecterInfo.size();
111 auto dbusInfoIndex = effecterInfo.dbusInfo.size();
112 createHostEffecterMatch(
113 dbusInfo.dbusMap.objectPath, dbusInfo.dbusMap.interface,
114 effecterInfoIndex, dbusInfoIndex, effecterId);
115 effecterInfo.dbusInfo.emplace_back(std::move(dbusInfo));
116 }
117 hostEffecterInfo.emplace_back(std::move(effecterInfo));
118 }
119}
120
121void HostEffecterParser::processHostEffecterChangeNotification(
122 const DbusChgHostEffecterProps& chProperties, size_t effecterInfoIndex,
123 size_t dbusInfoIndex, uint16_t effecterId)
124{
125 const auto& propertyName = hostEffecterInfo[effecterInfoIndex]
126 .dbusInfo[dbusInfoIndex]
127 .dbusMap.propertyName;
128
129 const auto& it = chProperties.find(propertyName);
130
131 if (it == chProperties.end())
132 {
133 return;
134 }
135
136 if (effecterId == PLDM_INVALID_EFFECTER_ID)
137 {
Sampa Misraa4a96162020-07-14 05:33:46 -0500138 constexpr auto localOrRemote = false;
Tom Joseph250c4752020-04-15 10:32:45 +0530139 effecterId = findStateEffecterId(
140 pdrRepo, hostEffecterInfo[effecterInfoIndex].entityType,
141 hostEffecterInfo[effecterInfoIndex].entityInstance,
142 hostEffecterInfo[effecterInfoIndex].containerId,
143 hostEffecterInfo[effecterInfoIndex]
144 .dbusInfo[dbusInfoIndex]
Sampa Misraa4a96162020-07-14 05:33:46 -0500145 .state.stateSetId,
146 localOrRemote);
Tom Joseph250c4752020-04-15 10:32:45 +0530147 if (effecterId == PLDM_INVALID_EFFECTER_ID)
148 {
149 std::cerr << "Effecter id not found in pdr repo \n";
150 return;
151 }
152 }
153 constexpr auto hostStateInterface =
Tom Joseph5dad5f42020-12-08 18:23:42 +0530154 "xyz.openbmc_project.State.Boot.Progress";
Tom Joseph250c4752020-04-15 10:32:45 +0530155 constexpr auto hostStatePath = "/xyz/openbmc_project/state/host0";
156
157 try
158 {
159 auto propVal = dbusHandler->getDbusPropertyVariant(
Tom Joseph5dad5f42020-12-08 18:23:42 +0530160 hostStatePath, "BootProgress", hostStateInterface);
Tom Joseph250c4752020-04-15 10:32:45 +0530161 const auto& currHostState = std::get<std::string>(propVal);
Tom Joseph5dad5f42020-12-08 18:23:42 +0530162 if ((currHostState != "xyz.openbmc_project.State.Boot.Progress."
163 "ProgressStages.SystemInitComplete") &&
164 (currHostState != "xyz.openbmc_project.State.Boot.Progress."
165 "ProgressStages.OSRunning") &&
166 (currHostState != "xyz.openbmc_project.State.Boot.Progress."
167 "ProgressStages.OSStart"))
Tom Joseph250c4752020-04-15 10:32:45 +0530168 {
169 std::cout << "Host is not up. Current host state: "
170 << currHostState.c_str() << "\n";
171 return;
172 }
173 }
174 catch (const sdbusplus::exception::SdBusError& e)
175 {
176 std::cerr << "Error in getting current host state. Will still "
177 "continue to set the host effecter \n";
178 }
179 uint8_t newState{};
180 try
181 {
182 newState =
183 findNewStateValue(effecterInfoIndex, dbusInfoIndex, it->second);
184 }
185 catch (const std::out_of_range& e)
186 {
187 std::cerr << "new state not found in json"
188 << "\n";
189 return;
190 }
191
192 std::vector<set_effecter_state_field> stateField;
193 for (uint8_t i = 0; i < hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
194 i++)
195 {
196 if (i == dbusInfoIndex)
197 {
198 stateField.push_back({PLDM_REQUEST_SET, newState});
199 }
200 else
201 {
202 stateField.push_back({PLDM_NO_CHANGE, 0});
203 }
204 }
205 int rc{};
206 try
207 {
208 rc = setHostStateEffecter(effecterInfoIndex, stateField, effecterId);
209 }
210 catch (const std::runtime_error& e)
211 {
212 std::cerr << "Could not set host state effecter \n";
213 return;
214 }
215 if (rc != PLDM_SUCCESS)
216 {
217 std::cerr << "Could not set the host state effecter, rc= " << rc
218 << " \n";
219 }
220}
221
222uint8_t
223 HostEffecterParser::findNewStateValue(size_t effecterInfoIndex,
224 size_t dbusInfoIndex,
225 const PropertyValue& propertyValue)
226{
227 const auto& propValues = hostEffecterInfo[effecterInfoIndex]
228 .dbusInfo[dbusInfoIndex]
229 .propertyValues;
230 auto it = std::find(propValues.begin(), propValues.end(), propertyValue);
231 uint8_t newState{};
232 if (it != propValues.end())
233 {
234 auto index = std::distance(propValues.begin(), it);
235 newState = hostEffecterInfo[effecterInfoIndex]
236 .dbusInfo[dbusInfoIndex]
237 .state.states[index];
238 }
239 else
240 {
241 throw std::out_of_range("new state not found in json");
242 }
243 return newState;
244}
245
246int HostEffecterParser::setHostStateEffecter(
247 size_t effecterInfoIndex, std::vector<set_effecter_state_field>& stateField,
248 uint16_t effecterId)
249{
250 uint8_t& mctpEid = hostEffecterInfo[effecterInfoIndex].mctpEid;
251 uint8_t& compEffCnt = hostEffecterInfo[effecterInfoIndex].compEffecterCnt;
252 auto instanceId = requester->getInstanceId(mctpEid);
253
254 std::vector<uint8_t> requestMsg(
255 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(compEffCnt) +
256 sizeof(set_effecter_state_field) * compEffCnt,
257 0);
258 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
259 auto rc = encode_set_state_effecter_states_req(
260 instanceId, effecterId, compEffCnt, stateField.data(), request);
261
262 if (rc != PLDM_SUCCESS)
263 {
264 std::cerr << "Message encode failure. PLDM error code = " << std::hex
265 << std::showbase << rc << "\n";
266 requester->markFree(mctpEid, instanceId);
267 return rc;
268 }
269
270 if (verbose)
271 {
272 if (requestMsg.size())
273 {
274 std::ostringstream tempStream;
275 for (int byte : requestMsg)
276 {
277 tempStream << std::setfill('0') << std::setw(2) << std::hex
278 << byte << " ";
279 }
280 std::cout << tempStream.str() << std::endl;
281 }
282 }
283
284 uint8_t* responseMsg = nullptr;
285 size_t responseMsgSize{};
286
287 rc = pldm_send_recv(mctpEid, sockFd, requestMsg.data(), requestMsg.size(),
288 &responseMsg, &responseMsgSize);
289 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
290 std::free};
291 requester->markFree(mctpEid, instanceId);
292
293 if (rc != PLDM_REQUESTER_SUCCESS)
294 {
295 std::cerr << "Failed to send message/receive response. RC = " << rc
296 << ", errno = " << errno << " for setting host effecter "
297 << effecterId << "\n";
298 pldm::utils::reportError(
299 "xyz.openbmc_project.bmc.pldm.InternalFailure");
300 return rc;
301 }
302 auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get());
303 uint8_t completionCode{};
304 rc = decode_set_state_effecter_states_resp(
305 responsePtr, responseMsgSize - sizeof(pldm_msg_hdr), &completionCode);
306 if (rc != PLDM_SUCCESS)
307 {
308 std::cerr << "Failed to decode setStateEffecterStates response, rc = "
309 << rc << "\n";
310 return rc;
311 }
312 if (completionCode != PLDM_SUCCESS)
313 {
314 std::cerr << "Failed setStateEffecterStates for effecter " << effecterId
315 << ". Response from Host " << (uint32_t)completionCode
316 << "\n";
317 pldm::utils::reportError(
318 "xyz.openbmc_project.bmc.pldm.InternalFailure");
319 }
320 return rc;
321}
322
323void HostEffecterParser::createHostEffecterMatch(const std::string& objectPath,
324 const std::string& interface,
325 size_t effecterInfoIndex,
326 size_t dbusInfoIndex,
327 uint16_t effecterId)
328{
329 using namespace sdbusplus::bus::match::rules;
330 effecterInfoMatch.emplace_back(
331 std::make_unique<sdbusplus::bus::match::match>(
332 pldm::utils::DBusHandler::getBus(),
333 propertiesChanged(objectPath, interface),
334 [this, effecterInfoIndex, dbusInfoIndex,
335 effecterId](sdbusplus::message::message& msg) {
336 DbusChgHostEffecterProps props;
337 std::string iface;
338 msg.read(iface, props);
339 processHostEffecterChangeNotification(
340 props, effecterInfoIndex, dbusInfoIndex, effecterId);
341 }));
342}
343
344} // namespace host_effecters
345} // namespace pldm