blob: 50e46d87d6205fbc48ac93229603d45a97edb93a [file] [log] [blame]
Deepak Kodihalli70e8db02019-10-21 00:59:46 -05001#include "fru.hpp"
2
3#include "utils.hpp"
4
5#include <systemd/sd-journal.h>
6
Deepak Kodihalli70e8db02019-10-21 00:59:46 -05007#include <iostream>
8#include <sdbusplus/bus.hpp>
9#include <set>
10
George Liu077fea22020-04-08 16:47:14 +080011#include "libpldm/utils.h"
12
Deepak Kodihalli70e8db02019-10-21 00:59:46 -050013namespace pldm
14{
15
16namespace responder
17{
18
Deepak Kodihalli3cd61812020-03-10 06:38:45 -050019FruImpl::FruImpl(const std::string& configPath, pldm_pdr* pdrRepo,
20 pldm_entity_association_tree* entityTree) :
21 pdrRepo(pdrRepo),
22 entityTree(entityTree)
Deepak Kodihalli70e8db02019-10-21 00:59:46 -050023{
24 fru_parser::FruParser handle(configPath);
25
Tom Josephf0076332020-02-06 10:18:50 +053026 fru_parser::DBusLookupInfo dbusInfo;
Deepak Kodihalli70e8db02019-10-21 00:59:46 -050027 // Read the all the inventory D-Bus objects
28 auto& bus = pldm::utils::DBusHandler::getBus();
29 dbus::ObjectValueTree objects;
30
31 try
32 {
Tom Josephf0076332020-02-06 10:18:50 +053033 dbusInfo = handle.inventoryLookup();
Deepak Kodihalli70e8db02019-10-21 00:59:46 -050034 auto method = bus.new_method_call(
35 std::get<0>(dbusInfo).c_str(), std::get<1>(dbusInfo).c_str(),
36 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
37 auto reply = bus.call(method);
38 reply.read(objects);
39 }
40 catch (const std::exception& e)
41 {
42 std::cerr << "Look up of inventory objects failed and PLDM FRU table "
43 "creation failed";
44 return;
45 }
46
Deepak Kodihalli3cd61812020-03-10 06:38:45 -050047 auto itemIntfsLookup = std::get<2>(dbusInfo);
Deepak Kodihalli70e8db02019-10-21 00:59:46 -050048
49 for (const auto& object : objects)
50 {
51 const auto& interfaces = object.second;
52
53 for (const auto& interface : interfaces)
54 {
55 if (itemIntfsLookup.find(interface.first) != itemIntfsLookup.end())
56 {
57 // An exception will be thrown by getRecordInfo, if the item
58 // D-Bus interface name specified in FRU_Master.json does
59 // not have corresponding config jsons
60 try
61 {
Deepak Kodihalli3cd61812020-03-10 06:38:45 -050062 pldm_entity entity{};
63 entity.entity_type = handle.getEntityType(interface.first);
64 pldm_entity_node* parent = nullptr;
65 auto parentObj = pldm::utils::findParent(object.first.str);
66 // To add a FRU to the entity association tree, we need to
67 // determine if the FRU has a parent (D-Bus object). For eg
68 // /system/backplane's parent is /system. /system has no
69 // parent. Some D-Bus pathnames might just be namespaces
70 // (not D-Bus objects), so we need to iterate upwards until
71 // a parent is found, or we reach the root ("/").
72 // Parents are always added first before children in the
73 // entity association tree. We're relying on the fact that
74 // the std::map containing object paths from the
75 // GetManagedObjects call will have a sorted pathname list.
76 do
77 {
78 auto iter = objToEntityNode.find(parentObj);
79 if (iter != objToEntityNode.end())
80 {
81 parent = iter->second;
82 break;
83 }
84 parentObj = pldm::utils::findParent(parentObj);
85 } while (parentObj != "/");
86
87 auto node = pldm_entity_association_tree_add(
88 entityTree, &entity, parent,
89 PLDM_ENTITY_ASSOCIAION_PHYSICAL);
90 objToEntityNode[object.first.str] = node;
91
Deepak Kodihalli70e8db02019-10-21 00:59:46 -050092 auto recordInfos = handle.getRecordInfo(interface.first);
Deepak Kodihalli3cd61812020-03-10 06:38:45 -050093 populateRecords(interfaces, recordInfos, entity);
94 break;
Deepak Kodihalli70e8db02019-10-21 00:59:46 -050095 }
96 catch (const std::exception& e)
97 {
98 std::cout << "Config JSONs missing for the item "
99 "interface type, interface = "
100 << interface.first << "\n";
101 break;
102 }
103 }
104 }
105 }
106
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500107 pldm_entity_association_pdr_add(entityTree, pdrRepo, false);
Deepak Kodihalli3cd61812020-03-10 06:38:45 -0500108
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500109 if (table.size())
110 {
111 padBytes = utils::getNumPadBytes(table.size());
112 table.resize(table.size() + padBytes, 0);
113
114 // Calculate the checksum
George Liu077fea22020-04-08 16:47:14 +0800115 checksum = crc32(table.data(), table.size());
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500116 }
117}
118
119void FruImpl::populateRecords(
120 const pldm::responder::dbus::InterfaceMap& interfaces,
Deepak Kodihalli3cd61812020-03-10 06:38:45 -0500121 const fru_parser::FruRecordInfos& recordInfos, const pldm_entity& entity)
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500122{
123 // recordSetIdentifier for the FRU will be set when the first record gets
124 // added for the FRU
125 uint16_t recordSetIdentifier = 0;
126 auto numRecsCount = numRecs;
127
128 for (auto const& [recType, encType, fieldInfos] : recordInfos)
129 {
130 std::vector<uint8_t> tlvs;
131 uint8_t numFRUFields = 0;
132 for (auto const& [intf, prop, propType, fieldTypeNum] : fieldInfos)
133 {
134 try
135 {
136 auto propValue = interfaces.at(intf).at(prop);
137 if (propType == "bytearray")
138 {
139 auto byteArray = std::get<std::vector<uint8_t>>(propValue);
140 if (!byteArray.size())
141 {
142 continue;
143 }
144
145 numFRUFields++;
146 tlvs.emplace_back(fieldTypeNum);
147 tlvs.emplace_back(byteArray.size());
148 std::move(std::begin(byteArray), std::end(byteArray),
149 std::back_inserter(tlvs));
150 }
151 else if (propType == "string")
152 {
153 auto str = std::get<std::string>(propValue);
154 if (!str.size())
155 {
156 continue;
157 }
158
159 numFRUFields++;
160 tlvs.emplace_back(fieldTypeNum);
161 tlvs.emplace_back(str.size());
162 std::move(std::begin(str), std::end(str),
163 std::back_inserter(tlvs));
164 }
165 }
166 catch (const std::out_of_range& e)
167 {
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500168 continue;
169 }
170 }
171
172 if (tlvs.size())
173 {
174 if (numRecs == numRecsCount)
175 {
176 recordSetIdentifier = nextRSI();
Deepak Kodihalli3cd61812020-03-10 06:38:45 -0500177 pldm_pdr_add_fru_record_set(
178 pdrRepo, 0, recordSetIdentifier, entity.entity_type,
179 entity.entity_instance_num, entity.entity_container_id);
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500180 }
181 auto curSize = table.size();
182 table.resize(curSize + recHeaderSize + tlvs.size());
183 encode_fru_record(table.data(), table.size(), &curSize,
184 recordSetIdentifier, recType, numFRUFields,
185 encType, tlvs.data(), tlvs.size());
186 numRecs++;
187 }
188 }
189}
190
191void FruImpl::getFRUTable(Response& response)
192{
193 auto hdrSize = response.size();
194
195 response.resize(hdrSize + table.size() + sizeof(checksum), 0);
196 std::copy(table.begin(), table.end(), response.begin() + hdrSize);
197
198 // Copy the checksum to response data
199 auto iter = response.begin() + hdrSize + table.size();
200 std::copy_n(reinterpret_cast<const uint8_t*>(&checksum), sizeof(checksum),
201 iter);
202}
203
Deepak Kodihallie60c5822019-10-23 03:26:15 -0500204namespace fru
205{
206
207Response Handler::getFRURecordTableMetadata(const pldm_msg* request,
208 size_t /*payloadLength*/)
209{
210 constexpr uint8_t major = 0x01;
211 constexpr uint8_t minor = 0x00;
212 constexpr uint32_t maxSize = 0xFFFFFFFF;
213
214 Response response(sizeof(pldm_msg_hdr) +
215 PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES,
216 0);
217 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
218
219 auto rc = encode_get_fru_record_table_metadata_resp(
220 request->hdr.instance_id, PLDM_SUCCESS, major, minor, maxSize,
221 impl.size(), impl.numRSI(), impl.numRecords(), impl.checkSum(),
222 responsePtr);
223 if (rc != PLDM_SUCCESS)
224 {
225 return ccOnlyResponse(request, rc);
226 }
227
228 return response;
229}
230
231Response Handler::getFRURecordTable(const pldm_msg* request,
232 size_t payloadLength)
233{
234 if (payloadLength != PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES)
235 {
236 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
237 }
238
239 Response response(
240 sizeof(pldm_msg_hdr) + PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES, 0);
241 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
242
243 auto rc =
244 encode_get_fru_record_table_resp(request->hdr.instance_id, PLDM_SUCCESS,
245 0, PLDM_START_AND_END, responsePtr);
246 if (rc != PLDM_SUCCESS)
247 {
248 return ccOnlyResponse(request, rc);
249 }
250
251 impl.getFRUTable(response);
252
253 return response;
254}
255
256} // namespace fru
257
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500258} // namespace responder
259
260} // namespace pldm