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