Make PLDM an optional feature for host dump offload

Host dumps are dumps which created and stored in the host
but offloaded through BMC.
With this change if the host dump needs to de downloaded
the transport mechanism also needs to be provided
    --with-host-dump-offload-transport=<transport>
for eg:
    --with-host-dump-offload-transport=pldm
If no options provided the phosphor-dump-manager will be built
with no host dump offload support and an exception will be thrown
if someone tried to call the host dump offload function.

Signed-off-by: Dhruvaraj Subhashchandran <dhruvaraj@in.ibm.com>
Change-Id: I27311427d8ca8b06b9f33ff5f42bdc7ca87fdcd1
diff --git a/offload-extensions/default/default.cpp b/offload-extensions/default/default.cpp
new file mode 100644
index 0000000..6a14fdc
--- /dev/null
+++ b/offload-extensions/default/default.cpp
@@ -0,0 +1,17 @@
+#include <cstdint>
+#include <stdexcept>
+
+namespace phosphor
+{
+namespace dump
+{
+namespace host
+{
+void requestOffload(uint32_t id)
+{
+    throw std::runtime_error("Hostdump offload method not specified");
+}
+
+} // namespace host
+} // namespace dump
+} // namespace phosphor
diff --git a/offload-extensions/default/default.mk b/offload-extensions/default/default.mk
new file mode 100644
index 0000000..5774fd5
--- /dev/null
+++ b/offload-extensions/default/default.mk
@@ -0,0 +1,2 @@
+phosphor_dump_manager_SOURCES += \
+       offload-extensions/default/default.cpp
diff --git a/offload-extensions/extensions.mk b/offload-extensions/extensions.mk
new file mode 100644
index 0000000..b663f62
--- /dev/null
+++ b/offload-extensions/extensions.mk
@@ -0,0 +1,7 @@
+if ENABLE_PLDM_OFFLOAD
+include offload-extensions/pldm/pldm.mk
+endif
+
+if DEFAULT_HOST_OFFLOAD
+include offload-extensions/default/default.mk
+endif
diff --git a/offload-extensions/pldm/pldm.mk b/offload-extensions/pldm/pldm.mk
new file mode 100644
index 0000000..c136fbb
--- /dev/null
+++ b/offload-extensions/pldm/pldm.mk
@@ -0,0 +1,12 @@
+noinst_HEADERS += \
+        offload-extensions/pldm/pldm_interface.hpp
+
+phosphor_dump_manager_LDADD += \
+	$(LIBPLDM_LIBS)
+
+phosphor_dump_manager_CXXFLAGS += \
+        $(LIBPLDM_CFLAGS)
+
+phosphor_dump_manager_SOURCES += \
+       offload-extensions/pldm/pldm_interface.cpp
+
diff --git a/offload-extensions/pldm/pldm_interface.cpp b/offload-extensions/pldm/pldm_interface.cpp
new file mode 100644
index 0000000..dfff103
--- /dev/null
+++ b/offload-extensions/pldm/pldm_interface.cpp
@@ -0,0 +1,180 @@
+/**
+ * Copyright © 2019 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "pldm_interface.hpp"
+
+#include "dump_utils.hpp"
+#include "xyz/openbmc_project/Common/error.hpp"
+
+#include <libpldm/base.h>
+#include <libpldm/platform.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/bus.hpp>
+
+namespace phosphor
+{
+namespace dump
+{
+namespace host
+{
+/**
+ * @brief Initiate offload of the dump with provided id
+ *
+ * @param[in] id - The Dump Source ID.
+ *
+ */
+void requestOffload(uint32_t id)
+{
+    pldm::requestOffload(id);
+}
+} // namespace host
+
+namespace pldm
+{
+
+using namespace phosphor::logging;
+
+constexpr auto eidPath = "/usr/share/pldm/host_eid";
+constexpr mctp_eid_t defaultEIDValue = 9;
+
+using InternalFailure =
+    sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
+
+void closeFD(int fd)
+{
+    if (fd >= 0)
+    {
+        close(fd);
+    }
+}
+
+mctp_eid_t readEID()
+{
+    mctp_eid_t eid = defaultEIDValue;
+
+    std::ifstream eidFile{eidPath};
+    if (!eidFile.good())
+    {
+        log<level::ERR>("Could not open host EID file");
+        elog<InternalFailure>();
+    }
+    else
+    {
+        std::string eid;
+        eidFile >> eid;
+        if (!eid.empty())
+        {
+            eid = strtol(eid.c_str(), nullptr, 10);
+        }
+        else
+        {
+            log<level::ERR>("EID file was empty");
+            elog<InternalFailure>();
+        }
+    }
+
+    return eid;
+}
+
+int open()
+{
+    auto fd = pldm_open();
+    if (fd < 0)
+    {
+        auto e = errno;
+        log<level::ERR>("pldm_open failed", entry("ERRNO=%d", e),
+                        entry("FD=%d\n", fd));
+        elog<InternalFailure>();
+    }
+    return fd;
+}
+
+void requestOffload(uint32_t id)
+{
+    uint16_t effecterId = 0x05; // TODO PhyP temporary Hardcoded value.
+
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(id) +
+                            sizeof(uint8_t)>
+        requestMsg{};
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    std::array<uint8_t, sizeof(id)> effecterValue{};
+
+    memcpy(effecterValue.data(), &id, sizeof(id));
+
+    mctp_eid_t eid = readEID();
+
+    auto instanceID = getPLDMInstanceID(eid);
+
+    auto rc = encode_set_numeric_effecter_value_req(
+        instanceID, effecterId, PLDM_EFFECTER_DATA_SIZE_UINT32,
+        effecterValue.data(), request,
+        requestMsg.size() - sizeof(pldm_msg_hdr));
+
+    if (rc != PLDM_SUCCESS)
+    {
+        log<level::ERR>("Message encode failure. ", entry("RC=%d", rc));
+        elog<InternalFailure>();
+    }
+
+    uint8_t* responseMsg = nullptr;
+    size_t responseMsgSize{};
+
+    auto fd = open();
+
+    rc = pldm_send_recv(eid, fd, requestMsg.data(), requestMsg.size(),
+                        &responseMsg, &responseMsgSize);
+    if (rc < 0)
+    {
+        closeFD(fd);
+        auto e = errno;
+        log<level::ERR>("pldm_send failed", entry("RC=%d", rc),
+                        entry("ERRNO=%d", e));
+        elog<InternalFailure>();
+    }
+    pldm_msg* response = reinterpret_cast<pldm_msg*>(responseMsg);
+    log<level::INFO>(
+        "Done. PLDM message",
+        entry("RC=%d", static_cast<uint16_t>(response->payload[0])));
+
+    closeFD(fd);
+}
+
+uint8_t getPLDMInstanceID(uint8_t eid)
+{
+
+    constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
+    constexpr auto pldm = "/xyz/openbmc_project/pldm";
+
+    auto bus = sdbusplus::bus::new_default();
+    auto service = phosphor::dump::getService(bus, pldm, pldmRequester);
+
+    auto method = bus.new_method_call(service.c_str(), pldm, pldmRequester,
+                                      "GetInstanceId");
+    method.append(eid);
+    auto reply = bus.call(method);
+
+    uint8_t instanceID = 0;
+    reply.read(instanceID);
+
+    return instanceID;
+}
+} // namespace pldm
+} // namespace dump
+} // namespace phosphor
diff --git a/offload-extensions/pldm/pldm_interface.hpp b/offload-extensions/pldm/pldm_interface.hpp
new file mode 100644
index 0000000..fffa682
--- /dev/null
+++ b/offload-extensions/pldm/pldm_interface.hpp
@@ -0,0 +1,56 @@
+#pragma once
+
+#include <libpldm/pldm.h>
+
+namespace phosphor
+{
+namespace dump
+{
+namespace pldm
+{
+
+/**
+ * PLDMInterface
+ *
+ * Handles sending the SetNumericEffecterValue PLDM
+ * command to the host to start dump offload.
+ *
+ */
+
+/**
+ * @brief Kicks of the SetNumericEffecterValue command to
+ *        start offload the dump
+ *
+ * @param[in] id - The Dump Source ID.
+ *
+ */
+
+void requestOffload(uint32_t id);
+
+/**
+ * @brief Reads the MCTP endpoint ID out of a file
+ */
+mctp_eid_t readEID();
+
+/**
+ * @brief Opens the PLDM file descriptor
+ */
+int open();
+
+/**
+ * @brief Closes the PLDM file descriptor
+ */
+void closeFD(int fd);
+
+/**
+ * @brief Returns the PLDM instance ID to use for PLDM commands
+ *
+ * @param[in] eid - The PLDM EID
+ *
+ * @return uint8_t - The instance ID
+ **/
+uint8_t getPLDMInstanceID(uint8_t eid);
+
+} // namespace pldm
+} // namespace dump
+} // namespace phosphor