diff options
author | Jason M. Bills <jason.m.bills@linux.intel.com> | 2020-09-21 22:59:23 +0300 |
---|---|---|
committer | Jason M. Bills <jason.m.bills@linux.intel.com> | 2020-09-22 00:17:37 +0300 |
commit | 5d3fc64c142786581d792d145231c835afbcdded (patch) | |
tree | 18d6cc15665dd2a3cf3ffbdf72cc3aabedc1ba1b /meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb | |
parent | f99301c1a626951ee7feee081a1494e795d0e243 (diff) | |
download | openbmc-5d3fc64c142786581d792d145231c835afbcdded.tar.xz |
Update to internal 0.74-57
Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb')
16 files changed, 1694 insertions, 161 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch index 274dd044a..23eac280d 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch @@ -1,4 +1,4 @@ -From f388587781c3d874b13b50ad39e8674f0bc08049 Mon Sep 17 00:00:00 2001 +From 1f91d5708cbe30610c0c8bbc4910709b99b8f270 Mon Sep 17 00:00:00 2001 From: AppaRao Puli <apparao.puli@linux.intel.com> Date: Mon, 25 May 2020 16:14:39 +0530 Subject: [PATCH] EventService: https client support @@ -17,12 +17,12 @@ Tested: Change-Id: I44c3918b39baa2eb5fddda9d635f99aa280a422a Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> --- - http/http_client.hpp | 270 +++++++++++++++++-------- + http/http_client.hpp | 325 +++++++++++++++++-------- redfish-core/include/event_service_manager.hpp | 2 +- - 2 files changed, 186 insertions(+), 86 deletions(-) + 2 files changed, 226 insertions(+), 101 deletions(-) diff --git a/http/http_client.hpp b/http/http_client.hpp -index e6a7db1..27d2af3 100644 +index e6a7db1..6d3d702 100644 --- a/http/http_client.hpp +++ b/http/http_client.hpp @@ -17,6 +17,7 @@ @@ -33,19 +33,42 @@ index e6a7db1..27d2af3 100644 #include <boost/beast/version.hpp> #include <cstdlib> -@@ -49,7 +50,10 @@ enum class ConnState +@@ -30,12 +31,14 @@ namespace crow + { + + static constexpr uint8_t maxRequestQueueSize = 50; ++static constexpr unsigned int httpReadBodyLimit = 1024; + + enum class ConnState + { + initialized, + connectInProgress, + connectFailed, ++ sslHandshakeInProgress, + connected, + sendInProgress, + sendFailed, +@@ -49,53 +52,97 @@ enum class ConnState class HttpClient : public std::enable_shared_from_this<HttpClient> { private: -- boost::beast::tcp_stream conn; -+ boost::asio::io_context& ioc; + boost::asio::ssl::context ctx{boost::asio::ssl::context::tlsv12_client}; -+ std::shared_ptr<boost::beast::ssl_stream<boost::beast::tcp_stream>> sslConn; -+ std::shared_ptr<boost::beast::tcp_stream> conn; + boost::beast::tcp_stream conn; ++ std::optional<boost::beast::ssl_stream<boost::beast::tcp_stream&>> sslConn; boost::asio::steady_timer timer; - boost::beast::flat_buffer buffer; +- boost::beast::flat_buffer buffer; ++ boost::beast::flat_static_buffer<httpReadBodyLimit> buffer; ++ std::optional< ++ boost::beast::http::response_parser<boost::beast::http::string_body>> ++ parser; boost::beast::http::request<boost::beast::http::string_body> req; -@@ -62,14 +66,37 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +- boost::beast::http::response<boost::beast::http::string_body> res; + boost::asio::ip::tcp::resolver::results_type endpoint; +- std::vector<std::pair<std::string, std::string>> headers; ++ boost::beast::http::fields fields; + std::queue<std::string> requestDataQueue; +- ConnState state; + std::string subId; std::string host; std::string port; std::string uri; @@ -55,59 +78,28 @@ index e6a7db1..27d2af3 100644 uint32_t retryIntervalSecs; std::string retryPolicyAction; bool runningTimer; ++ ConnState state; -+ inline boost::beast::tcp_stream& getConn() -+ { -+ if (useSsl) -+ { -+ return (boost::beast::get_lowest_layer(*sslConn)); -+ } -+ else -+ { -+ return (*conn); -+ } -+ } -+ void doConnect() { +- if (state == ConnState::connectInProgress) + if (useSsl) + { -+ sslConn = std::make_shared< -+ boost::beast::ssl_stream<boost::beast::tcp_stream>>(ioc, ctx); -+ } -+ else -+ { -+ conn = std::make_shared<boost::beast::tcp_stream>(ioc); ++ sslConn.emplace(conn, ctx); + } + - if (state == ConnState::connectInProgress) ++ if ((state == ConnState::connectInProgress) || ++ (state == ConnState::sslHandshakeInProgress)) { return; -@@ -77,25 +104,53 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + } state = ConnState::connectInProgress; BMCWEB_LOG_DEBUG << "Trying to connect to: " << host << ":" << port; - // Set a timeout on the operation -- conn.expires_after(std::chrono::seconds(30)); -- conn.async_connect(endpoint, [self(shared_from_this())]( -- const boost::beast::error_code& ec, -- const boost::asio::ip::tcp::resolver:: -- results_type::endpoint_type& ep) { -- if (ec) -- { -- BMCWEB_LOG_ERROR << "Connect " << ep -- << " failed: " << ec.message(); -- self->state = ConnState::connectFailed; -- self->checkQueue(); -- return; -- } -- self->state = ConnState::connected; -- BMCWEB_LOG_DEBUG << "Connected to: " << ep; - -- self->checkQueue(); -- }); ++ + auto respHandler = -+ [self(shared_from_this())](const boost::beast::error_code& ec, ++ [self(shared_from_this())](const boost::beast::error_code ec, + const boost::asio::ip::tcp::resolver:: + results_type::endpoint_type& ep) { + if (ec) @@ -119,7 +111,7 @@ index e6a7db1..27d2af3 100644 + return; + } + BMCWEB_LOG_DEBUG << "Connected to: " << ep; -+ if (self->useSsl) ++ if (self->sslConn) + { + self->performHandshake(); + } @@ -130,57 +122,91 @@ index e6a7db1..27d2af3 100644 + } + }; + -+ getConn().expires_after(std::chrono::seconds(30)); -+ getConn().async_connect(endpoint, std::move(respHandler)); + conn.expires_after(std::chrono::seconds(30)); +- conn.async_connect(endpoint, [self(shared_from_this())]( +- const boost::beast::error_code& ec, +- const boost::asio::ip::tcp::resolver:: +- results_type::endpoint_type& ep) { +- if (ec) +- { +- BMCWEB_LOG_ERROR << "Connect " << ep +- << " failed: " << ec.message(); +- self->state = ConnState::connectFailed; +- self->checkQueue(); +- return; +- } +- self->state = ConnState::connected; +- BMCWEB_LOG_DEBUG << "Connected to: " << ep; ++ conn.async_connect(endpoint, std::move(respHandler)); + } -+ + +- self->checkQueue(); +- }); + void performHandshake() + { ++ if (state == ConnState::sslHandshakeInProgress) ++ { ++ return; ++ } ++ state = ConnState::sslHandshakeInProgress; ++ + sslConn->async_handshake( + boost::asio::ssl::stream_base::client, -+ [self(shared_from_this())](const boost::beast::error_code& ec) { ++ [self(shared_from_this())](const boost::beast::error_code ec) { + if (ec) + { + BMCWEB_LOG_ERROR << "SSL handshake failed: " + << ec.message(); -+ self->state = ConnState::connectFailed; -+ self->doCloseAndCheckQueue(); ++ self->doCloseAndCheckQueue(ConnState::connectFailed); + return; + } + self->state = ConnState::connected; -+ BMCWEB_LOG_DEBUG << "SSL Handshake successfull \n"; ++ BMCWEB_LOG_DEBUG << "SSL Handshake successfull"; + + self->checkQueue(); + }); } void sendMessage(const std::string& data) -@@ -108,7 +163,10 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> - - BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port; +@@ -106,100 +153,167 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + } + state = ConnState::sendInProgress; +- BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port; +- - req.version(static_cast<int>(11)); // HTTP 1.1 +- req.target(uri); +- req.method(boost::beast::http::verb::post); ++ BMCWEB_LOG_DEBUG << host << ":" << port; + +- // Set headers +- for (const auto& [key, value] : headers) + req = {}; -+ res = {}; ++ for (const auto& field : fields) + { +- req.set(key, value); ++ req.set(field.name_string(), field.value()); + } + req.set(boost::beast::http::field::host, host); ++ req.set(boost::beast::http::field::content_type, "text/plain"); + -+ req.version(11); // HTTP 1.1 - req.target(uri); - req.method(boost::beast::http::verb::post); ++ req.version(static_cast<int>(11)); // HTTP 1.1 ++ req.target(uri); ++ req.method(boost::beast::http::verb::post); + req.keep_alive(true); -@@ -123,83 +181,121 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> req.body() = data; req.prepare_payload(); - // Set a timeout on the operation - conn.expires_after(std::chrono::seconds(30)); + auto respHandler = [self(shared_from_this())]( -+ const boost::beast::error_code& ec, ++ const boost::beast::error_code ec, + const std::size_t& bytesTransferred) { + if (ec) + { + BMCWEB_LOG_ERROR << "sendMessage() failed: " << ec.message(); -+ self->state = ConnState::sendFailed; -+ self->doCloseAndCheckQueue(); ++ self->doCloseAndCheckQueue(ConnState::sendFailed); + return; + } + BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: " @@ -208,15 +234,15 @@ index e6a7db1..27d2af3 100644 - self->recvMessage(); - }); -+ getConn().expires_after(std::chrono::seconds(30)); -+ if (useSsl) ++ conn.expires_after(std::chrono::seconds(30)); ++ if (sslConn) + { + boost::beast::http::async_write(*sslConn, req, + std::move(respHandler)); + } + else + { -+ boost::beast::http::async_write(*conn, req, std::move(respHandler)); ++ boost::beast::http::async_write(conn, req, std::move(respHandler)); + } } @@ -227,109 +253,141 @@ index e6a7db1..27d2af3 100644 - conn, buffer, res, - [self(shared_from_this())](const boost::beast::error_code& ec, - const std::size_t& bytesTransferred) { -- if (ec) -- { -- BMCWEB_LOG_ERROR << "recvMessage() failed: " -- << ec.message(); -- self->state = ConnState::recvFailed; -- self->checkQueue(); -- return; -- } -- BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " -- << bytesTransferred; -- boost::ignore_unused(bytesTransferred); + auto respHandler = [self(shared_from_this())]( -+ const boost::beast::error_code& ec, ++ const boost::beast::error_code ec, + const std::size_t& bytesTransferred) { + if (ec && ec != boost::beast::http::error::partial_message) + { + BMCWEB_LOG_ERROR << "recvMessage() failed: " << ec.message(); -+ self->state = ConnState::recvFailed; -+ self->doCloseAndCheckQueue(); ++ self->doCloseAndCheckQueue(ConnState::recvFailed); + return; + } + BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " + << bytesTransferred; + boost::ignore_unused(bytesTransferred); - -- // Discard received data. We are not interested. -- BMCWEB_LOG_DEBUG << "recvMessage() data: " << self->res; -+ // Discard received data. We are not interested. -+ BMCWEB_LOG_DEBUG << "recvMessage() data: " << self->res; - -- // Send is successful, Lets remove data from queue -- // check for next request data in queue. -- self->requestDataQueue.pop(); -- self->state = ConnState::idle; -- self->checkQueue(); -- }); ++ ++ // TODO: check for return status code and perform ++ // retry if fails(Ex: 40x). Take action depending on ++ // retry policy. ++ BMCWEB_LOG_DEBUG << "recvMessage() data: " ++ << self->parser->get().body(); ++ + // Send is successful, Lets remove data from queue + // check for next request data in queue. + self->requestDataQueue.pop(); -+ self->state = ConnState::idle; + -+ if (ec == boost::beast::http::error::partial_message) -+ { -+ // Least bothered about recv message. Partial -+ // message means, already data is sent. Lets close -+ // connection and let next request open connection -+ // to avoid truncated stream. -+ self->state = ConnState::closed; -+ self->doCloseAndCheckQueue(); -+ return; -+ } ++ // Transfer ownership of the response ++ self->parser->release(); + -+ self->checkQueue(); ++ // TODO: Implement the keep-alive connections. ++ // Most of the web servers close connection abruptly ++ // and might be reason due to which its observed that ++ // stream_truncated(Next read) or partial_message ++ // errors. So for now, closing connection and re-open ++ // for all cases. ++ self->doCloseAndCheckQueue(ConnState::closed); + }; + -+ getConn().expires_after(std::chrono::seconds(30)); -+ if (useSsl) ++ parser.emplace(std::piecewise_construct, std::make_tuple()); ++ parser->body_limit(httpReadBodyLimit); ++ buffer.consume(buffer.size()); ++ ++ conn.expires_after(std::chrono::seconds(30)); ++ if (sslConn) + { -+ boost::beast::http::async_read(*sslConn, buffer, res, ++ boost::beast::http::async_read(*sslConn, buffer, *parser, + std::move(respHandler)); + } + else + { -+ boost::beast::http::async_read(*conn, buffer, res, ++ boost::beast::http::async_read(conn, buffer, *parser, + std::move(respHandler)); + } - } - ++ } ++ ++ void doCloseAndCheckQueue(const ConnState setState = ConnState::closed) ++ { ++ if (sslConn) ++ { ++ conn.expires_after(std::chrono::seconds(30)); ++ sslConn->async_shutdown([self = shared_from_this(), ++ setState{std::move(setState)}]( ++ const boost::system::error_code ec) { + if (ec) + { +- BMCWEB_LOG_ERROR << "recvMessage() failed: " +- << ec.message(); +- self->state = ConnState::recvFailed; +- self->checkQueue(); +- return; ++ // Many https server closes connection abruptly ++ // i.e witnout close_notify. More details are at ++ // https://github.com/boostorg/beast/issues/824 ++ if (ec == boost::asio::ssl::error::stream_truncated) ++ { ++ BMCWEB_LOG_ERROR ++ << "doCloseAndCheckQueue(): Connection " ++ "closed by server. "; ++ } ++ else ++ { ++ BMCWEB_LOG_ERROR << "doCloseAndCheckQueue() failed: " ++ << ec.message(); ++ } + } +- BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " +- << bytesTransferred; +- boost::ignore_unused(bytesTransferred); +- +- // Discard received data. We are not interested. +- BMCWEB_LOG_DEBUG << "recvMessage() data: " << self->res; +- +- // Send is successful, Lets remove data from queue +- // check for next request data in queue. +- self->requestDataQueue.pop(); +- self->state = ConnState::idle; ++ else ++ { ++ BMCWEB_LOG_DEBUG << "Connection closed gracefully..."; ++ } ++ self->conn.cancel(); ++ self->state = setState; + self->checkQueue(); + }); +- } +- - void doClose() -+ void doCloseAndCheckQueue() - { - boost::beast::error_code ec; +- { +- boost::beast::error_code ec; - conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); -+ getConn().cancel(); -+ getConn().expires_after(std::chrono::seconds(30)); -+ getConn().socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, -+ ec); - +- - state = ConnState::closed; - // not_connected happens sometimes so don't bother reporting it. - if (ec && ec != boost::beast::errc::not_connected) -+ if (ec && ec != boost::asio::error::eof) ++ } ++ else { - BMCWEB_LOG_ERROR << "shutdown failed: " << ec.message(); - return; -+ // Many https server closes connection abruptly -+ // i.e witnout close_notify. More details are at -+ // https://github.com/boostorg/beast/issues/824 -+ if (ec == boost::asio::ssl::error::stream_truncated) ++ boost::beast::error_code ec; ++ conn.expires_after(std::chrono::seconds(30)); ++ conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ++ ec); ++ if (ec) + { -+ BMCWEB_LOG_DEBUG -+ << "doCloseAndCheckQueue(): Connection closed by server."; ++ BMCWEB_LOG_ERROR << "doCloseAndCheckQueue() failed: " ++ << ec.message(); + } + else + { -+ BMCWEB_LOG_ERROR << "doCloseAndCheckQueue() failed: " -+ << ec.message(); ++ BMCWEB_LOG_DEBUG << "Connection closed gracefully..."; + } - } + -+ getConn().close(); - BMCWEB_LOG_DEBUG << "Connection closed gracefully"; -+ checkQueue(); ++ conn.close(); ++ state = setState; ++ checkQueue(); + } +- BMCWEB_LOG_DEBUG << "Connection closed gracefully"; + return; } @@ -344,7 +402,7 @@ index e6a7db1..27d2af3 100644 BMCWEB_LOG_DEBUG << "requestDataQueue is empty\n"; return; } -@@ -257,17 +353,20 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +@@ -257,16 +371,17 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> BMCWEB_LOG_DEBUG << "Attempt retry after " << retryIntervalSecs << " seconds. RetryCount = " << retryCount; timer.expires_after(std::chrono::seconds(retryIntervalSecs)); @@ -360,38 +418,66 @@ index e6a7db1..27d2af3 100644 + }); return; } - else +- else ++ ++ if (state == ConnState::idle) { - // reset retry count. -- retryCount = 0; -+ if (state == ConnState::idle) -+ { -+ // State idle means, previous attempt is successful. -+ retryCount = 0; -+ } ++ // State idle means, previous attempt is successful. + retryCount = 0; } connStateCheck(); - -@@ -310,10 +409,11 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +@@ -279,6 +394,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + switch (state) + { + case ConnState::connectInProgress: ++ case ConnState::sslHandshakeInProgress: + case ConnState::sendInProgress: + case ConnState::suspended: + case ConnState::terminated: +@@ -310,15 +426,19 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> public: explicit HttpClient(boost::asio::io_context& ioc, const std::string& id, const std::string& destIP, const std::string& destPort, - const std::string& destUri) : -- conn(ioc), + const std::string& destUri, + const bool inUseSsl = true) : -+ ioc(ioc), + conn(ioc), timer(ioc), subId(id), host(destIP), port(destPort), uri(destUri), - retryCount(0), maxRetryAttempts(5), +- retryPolicyAction("TerminateAfterRetries"), runningTimer(false) + useSsl(inUseSsl), retryCount(0), maxRetryAttempts(5), - retryPolicyAction("TerminateAfterRetries"), runningTimer(false) ++ retryPolicyAction("TerminateAfterRetries"), runningTimer(false), ++ state(ConnState::initialized) { boost::asio::ip::tcp::resolver resolver(ioc); ++ // TODO: Use async_resolver. boost asio example ++ // code as is crashing with async_resolve(). ++ // It needs debug. + endpoint = resolver.resolve(host, port); +- state = ConnState::initialized; + } + + void sendData(const std::string& data) +@@ -344,7 +464,12 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + void setHeaders( + const std::vector<std::pair<std::string, std::string>>& httpHeaders) + { +- headers = httpHeaders; ++ // Set headers ++ for (const auto& [key, value] : httpHeaders) ++ { ++ // TODO: Validate the header fileds before assign. ++ fields.set(key, value); ++ } + } + + void setRetryConfig(const uint32_t retryAttempts, diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp -index 6362112..3ab2605 100644 +index 9c42e06..2a02920 100644 --- a/redfish-core/include/event_service_manager.hpp +++ b/redfish-core/include/event_service_manager.hpp -@@ -383,7 +383,7 @@ class Subscription +@@ -384,7 +384,7 @@ class Subscription { conn = std::make_shared<crow::HttpClient>( crow::connections::systemBus->get_io_context(), id, host, port, diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0007-cpudimm-get-cpu-details-from-Redfish.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0007-cpudimm-get-cpu-details-from-Redfish.patch new file mode 100644 index 000000000..ccf13e2af --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0007-cpudimm-get-cpu-details-from-Redfish.patch @@ -0,0 +1,231 @@ +From 7e50451bc8d4c4e8fa5ee1b0e2af86c800ea2efc Mon Sep 17 00:00:00 2001 +From: jayaprakash Mutyala <mutyalax.jayaprakash@intel.com> +Date: Mon, 13 Apr 2020 23:31:06 +0000 +Subject: [PATCH] cpudimm: get cpu details from Redfish + +Modified the code to fetch cpu details from Redfish + +Note: This patch will be removed after code is up streamed. +https://gerrit.openbmc-project.xyz/#/c/openbmc/bmcweb/+/31294/ + +Tested: +1. Verified redfish validator passed +2. Get cpu details from Redfish +GET: https://<BMC-IP>/redfish/v1/Systems/system/Processors/cpu0 +Response: +{ + "@odata.id": "/redfish/v1/Systems/system/Processors/cpu0", + "@odata.type": "#Processor.v1_7_0.Processor", + "Id": "cpu0", + "InstructionSet": "x86-64", + "Manufacturer": "Intel(R) Corporation", + "MaxSpeedMHz": 4000, + "Model": "", + "Name": "Central Processor", + "ProcessorArchitecture": "x86", + "ProcessorId": { + "EffectiveFamily": "Intel Xeon processor", + "VendorId": "329300" + }, + "ProcessorType": "CPU", + "SerialNumber": "", + "Socket": "CPU0", + "Status": { + "Health": "OK", + "HealthRollup": "OK", + "State": "Enabled" + }, + "TotalCores": 18, + "TotalThreads": 36, + "Version": "Intel(R) Xeon(R) Gold 6139 CPU @ 2.30GHz" +} + +GET: https://<BMC-IP>/redfish/v1/Systems/system/Processors/cpu1 +Response: +{ + "@odata.id": "/redfish/v1/Systems/system/Processors/cpu1", + "@odata.type": "#Processor.v1_7_0.Processor", + "Id": "cpu1", + "Name": "Processor", + "ProcessorType": "CPU", + "Status": { + "Health": "OK", + "HealthRollup": "OK", + "State": "Absent" + } +} + +Signed-off-by: jayaprakash Mutyala <mutyalax.jayaprakash@intel.com> +Change-Id: Idcad6e643684f4912f24c259b075a443e1da5007 +--- + redfish-core/lib/cpudimm.hpp | 81 ++++++++++++++++++++---------------- + 1 file changed, 46 insertions(+), 35 deletions(-) + +diff --git a/redfish-core/lib/cpudimm.hpp b/redfish-core/lib/cpudimm.hpp +index ed5e641..e332a11 100644 +--- a/redfish-core/lib/cpudimm.hpp ++++ b/redfish-core/lib/cpudimm.hpp +@@ -73,8 +73,13 @@ void getCpuDataByInterface(std::shared_ptr<AsyncResp> aResp, + { + BMCWEB_LOG_DEBUG << "Get CPU resources by interface."; + +- const bool* present = nullptr; +- const bool* functional = nullptr; ++ // Added for future purpose. Once present and functional attributes added ++ // in busctl call, need to add actual logic to fetch original values. ++ bool present = false; ++ const bool functional = true; ++ auto health = std::make_shared<HealthPopulate>(aResp); ++ health->populate(); ++ + for (const auto& interface : cpuInterfacesProperties) + { + for (const auto& property : interface.second) +@@ -93,10 +98,13 @@ void getCpuDataByInterface(std::shared_ptr<AsyncResp> aResp, + { + // Slot is not populated, set status end return + aResp->res.jsonValue["Status"]["State"] = "Absent"; +- aResp->res.jsonValue["Status"]["Health"] = "OK"; + // HTTP Code will be set up automatically, just return + return; + } ++ else ++ { ++ aResp->res.jsonValue["Status"]["State"] = "Enabled"; ++ } + + aResp->res.jsonValue["TotalCores"] = *coresCount; + } +@@ -104,7 +112,7 @@ void getCpuDataByInterface(std::shared_ptr<AsyncResp> aResp, + { + aResp->res.jsonValue["Name"] = property.second; + } +- else if (property.first == "Manufacturer") ++ else if (property.first == "ProcessorManufacturer") + { + const std::string* value = + std::get_if<std::string>(&property.second); +@@ -128,50 +136,48 @@ void getCpuDataByInterface(std::shared_ptr<AsyncResp> aResp, + { + aResp->res.jsonValue["MaxSpeedMHz"] = property.second; + } +- else if (property.first == "ProcessorThreadCount") +- { +- aResp->res.jsonValue["TotalThreads"] = property.second; +- } +- else if (property.first == "Model") ++ else if (property.first == "ProcessorSocket") + { + const std::string* value = + std::get_if<std::string>(&property.second); + if (value != nullptr) + { +- aResp->res.jsonValue["Model"] = *value; ++ aResp->res.jsonValue["Socket"] = *value; + } + } +- else if (property.first == "PartNumber") ++ else if (property.first == "ProcessorThreadCount") + { +- aResp->res.jsonValue["PartNumber"] = property.second; ++ aResp->res.jsonValue["TotalThreads"] = property.second; + } +- else if (property.first == "SerialNumber") ++ else if (property.first == "ProcessorFamily") + { +- aResp->res.jsonValue["SerialNumber"] = property.second; ++ const std::string* value = ++ std::get_if<std::string>(&property.second); ++ if (value != nullptr) ++ { ++ aResp->res.jsonValue["ProcessorId"]["EffectiveFamily"] = ++ *value; ++ } + } +- else if (property.first == "Version") ++ else if (property.first == "ProcessorVersion") + { + aResp->res.jsonValue["Version"] = property.second; + } +- else if (property.first == "Present") +- { +- present = std::get_if<bool>(&property.second); +- } +- else if (property.first == "Functional") ++ else if (property.first == "ProcessorId") + { +- functional = std::get_if<bool>(&property.second); ++ const uint32_t* value = std::get_if<uint32_t>(&property.second); ++ ++ if (value != nullptr && *value != 0) ++ { ++ present = true; ++ aResp->res.jsonValue["ProcessorId"]["VendorId"] = ++ boost::lexical_cast<std::string>(*value); ++ } + } + } + } + +- if ((present == nullptr) || (functional == nullptr)) +- { +- // Important property not in desired type +- messages::internalError(aResp->res); +- return; +- } +- +- if (*present == false) ++ if (present == false) + { + aResp->res.jsonValue["Status"]["State"] = "Absent"; + aResp->res.jsonValue["Status"]["Health"] = "OK"; +@@ -179,7 +185,7 @@ void getCpuDataByInterface(std::shared_ptr<AsyncResp> aResp, + else + { + aResp->res.jsonValue["Status"]["State"] = "Enabled"; +- if (*functional == true) ++ if (functional) + { + aResp->res.jsonValue["Status"]["Health"] = "OK"; + } +@@ -212,6 +218,7 @@ void getCpuDataByService(std::shared_ptr<AsyncResp> aResp, + aResp->res.jsonValue["Name"] = "Processor"; + aResp->res.jsonValue["ProcessorType"] = "CPU"; + ++ bool slotPresent = false; + std::string corePath = objPath + "/core"; + size_t totalCores = 0; + for (const auto& object : dbusData) +@@ -237,6 +244,7 @@ void getCpuDataByService(std::shared_ptr<AsyncResp> aResp, + { + if (*present == true) + { ++ slotPresent = true; + totalCores++; + } + } +@@ -249,13 +257,16 @@ void getCpuDataByService(std::shared_ptr<AsyncResp> aResp, + // In getCpuDataByInterface(), state and health are set + // based on the present and functional status. If core + // count is zero, then it has a higher precedence. +- if (totalCores == 0) ++ if (slotPresent) + { +- // Slot is not populated, set status end return +- aResp->res.jsonValue["Status"]["State"] = "Absent"; +- aResp->res.jsonValue["Status"]["Health"] = "OK"; ++ if (totalCores == 0) ++ { ++ // Slot is not populated, set status end return ++ aResp->res.jsonValue["Status"]["State"] = "Absent"; ++ aResp->res.jsonValue["Status"]["Health"] = "OK"; ++ } ++ aResp->res.jsonValue["TotalCores"] = totalCores; + } +- aResp->res.jsonValue["TotalCores"] = totalCores; + return; + }, + service, "/xyz/openbmc_project/inventory", +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0008-systems-Fix-for-Processor-Summary-Model.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0008-systems-Fix-for-Processor-Summary-Model.patch new file mode 100644 index 000000000..d210e3808 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0008-systems-Fix-for-Processor-Summary-Model.patch @@ -0,0 +1,138 @@ +From ea3f3da3b29c7ecca34c12f94ce1e0364cbf9d7c Mon Sep 17 00:00:00 2001 +From: jayaprakash Mutyala <mutyalax.jayaprakash@intel.com> +Date: Fri, 29 May 2020 00:50:46 +0000 +Subject: [PATCH] systems: Fix for Processor Summary Model + +Issue: Processor summary is not showing model name as expected from + Redfish + +Fix: Add condition to fetch valid model name in processor summary + +Tested: +1. Verified redfish validator passed +2. Get system details from Redfish +GET: https://<BMC-IP>/redfish/v1/Systems/system/ +Before fix: +Response: + "ProcessorSummary": { + "Count": 2, + "Model": "Unknown Processor Family", + "Status": { + "Health": "OK", + "HealthRollup": "OK", + "State": "Enabled" + } + }, + +After fix: +Response: + "ProcessorSummary": { + "Count": 1, + "Model": "Intel Xeon processor", + "Status": { + "Health": "OK", + "HealthRollup": "OK", + "State": "Enabled" + } + }, + +Signed-off-by: jayaprakash Mutyala <mutyalax.jayaprakash@intel.com> +Change-Id: I4af7132135aef26556839fabada623728b52be8b +--- + redfish-core/lib/systems.hpp | 73 +++++++++++++++++++++++------------- + 1 file changed, 46 insertions(+), 27 deletions(-) + +diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp +index 2baeaa7..884fbb6 100644 +--- a/redfish-core/lib/systems.hpp ++++ b/redfish-core/lib/systems.hpp +@@ -325,40 +325,59 @@ void getComputerSystem(std::shared_ptr<AsyncResp> aResp, + + if (properties.size() > 0) + { ++ const uint32_t* processorId = nullptr; ++ const std::string* procFamily = nullptr; ++ nlohmann::json& procSummary = ++ aResp->res.jsonValue["ProcessorSumm" ++ "ary"]; ++ nlohmann::json& procCount = ++ procSummary["Count"]; ++ ++ auto procCountPtr = procCount.get_ptr< ++ nlohmann::json:: ++ number_integer_t*>(); ++ if (procCountPtr == nullptr) ++ { ++ messages::internalError(aResp->res); ++ return; ++ } + for (const auto& property : properties) + { ++ ++ if (property.first == "ProcessorId") ++ { ++ processorId = ++ std::get_if<uint32_t>( ++ &property.second); ++ if (nullptr != procFamily) ++ break; ++ continue; ++ } ++ + if (property.first == + "ProcessorFamily") + { +- const std::string* value = ++ procFamily = + std::get_if<std::string>( + &property.second); +- if (value != nullptr) +- { +- nlohmann::json& +- procSummary = +- aResp->res.jsonValue +- ["ProcessorSumm" +- "ary"]; +- nlohmann::json& procCount = +- procSummary["Count"]; +- +- auto procCountPtr = +- procCount.get_ptr< +- nlohmann::json:: +- number_integer_t*>(); +- if (procCountPtr != nullptr) +- { +- // shouldn't be possible +- // to be nullptr +- *procCountPtr += 1; +- } +- procSummary["Status"] +- ["State"] = +- "Enabled"; +- procSummary["Model"] = +- *value; +- } ++ if (nullptr != processorId) ++ break; ++ continue; ++ } ++ } ++ ++ if (procFamily != nullptr && ++ processorId != nullptr) ++ { ++ if (procCountPtr != nullptr && ++ *processorId != 0) ++ { ++ *procCountPtr += 1; ++ procSummary["Status"]["State"] = ++ "Enabled"; ++ ++ procSummary["Model"] = ++ *procFamily; + } + } + } +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Fix-MetricReportDefinitions-filter-not-working.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Fix-MetricReportDefinitions-filter-not-working.patch new file mode 100644 index 000000000..64b3c1112 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Fix-MetricReportDefinitions-filter-not-working.patch @@ -0,0 +1,112 @@ +From 455b1d4c687a5c14197af1c1aba80b579c75900e Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Mon, 3 Aug 2020 22:23:12 +0530 +Subject: [PATCH 1/2] Fix: MetricReportDefinitions filter not working + +The metric reports are not sending when user configures +the MetricReportDefinitions filter. This is of odata json +object type. Corrected code to properly handle odata type +object and store it as string array to make filters faster. + +Tested: + - Created metric report EventService subscription type + with MetricReportDefinitions and events properly sent to + Event listener. + +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +Change-Id: If96564219da7d38a2ee5e415b89824ba25cd686d +--- + redfish-core/include/event_service_manager.hpp | 4 ++-- + redfish-core/lib/event_service.hpp | 32 +++++++++++++++++++++----- + 2 files changed, 28 insertions(+), 8 deletions(-) + +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index 214f1e4..7c47842 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -283,7 +283,7 @@ bool isFilterQuerySpecialChar(char c) + bool readSSEQueryParams(std::string sseFilter, std::string& formatType, + std::vector<std::string>& messageIds, + std::vector<std::string>& registryPrefixes, +- std::vector<nlohmann::json>& metricReportDefinitions) ++ std::vector<std::string>& metricReportDefinitions) + { + sseFilter.erase(std::remove_if(sseFilter.begin(), sseFilter.end(), + isFilterQuerySpecialChar), +@@ -369,7 +369,7 @@ class Subscription + std::vector<std::string> registryMsgIds; + std::vector<std::string> registryPrefixes; + std::vector<nlohmann::json> httpHeaders; // key-value pair +- std::vector<nlohmann::json> metricReportDefinitions; ++ std::vector<std::string> metricReportDefinitions; + + Subscription(const Subscription&) = delete; + Subscription& operator=(const Subscription&) = delete; +diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp +index 8bd30f5..f59d093 100644 +--- a/redfish-core/lib/event_service.hpp ++++ b/redfish-core/lib/event_service.hpp +@@ -229,7 +229,7 @@ class EventDestinationCollection : public Node + std::optional<std::vector<std::string>> msgIds; + std::optional<std::vector<std::string>> regPrefixes; + std::optional<std::vector<nlohmann::json>> headers; +- std::optional<std::vector<nlohmann::json>> metricReportDefinitions; ++ std::optional<std::vector<nlohmann::json>> mrdJsonArray; + + if (!json_util::readJson( + req, res, "Destination", destUrl, "Context", context, +@@ -237,7 +237,7 @@ class EventDestinationCollection : public Node + "EventFormatType", eventFormatType, "HttpHeaders", headers, + "RegistryPrefixes", regPrefixes, "MessageIds", msgIds, + "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions", +- metricReportDefinitions)) ++ mrdJsonArray)) + { + return; + } +@@ -387,9 +387,24 @@ class EventDestinationCollection : public Node + subValue->retryPolicy = "TerminateAfterRetries"; + } + +- if (metricReportDefinitions) ++ if (mrdJsonArray) + { +- subValue->metricReportDefinitions = *metricReportDefinitions; ++ for (nlohmann::json& mrdObj : *mrdJsonArray) ++ { ++ std::string mrdUri; ++ if (json_util::getValueFromJsonObject(mrdObj, "@odata.id", ++ mrdUri)) ++ { ++ subValue->metricReportDefinitions.emplace_back(mrdUri); ++ } ++ else ++ { ++ messages::propertyValueFormatError( ++ asyncResp->res, mrdObj.dump(), ++ "MetricReportDefinitions"); ++ return; ++ } ++ } + } + + std::string id = +@@ -565,8 +580,13 @@ class EventDestination : public Node + subValue->registryPrefixes; + asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds; + asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy; +- asyncResp->res.jsonValue["MetricReportDefinitions"] = +- subValue->metricReportDefinitions; ++ ++ std::vector<nlohmann::json> mrdJsonArray; ++ for (const auto& mdrUri : subValue->metricReportDefinitions) ++ { ++ mrdJsonArray.push_back({{"@odata.id", mdrUri}}); ++ } ++ asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray; + } + + void doPatch(crow::Response& res, const crow::Request& req, +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Workaround-Fix-memory-leak.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Workaround-Fix-memory-leak.patch new file mode 100644 index 000000000..90905762b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Workaround-Fix-memory-leak.patch @@ -0,0 +1,33 @@ +From f43d6ba7e32565a7881949070bd25cb13f50ebf7 Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Thu, 27 Aug 2020 13:56:52 -0700 +Subject: [PATCH 1/1] Workaround: Fix memory leak + +Req caputures self not allowing the connection to +be freed. There is discussion in upstream about a +real fix, this should be kept downstream only. + +Tested: Sent 1000 connections, saw no VSZ increase + +Change-Id: I63440abbe0882ffe228395b5d3bc869f10048ddc +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + http/http_connection.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/http/http_connection.h b/http/http_connection.h +index 109a272..393c2e7 100644 +--- a/http/http_connection.h ++++ b/http/http_connection.h +@@ -422,6 +422,8 @@ class Connection : + { + adaptor.close(); + } ++ // HACK TO REMOVE MEMORY LEAK ++ req.reset(); + } + + void completeRequest() +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-Fix-EventService-stops-sending-events.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-Fix-EventService-stops-sending-events.patch new file mode 100644 index 000000000..d7df52ddf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-Fix-EventService-stops-sending-events.patch @@ -0,0 +1,67 @@ +From 27705854ade6832bc1e91dada33fee43ee4b2bc9 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Sun, 2 Aug 2020 17:03:10 +0530 +Subject: [PATCH 2/2] Fix: EventService stops sending events + +When redfish log file(/var/log/redfish) is recreated +by rsyslog daemon, EventService stops sending events +to subscribers. + +The rsyslog service take redfish log files to back up +as per design. EventService has inotify on redfish log +file modifications. It needs to be removed from inotify +watcher list and added with new File descriptor. +Corrected code to handle remove & add of new descriptor. +Also corrected code to properly handle last event timestamp. + +Tested: + - Ran stress test on redfish log file to create multiple + backup files and events sends to clients properly, in + all switching scenarios. + +Change-Id: Ic0378edfc2cae86d1f69f6df4c429d07c2744bdf +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + redfish-core/include/event_service_manager.hpp | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index 7c47842..4671995 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -1019,6 +1019,7 @@ class EventServiceManager + #ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES + void cacheLastEventTimestamp() + { ++ lastEventTStr.clear(); + std::ifstream logStream(redfishEventLogFile); + if (!logStream.good()) + { +@@ -1062,7 +1063,7 @@ class EventServiceManager + std::string logEntry; + while (std::getline(logStream, logEntry)) + { +- if (!startLogCollection) ++ if (!startLogCollection && !lastEventTStr.empty()) + { + if (boost::starts_with(logEntry, lastEventTStr)) + { +@@ -1160,9 +1161,12 @@ class EventServiceManager + if (fileWatchDesc != -1) + { + BMCWEB_LOG_DEBUG +- << "Redfish log file is already on " +- "inotify_add_watch."; +- return; ++ << "Remove and Add inotify watcher on " ++ "redfish event log file"; ++ // Remove existing inotify watcher and add ++ // with new redfish event log file. ++ inotify_rm_watch(inotifyFd, fileWatchDesc); ++ fileWatchDesc = -1; + } + + fileWatchDesc = inotify_add_watch( +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-Deallocate-memory-during-failed-case.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-Deallocate-memory-during-failed-case.patch new file mode 100644 index 000000000..57ec01c7b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0011-Deallocate-memory-during-failed-case.patch @@ -0,0 +1,32 @@ +From cf5ba2028909d4fa0ee3bba4b60620e72cd612f0 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Fri, 7 Aug 2020 01:37:28 +0530 +Subject: [PATCH] Deallocate memory during failed case + +Free memory during failed case inside +pamFunctionConversation() function. + +Tested: + - Pam authentication works as normal. + +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +Change-Id: I81c06a3d674b0806c96e5847cda6f208795bd02c +--- + include/pam_authenticate.hpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/pam_authenticate.hpp b/include/pam_authenticate.hpp +index f2c7356..3e5c691 100644 +--- a/include/pam_authenticate.hpp ++++ b/include/pam_authenticate.hpp +@@ -30,6 +30,7 @@ inline int pamFunctionConversation(int numMsg, const struct pam_message** msg, + + if (resp == nullptr) + { ++ free(pass); + return PAM_AUTH_ERR; + } + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-System-Replace-chassis-name-in-Redfish.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-System-Replace-chassis-name-in-Redfish.patch new file mode 100644 index 000000000..870b33249 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0012-System-Replace-chassis-name-in-Redfish.patch @@ -0,0 +1,64 @@ +From e0e19506ac81b3fa858de30c90ed3d75e10df749 Mon Sep 17 00:00:00 2001 +From: srikanta mondal <srikantax.mondal@intel.com> +Date: Wed, 12 Aug 2020 18:26:26 +0000 +Subject: [PATCH] System: Replace chassis name in Redfish + +Modify code to replace chassis name to WC_Baseboard + +Note: This patch will be removed after code is up streamed. +https://gerrit.openbmc-project.xyz/#/c/openbmc/bmcweb/+/31748/ + +Tested: +1. Verified redfish validator passed +2. Verified details from Redfish + +GET: https://<BMC-IP>/redfish/v1/Systems/system +Response: +{ + .... + "Links": { + "Chassis": [ + { + "@odata.id": "/redfish/v1/Chassis/WC_Baseboard" + } + ], + "ManagedBy": [ + { + "@odata.id": "/redfish/v1/Managers/bmc" + } + ] + }, + .... +} + +GET: https://<BMC-IP>/redfish/v1/Chassis/WC_Baseboard +Response: +{ + // SUCCESS +} + +Signed-off-by: James Feist <james.feist@linux.intel.com> +Signed-off-by: srikanta mondal <srikantax.mondal@intel.com> +--- + redfish-core/lib/redfish_util.hpp | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/redfish-core/lib/redfish_util.hpp b/redfish-core/lib/redfish_util.hpp +index 5701712..3adb392 100644 +--- a/redfish-core/lib/redfish_util.hpp ++++ b/redfish-core/lib/redfish_util.hpp +@@ -57,9 +57,8 @@ void getMainChassisId(std::shared_ptr<AsyncResp> asyncResp, + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTree", + "/xyz/openbmc_project/inventory", 0, +- std::array<const char*, 2>{ +- "xyz.openbmc_project.Inventory.Item.Board", +- "xyz.openbmc_project.Inventory.Item.Chassis"}); ++ std::array<const char*, 1>{ ++ "xyz.openbmc_project.Inventory.Item.System"}); + } + } // namespace redfish + #endif +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-url_view-throws-if-a-parse-error-is-found.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-url_view-throws-if-a-parse-error-is-found.patch new file mode 100644 index 000000000..c7d4ca914 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0013-url_view-throws-if-a-parse-error-is-found.patch @@ -0,0 +1,54 @@ +From 6ab885e4cabe28f74050b7e996868e4d8387e94d Mon Sep 17 00:00:00 2001 +From: Ed Tanous <ed@tanous.net> +Date: Mon, 17 Aug 2020 15:04:58 -0700 +Subject: [PATCH] url_view throws if a parse error is found + +This causes a strange condition where the webserver crashes on bad urls. + +Tested: +Loaded on RPI. Verified that this particular crash no longer breaks the +fuzzer. + +Signed-off-by: Ed Tanous <ed@tanous.net> +Signed-off-by: James Feist <james.feist@linux.intel.com> +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +Change-Id: I459421e27c8d07c2bc45099b5942f7c7c929610d +--- + http/http_connection.h | 21 ++++++++++++++++++--- + 1 file changed, 18 insertions(+), 3 deletions(-) + +diff --git a/http/http_connection.h b/http/http_connection.h +index 8dba3d6..8db8108 100644 +--- a/http/http_connection.h ++++ b/http/http_connection.h +@@ -728,9 +728,24 @@ class Connection : + return; + } + +- req->urlView = boost::urls::url_view(req->target()); +- req->url = req->urlView.encoded_path(); +- ++ // Note, despite the bmcweb coding policy on use of exceptions ++ // for error handling, this one particular use of exceptions is ++ // deemed acceptible, as it solved a significant error handling ++ // problem that resulted in seg faults, the exact thing that the ++ // exceptions rule is trying to avoid. If at some point, ++ // boost::urls makes the parser object public (or we port it ++ // into bmcweb locally) this will be replaced with ++ // parser::parse, which returns a status code ++ ++ try ++ { ++ req->urlView = boost::urls::url_view(req->target()); ++ req->url = req->urlView.encoded_path(); ++ } ++ catch (std::exception& p) ++ { ++ BMCWEB_LOG_ERROR << p.what(); ++ } + crow::authorization::authenticate(*req, res, session); + + bool loggedIn = req && req->session; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0014-add-sufficient-delay-to-create-fw-update-object.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0014-add-sufficient-delay-to-create-fw-update-object.patch new file mode 100644 index 000000000..e6fd85f85 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0014-add-sufficient-delay-to-create-fw-update-object.patch @@ -0,0 +1,44 @@ +From d7df47f5df9c6e389c3deeb418be8fb7c32bc6f4 Mon Sep 17 00:00:00 2001 +From: Chalapathi Venkataramashetty <chalapathix.venkataramashetty@intel.com> +Date: Tue, 25 Aug 2020 15:44:35 +0000 +Subject: [PATCH] add sufficient delay to create fw update object + +Add support to increase timeoutTimeSeconds to 10 secs to allow firmware +object to create successfully to proceed for firmware update. + +Tested: +Redfish validator passed. + +Updated the firmware using redfish for 16 times continuously. +POST: https://<BMC_IP>/redfish/v1/UpdateService/ + with <BMC_signed_cap> binary file +firmware updated. +{ + "@odata.id": "/redfish/v1/TaskService/Tasks/0", + "@odata.type": "#Task.v1_4_3.Task", + "Id": "0", + "TaskState": "Running", + "TaskStatus": "OK" +} + +Signed-off-by: Chalapathi Venkataramashetty <chalapathix.venkataramashetty@intel.com> +--- + redfish-core/lib/update_service.hpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp +index 9407d75..ec5ab8c 100644 +--- a/redfish-core/lib/update_service.hpp ++++ b/redfish-core/lib/update_service.hpp +@@ -363,7 +363,7 @@ static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp, + static void monitorForSoftwareAvailable( + std::shared_ptr<AsyncResp> asyncResp, const crow::Request& req, + const std::string& url, const std::vector<std::string>& imgUriTargets, +- int timeoutTimeSeconds = 5) ++ int timeoutTimeSeconds = 10) + { + // Only allow one FW update at a time + if (fwUpdateInProgress != false) +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0015-Add-firmware-activation-messages-to-the-registry.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0015-Add-firmware-activation-messages-to-the-registry.patch new file mode 100644 index 000000000..6cc95eda5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0015-Add-firmware-activation-messages-to-the-registry.patch @@ -0,0 +1,72 @@ +From d61d668f6db81bed90f41c3a128ce6fd652cc98c Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" <jason.m.bills@linux.intel.com> +Date: Wed, 12 Aug 2020 14:45:32 -0700 +Subject: [PATCH] Add firmware activation messages to the registry + +In some situations a firmware requires activation rather than +update. These messages are intended to cover those situations. + +Tested: +Logged these events and confirmed that they appear correctly in +Redfish. + +Change-Id: I6171b9584626e049349a26c414146f37c04768c7 +Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> +--- + .../registries/openbmc_message_registry.hpp | 33 ++++++++++++++++++- + 1 file changed, 32 insertions(+), 1 deletion(-) + +diff --git a/redfish-core/include/registries/openbmc_message_registry.hpp b/redfish-core/include/registries/openbmc_message_registry.hpp +index 236002e..58c085d 100644 +--- a/redfish-core/include/registries/openbmc_message_registry.hpp ++++ b/redfish-core/include/registries/openbmc_message_registry.hpp +@@ -29,7 +29,7 @@ const Header header = { + "0.1.0", + "OpenBMC", + }; +-constexpr std::array<MessageEntry, 182> registry = { ++constexpr std::array<MessageEntry, 185> registry = { + MessageEntry{ + "ADDDCCorrectable", + { +@@ -443,6 +443,37 @@ constexpr std::array<MessageEntry, 182> registry = { + {"string"}, + "None.", + }}, ++ MessageEntry{ ++ "FirmwareActivationCompleted", ++ { ++ "Indicates a firmware activation has completed successfully.", ++ "%1 firmware activation completed successfully.", ++ "OK", ++ "OK", ++ 1, ++ {"string"}, ++ "None.", ++ }}, ++ MessageEntry{"FirmwareActivationFailed", ++ { ++ "Indicates a firmware activation has failed.", ++ "%1 firmware activation failed: %2.", ++ "Warning", ++ "Warning", ++ 2, ++ {"string", "string"}, ++ "None.", ++ }}, ++ MessageEntry{"FirmwareActivationStarted", ++ { ++ "Indicates a firmware activation has started.", ++ "%1 firmware activation started.", ++ "OK", ++ "OK", ++ 1, ++ {"string"}, ++ "None.", ++ }}, + MessageEntry{"FirmwareUpdateCompleted", + { + "Indicates a firmware update has completed successfully.", +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Fix-MetricReport-timestamp-for-EventService.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0016-EventService-Fix-type-mismatch-in-MetricReport.patch index 75d49b6d6..378ce6c47 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Fix-MetricReport-timestamp-for-EventService.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0016-EventService-Fix-type-mismatch-in-MetricReport.patch @@ -1,18 +1,23 @@ -From b71f087a173c36a16526156fa34581673e2b860c Mon Sep 17 00:00:00 2001 +From cdfc5cfad41bcfa3fc0e53023bd62bdadf15ad86 Mon Sep 17 00:00:00 2001 From: "Wludzik, Jozef" <jozef.wludzik@intel.com> Date: Fri, 24 Jul 2020 17:05:38 +0200 -Subject: [PATCH 6/6] Fix MetricReport timestamp for EventService +Subject: [PATCH] EventService: Fix type mismatch in MetricReport -Changed MetricReport timestamp type from std::string to int32_t. +Fix the type mismatch in MetricReport data which +is sent to Event Subscribers. Change below properties +type to match with MetricReport schema. + - Timestamp: It should be uint32_t type. + - MetricValue: It should be string type. Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com> +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> Change-Id: I0a52b6963e7bedda89a216256f64764cd8799bf1 --- redfish-core/include/event_service_manager.hpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp -index d2f4f2a..dc04ccb 100644 +index 3e3058f..0f5c6b7 100644 --- a/redfish-core/include/event_service_manager.hpp +++ b/redfish-core/include/event_service_manager.hpp @@ -38,7 +38,7 @@ namespace redfish @@ -36,12 +41,12 @@ index d2f4f2a..dc04ccb 100644 + + entry = {{"MetricId", id}, + {"MetricProperty", property}, -+ {"MetricValue", value}, ++ {"MetricValue", std::to_string(value)}, + {"Timestamp", crow::utility::getDateTime(timestamp)}}; } nlohmann::json msg = { -@@ -1266,7 +1268,7 @@ class EventServiceManager +@@ -1270,7 +1272,7 @@ class EventServiceManager [idStr{std::move(idStr)}]( const boost::system::error_code ec, boost::container::flat_map< @@ -50,7 +55,7 @@ index d2f4f2a..dc04ccb 100644 resp) { if (ec) { -@@ -1275,8 +1277,8 @@ class EventServiceManager +@@ -1279,8 +1281,8 @@ class EventServiceManager return; } @@ -61,7 +66,7 @@ index d2f4f2a..dc04ccb 100644 if (!timestampPtr) { BMCWEB_LOG_DEBUG << "Failed to Get timestamp."; -@@ -1303,8 +1305,9 @@ class EventServiceManager +@@ -1307,8 +1309,9 @@ class EventServiceManager std::shared_ptr<Subscription> entry = it.second; if (entry->eventFormatType == metricReportFormatType) { @@ -74,5 +79,5 @@ index d2f4f2a..dc04ccb 100644 } }, -- -2.16.6 +2.7.4 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0017-Add-MutualExclusiveProperties-registry.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0017-Add-MutualExclusiveProperties-registry.patch new file mode 100644 index 000000000..2b510e0b5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0017-Add-MutualExclusiveProperties-registry.patch @@ -0,0 +1,151 @@ +From 891a0a2deb616b7e3f135b5df8501947ce5d6ad4 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Tue, 8 Sep 2020 01:53:21 +0530 +Subject: [PATCH] Add MutualExclusiveProperties registry + +Add MutualExclusiveProperties message registry entry +and error message. +As per redfish specification, "RegistryPrefixes" and +"MessageIds" are mutually exclusive. So add check for +same in EventService and return MutualExclusiveProperties +error message. + +Tested: + - Create subscription failed with error(bad request) + when the request body contain both "RegistryPrefixes" + and "MessageIds". + +Change-Id: I4c14f946977bce2ced8a7f96eb85855117fde9a8 +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + redfish-core/include/error_messages.hpp | 14 +++++++++++ + .../include/registries/base_message_registry.hpp | 18 +++++++++++++- + redfish-core/lib/event_service.hpp | 10 ++++++++ + redfish-core/src/error_messages.cpp | 29 ++++++++++++++++++++++ + 4 files changed, 70 insertions(+), 1 deletion(-) + +diff --git a/redfish-core/include/error_messages.hpp b/redfish-core/include/error_messages.hpp +index 0243be9..9a2d1ca 100644 +--- a/redfish-core/include/error_messages.hpp ++++ b/redfish-core/include/error_messages.hpp +@@ -787,6 +787,20 @@ nlohmann::json invalidUpload(const std::string& arg1, const std::string& arg2); + void invalidUpload(crow::Response& res, const std::string& arg1, + const std::string& arg2); + ++/** ++ * @brief Formats MutualExclusiveProperties message into JSON ++ * Message body: "The properties <arg1> and <arg2> are mutually exclusive." ++ * ++ * @param[in] arg1 Parameter of message that will replace %1 in its body. ++ * @param[in] arg2 Parameter of message that will replace %2 in its body. ++ * ++ * @returns Message MutualExclusiveProperties formatted to JSON */ ++nlohmann::json mutualExclusiveProperties(const std::string& arg1, ++ const std::string& arg2); ++ ++void mutualExclusiveProperties(crow::Response& res, const std::string& arg1, ++ const std::string& arg2); ++ + } // namespace messages + + } // namespace redfish +diff --git a/redfish-core/include/registries/base_message_registry.hpp b/redfish-core/include/registries/base_message_registry.hpp +index 90aef56..7c385a0 100644 +--- a/redfish-core/include/registries/base_message_registry.hpp ++++ b/redfish-core/include/registries/base_message_registry.hpp +@@ -36,7 +36,7 @@ const Header header = { + constexpr const char* url = + "https://redfish.dmtf.org/registries/Base.1.8.1.json"; + +-constexpr std::array<MessageEntry, 73> registry = { ++constexpr std::array<MessageEntry, 74> registry = { + MessageEntry{ + "AccessDenied", + { +@@ -429,6 +429,22 @@ constexpr std::array<MessageEntry, 73> registry = { + "Resolve other reported errors and retry the current operation.", + }}, + MessageEntry{ ++ "MutualExclusiveProperties", ++ { ++ "Indicates that the requested operation could not be completed, " ++ "because of a conflict properties.", ++ "The properties '%1' and '%2' are mutually exclusive.", ++ "Warning", ++ "Warning", ++ 2, ++ { ++ "string", ++ "string", ++ }, ++ "Ensure that the request body doesn't have mutually exclusive " ++ "properties and resubmit the request.", ++ }}, ++ MessageEntry{ + "NoOperation", + { + "Indicates that the requested operation will not perform any " +diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp +index f59d093..4804d26 100644 +--- a/redfish-core/lib/event_service.hpp ++++ b/redfish-core/lib/event_service.hpp +@@ -242,6 +242,16 @@ class EventDestinationCollection : public Node + return; + } + ++ if (regPrefixes && msgIds) ++ { ++ if (regPrefixes->size() && msgIds->size()) ++ { ++ messages::mutualExclusiveProperties( ++ asyncResp->res, "RegistryPrefixes", "MessageIds"); ++ return; ++ } ++ } ++ + // Validate the URL using regex expression + // Format: <protocol>://<host>:<port>/<uri> + // protocol: http/https +diff --git a/redfish-core/src/error_messages.cpp b/redfish-core/src/error_messages.cpp +index 160b73f..c6938ba 100644 +--- a/redfish-core/src/error_messages.cpp ++++ b/redfish-core/src/error_messages.cpp +@@ -1750,6 +1750,35 @@ nlohmann::json invalidUpload(const std::string& arg1, const std::string& arg2) + {"Resolution", "None."}}; + } + ++/** ++ * @internal ++ * @brief Formats MutualExclusiveProperties into JSON ++ * ++ * See header file for more information ++ * @endinternal ++ */ ++nlohmann::json mutualExclusiveProperties(const std::string& arg1, ++ const std::string& arg2) ++{ ++ return nlohmann::json{ ++ {"@odata.type", "#Message.v1_0_0.Message"}, ++ {"MessageId", "Base.1.5.0.MutualExclusiveProperties"}, ++ {"Message", "The properties " + arg1 + " and " + arg2 + ++ " are mutually exclusive."}, ++ {"MessageArgs", {arg1, arg2}}, ++ {"Severity", "Warning"}, ++ {"Resolution", ++ "Ensure that the request body doesn't contain mutually exclusive " ++ "properties and resubmit the request."}}; ++} ++ ++void mutualExclusiveProperties(crow::Response& res, const std::string& arg1, ++ const std::string& arg2) ++{ ++ res.result(boost::beast::http::status::bad_request); ++ addMessageToErrorJson(res.jsonValue, mutualExclusiveProperties(arg1, arg2)); ++} ++ + } // namespace messages + + } // namespace redfish +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0018-Add-sse-event-sequence-number.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0018-Add-sse-event-sequence-number.patch new file mode 100644 index 000000000..e2b8644d8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0018-Add-sse-event-sequence-number.patch @@ -0,0 +1,74 @@ +From c03fa3c7b6c98d299f18e106c1aabf655db10327 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Fri, 4 Sep 2020 16:44:52 +0530 +Subject: [PATCH] Add sse event sequence number + +Add sequence number to sse events. +This is different for event ID's. + +Tested: + - The sequence number increments properly + after sending sse events. + +Change-Id: I8f48082497094a0435d4a400cb8068c3af506a7a +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + redfish-core/include/event_service_manager.hpp | 2 +- + redfish-core/include/server_sent_events.hpp | 7 ++++--- + 2 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index 4671995..1a99e54 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -415,7 +415,7 @@ class Subscription + + if (sseConn != nullptr) + { +- sseConn->sendData(eventSeqNum, msg); ++ sseConn->sendData(msg); + } + } + +diff --git a/redfish-core/include/server_sent_events.hpp b/redfish-core/include/server_sent_events.hpp +index 1c4d2a5..23517ca 100644 +--- a/redfish-core/include/server_sent_events.hpp ++++ b/redfish-core/include/server_sent_events.hpp +@@ -56,6 +56,7 @@ class ServerSentEvents : public std::enable_shared_from_this<ServerSentEvents> + SseConnState state; + int retryCount; + int maxRetryAttempts; ++ uint64_t sseEventId; + + void sendEvent(const std::string& id, const std::string& msg) + { +@@ -260,7 +261,7 @@ class ServerSentEvents : public std::enable_shared_from_this<ServerSentEvents> + + ServerSentEvents(const std::shared_ptr<crow::Request::Adaptor>& adaptor) : + sseConn(std::move(adaptor)), state(SseConnState::startInit), +- retryCount(0), maxRetryAttempts(5) ++ retryCount(0), maxRetryAttempts(5), sseEventId(1) + { + startSSE(); + } +@@ -268,7 +269,7 @@ class ServerSentEvents : public std::enable_shared_from_this<ServerSentEvents> + ~ServerSentEvents() + {} + +- void sendData(const uint64_t& id, const std::string& data) ++ void sendData(const std::string& data) + { + if (state == SseConnState::suspended) + { +@@ -277,7 +278,7 @@ class ServerSentEvents : public std::enable_shared_from_this<ServerSentEvents> + + if (requestDataQueue.size() <= maxReqQueueSize) + { +- requestDataQueue.push(std::pair(id, data)); ++ requestDataQueue.push(std::pair(sseEventId++, data)); + checkQueue(true); + } + else +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0019-EventService-Limit-SSE-connections-as-per-design.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0019-EventService-Limit-SSE-connections-as-per-design.patch new file mode 100644 index 000000000..c6c0634ce --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0019-EventService-Limit-SSE-connections-as-per-design.patch @@ -0,0 +1,108 @@ +From eb1f888660bd34bde0c049e48db2404803b57d6e Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Tue, 8 Sep 2020 02:37:19 +0530 +Subject: [PATCH] EventService: Limit SSE connections as per design + +Limit the number of SSE connections for event service. + +Tested: + - Tried creating more than 10 SSE connections and it fails. + +Change-Id: I4c7aa5c05a832115717e1261e330350ce59ab630 +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + redfish-core/include/event_service_manager.hpp | 17 +++++++++++++++++ + redfish-core/lib/event_service.hpp | 14 +++++++++----- + 2 files changed, 26 insertions(+), 5 deletions(-) + +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index 502a6f7..22d1f10 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -44,6 +44,9 @@ using EventServiceConfig = std::tuple<bool, uint32_t, uint32_t>; + static constexpr const char* eventFormatType = "Event"; + static constexpr const char* metricReportFormatType = "MetricReport"; + ++static constexpr const char* subscriptionTypeRedfishEvent = "RedfishEvent"; ++static constexpr const char* subscriptionTypeSSE = "SSE"; ++ + static constexpr const char* eventServiceFile = + "/var/lib/bmcweb/eventservice_config.json"; + +@@ -983,6 +986,20 @@ class EventServiceManager + return subscriptionsMap.size(); + } + ++ size_t getNumberOfSSESubscriptions() ++ { ++ size_t count = 0; ++ for (const auto& it : this->subscriptionsMap) ++ { ++ std::shared_ptr<Subscription> entry = it.second; ++ if (entry->subscriptionType == subscriptionTypeSSE) ++ { ++ count++; ++ } ++ } ++ return count; ++ } ++ + std::vector<std::string> getAllIDs() + { + std::vector<std::string> idList; +diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp +index 4804d26..f14c03e 100644 +--- a/redfish-core/lib/event_service.hpp ++++ b/redfish-core/lib/event_service.hpp +@@ -27,6 +27,7 @@ static constexpr const std::array<const char*, 3> supportedRetryPolicies = { + "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; + + static constexpr const uint8_t maxNoOfSubscriptions = 20; ++static constexpr const uint8_t maxNoOfSSESubscriptions = 10; + + class EventService : public Node + { +@@ -307,7 +308,7 @@ class EventDestinationCollection : public Node + + if (subscriptionType) + { +- if (*subscriptionType != "RedfishEvent") ++ if (*subscriptionType != subscriptionTypeRedfishEvent) + { + messages::propertyValueNotInList( + asyncResp->res, *subscriptionType, "SubscriptionType"); +@@ -317,7 +318,8 @@ class EventDestinationCollection : public Node + } + else + { +- subValue->subscriptionType = "RedfishEvent"; // Default ++ subValue->subscriptionType = ++ subscriptionTypeRedfishEvent; // Default + } + + if (protocol != "Redfish") +@@ -450,8 +452,10 @@ class EventServiceSSE : public Node + void doGet(crow::Response& res, const crow::Request& req, + const std::vector<std::string>& params) override + { +- if (EventServiceManager::getInstance().getNumberOfSubscriptions() >= +- maxNoOfSubscriptions) ++ if ((EventServiceManager::getInstance().getNumberOfSubscriptions() >= ++ maxNoOfSubscriptions) || ++ EventServiceManager::getInstance().getNumberOfSSESubscriptions() >= ++ maxNoOfSSESubscriptions) + { + messages::eventSubscriptionLimitExceeded(res); + res.end(); +@@ -464,7 +468,7 @@ class EventServiceSSE : public Node + std::make_shared<Subscription>(sseConn); + + // GET on this URI means, Its SSE subscriptionType. +- subValue->subscriptionType = "SSE"; ++ subValue->subscriptionType = subscriptionTypeSSE; + + // Default values + subValue->protocol = "Redfish"; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0020-EventService-Validate-SSE-query-filters.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0020-EventService-Validate-SSE-query-filters.patch new file mode 100644 index 000000000..8f3e1fc9b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0020-EventService-Validate-SSE-query-filters.patch @@ -0,0 +1,262 @@ +From 5fd71f098aad2f6d64e94343738c43ffdff5709e Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Tue, 8 Sep 2020 16:19:30 +0530 +Subject: [PATCH] EventService: Validate SSE query filters + +Validate the query filters which are specified in +requested url and return with error if not supported. +Also RegistryPrefix and MessageId are mutually exclusive +as per redfish specification. so return error if user +specifies both. + +Tested: + - Checked with invalid query filters and it returns + the error. + +Change-Id: If07341f39d8c6b9bc229baae966f8569ebdd7b19 +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + redfish-core/include/error_messages.hpp | 9 ++ + .../include/registries/base_message_registry.hpp | 14 ++- + redfish-core/lib/event_service.hpp | 99 +++++++++++++++------- + redfish-core/src/error_messages.cpp | 26 ++++++ + 4 files changed, 116 insertions(+), 32 deletions(-) + +diff --git a/redfish-core/include/error_messages.hpp b/redfish-core/include/error_messages.hpp +index 9a2d1ca..fd6bb48 100644 +--- a/redfish-core/include/error_messages.hpp ++++ b/redfish-core/include/error_messages.hpp +@@ -801,6 +801,15 @@ nlohmann::json mutualExclusiveProperties(const std::string& arg1, + void mutualExclusiveProperties(crow::Response& res, const std::string& arg1, + const std::string& arg2); + ++/** ++ * @brief Formats InvalidQueryFilter message into JSON ++ * Message body: "The requested URL contains the invalid query filters" ++ * ++ * @returns Message InvalidQueryFilter formatted to JSON */ ++nlohmann::json invalidQueryFilter(); ++ ++void invalidQueryFilter(crow::Response& res); ++ + } // namespace messages + + } // namespace redfish +diff --git a/redfish-core/include/registries/base_message_registry.hpp b/redfish-core/include/registries/base_message_registry.hpp +index 7c385a0..18085c8 100644 +--- a/redfish-core/include/registries/base_message_registry.hpp ++++ b/redfish-core/include/registries/base_message_registry.hpp +@@ -36,7 +36,7 @@ const Header header = { + constexpr const char* url = + "https://redfish.dmtf.org/registries/Base.1.8.1.json"; + +-constexpr std::array<MessageEntry, 74> registry = { ++constexpr std::array<MessageEntry, 75> registry = { + MessageEntry{ + "AccessDenied", + { +@@ -403,6 +403,18 @@ constexpr std::array<MessageEntry, 74> registry = { + "Either the object is malformed or the URI is not correct. " + "Correct the condition and resubmit the request if it failed.", + }}, ++ MessageEntry{ ++ "InvalidQueryFilter", ++ { ++ "Indicates the request url contains invalid query filter.", ++ "The requested url contains the invalid query filter.", ++ "Warning", ++ "Warning", ++ 0, ++ {}, ++ "Ensure the correct query filter is specified in requested url " ++ "and resubmit the request if the operation failed.", ++ }}, + MessageEntry{"MalformedJSON", + { + "Indicates that the request body was malformed JSON. " +diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp +index f14c03e..b91b745 100644 +--- a/redfish-core/lib/event_service.hpp ++++ b/redfish-core/lib/event_service.hpp +@@ -462,73 +462,110 @@ class EventServiceSSE : public Node + return; + } + +- std::shared_ptr<crow::Request::Adaptor> sseConn = +- std::make_shared<crow::Request::Adaptor>(std::move(req.socket())); +- std::shared_ptr<Subscription> subValue = +- std::make_shared<Subscription>(sseConn); +- +- // GET on this URI means, Its SSE subscriptionType. +- subValue->subscriptionType = subscriptionTypeSSE; +- +- // Default values +- subValue->protocol = "Redfish"; +- subValue->retryPolicy = "TerminateAfterRetries"; +- +- boost::urls::url_view::params_type::iterator it = +- req.urlParams.find("$filter"); +- if (it == req.urlParams.end()) ++ // It supports only "$filter" query param. ++ if (req.urlParams.size() > 1) + { +- subValue->eventFormatType = "Event"; ++ messages::invalidQueryFilter(res); ++ res.end(); ++ return; + } + ++ std::string eventFormatType; ++ std::string queryFilters; ++ if (req.urlParams.size()) ++ { ++ boost::urls::url_view::params_type::iterator it = ++ req.urlParams.find("$filter"); ++ if (it == req.urlParams.end()) ++ { ++ messages::invalidQueryFilter(res); ++ res.end(); ++ return; ++ } ++ else ++ { ++ queryFilters = it->value(); ++ } ++ } + else + { +- std::string filters = it->value(); +- // Reading from query params. +- bool status = readSSEQueryParams( +- filters, subValue->eventFormatType, subValue->registryMsgIds, +- subValue->registryPrefixes, subValue->metricReportDefinitions); ++ eventFormatType = "Event"; ++ } + ++ std::vector<std::string> msgIds; ++ std::vector<std::string> regPrefixes; ++ std::vector<std::string> mrdsArray; ++ if (!queryFilters.empty()) ++ { ++ // Reading from query params. ++ bool status = readSSEQueryParams(queryFilters, eventFormatType, ++ msgIds, regPrefixes, mrdsArray); + if (!status) + { +- messages::invalidObject(res, filters); ++ messages::invalidObject(res, queryFilters); ++ res.end(); + return; + } + +- if (!subValue->eventFormatType.empty()) ++ // RegsitryPrefix and messageIds are mutuly exclusive as per redfish ++ // specification. ++ if (regPrefixes.size() && msgIds.size()) ++ { ++ messages::mutualExclusiveProperties(res, "RegistryPrefix", ++ "MessageId"); ++ res.end(); ++ return; ++ } ++ ++ if (!eventFormatType.empty()) + { + if (std::find(supportedEvtFormatTypes.begin(), + supportedEvtFormatTypes.end(), +- subValue->eventFormatType) == +- supportedEvtFormatTypes.end()) ++ eventFormatType) == supportedEvtFormatTypes.end()) + { +- messages::propertyValueNotInList( +- res, subValue->eventFormatType, "EventFormatType"); ++ messages::propertyValueNotInList(res, eventFormatType, ++ "EventFormatType"); ++ res.end(); + return; + } + } + else + { + // If nothing specified, using default "Event" +- subValue->eventFormatType.assign({"Event"}); ++ eventFormatType.assign({"Event"}); + } + +- if (!subValue->registryPrefixes.empty()) ++ if (!regPrefixes.empty()) + { +- for (const std::string& it : subValue->registryPrefixes) ++ for (const std::string& it : regPrefixes) + { + if (std::find(supportedRegPrefixes.begin(), + supportedRegPrefixes.end(), + it) == supportedRegPrefixes.end()) + { + messages::propertyValueNotInList(res, it, +- "RegistryPrefixes"); ++ "RegistryPrefix"); ++ res.end(); + return; + } + } + } + } + ++ std::shared_ptr<crow::Request::Adaptor> sseConn = ++ std::make_shared<crow::Request::Adaptor>(std::move(req.socket())); ++ std::shared_ptr<Subscription> subValue = ++ std::make_shared<Subscription>(sseConn); ++ ++ // GET on this URI means, Its SSE subscriptionType. ++ subValue->subscriptionType = subscriptionTypeSSE; ++ subValue->protocol = "Redfish"; ++ subValue->retryPolicy = "TerminateAfterRetries"; ++ subValue->eventFormatType = eventFormatType; ++ subValue->registryMsgIds = msgIds; ++ subValue->registryPrefixes = regPrefixes; ++ subValue->metricReportDefinitions = mrdsArray; ++ + std::string id = + EventServiceManager::getInstance().addSubscription(subValue, false); + if (id.empty()) +diff --git a/redfish-core/src/error_messages.cpp b/redfish-core/src/error_messages.cpp +index c6938ba..290d3f2 100644 +--- a/redfish-core/src/error_messages.cpp ++++ b/redfish-core/src/error_messages.cpp +@@ -1779,6 +1779,32 @@ void mutualExclusiveProperties(crow::Response& res, const std::string& arg1, + addMessageToErrorJson(res.jsonValue, mutualExclusiveProperties(arg1, arg2)); + } + ++/** ++ * @internal ++ * @brief Formats InvalidQueryFilter into JSON ++ * ++ * See header file for more information ++ * @endinternal ++ */ ++nlohmann::json invalidQueryFilter() ++{ ++ return nlohmann::json{ ++ {"@odata.type", "#Message.v1_0_0.Message"}, ++ {"MessageId", "Base.1.5.0.InvalidQueryFilter"}, ++ {"Message", "The requested url contains the invalid query filter."}, ++ {"MessageArgs", nlohmann::json::array()}, ++ {"Severity", "Warning"}, ++ {"Resolution", ++ "Ensure the correct query filter is specified in requested url " ++ "and resubmit the request."}}; ++} ++ ++void invalidQueryFilter(crow::Response& res) ++{ ++ res.result(boost::beast::http::status::bad_request); ++ addMessageToErrorJson(res.jsonValue, invalidQueryFilter()); ++} ++ + } // namespace messages + + } // namespace redfish +-- +2.7.4 + |