blob: 05ccb42d223a2cdb732102fb7c45cf07af5eb63e [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matt Spinler4e8078c2019-07-09 13:22:32 -050016#include "manager.hpp"
17
18#include "additional_data.hpp"
Matt Spinler05c2c6c2019-12-18 14:02:09 -060019#include "json_utils.hpp"
Matt Spinler89fa0822019-07-17 13:54:30 -050020#include "pel.hpp"
21
Matt Spinler6b1a5c82020-01-07 08:48:53 -060022#include <unistd.h>
23
Matt Spinler89fa0822019-07-17 13:54:30 -050024#include <filesystem>
25#include <fstream>
Matt Spinlera34ab722019-12-16 10:39:32 -060026#include <xyz/openbmc_project/Common/error.hpp>
Matt Spinler4e8078c2019-07-09 13:22:32 -050027
28namespace openpower
29{
30namespace pels
31{
32
33using namespace phosphor::logging;
Matt Spinler89fa0822019-07-17 13:54:30 -050034namespace fs = std::filesystem;
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +080035namespace rg = openpower::pels::message;
Matt Spinler4e8078c2019-07-09 13:22:32 -050036
Matt Spinlera34ab722019-12-16 10:39:32 -060037namespace common_error = sdbusplus::xyz::openbmc_project::Common::Error;
38
Matt Spinler4e8078c2019-07-09 13:22:32 -050039namespace additional_data
40{
41constexpr auto rawPEL = "RAWPEL";
42}
43
44void Manager::create(const std::string& message, uint32_t obmcLogID,
45 uint64_t timestamp, Entry::Level severity,
46 const std::vector<std::string>& additionalData,
47 const std::vector<std::string>& associations)
48{
49 AdditionalData ad{additionalData};
50
51 // If a PEL was passed in, use that. Otherwise, create one.
52 auto rawPelPath = ad.getValue(additional_data::rawPEL);
53 if (rawPelPath)
54 {
55 addRawPEL(*rawPelPath, obmcLogID);
56 }
57 else
58 {
59 createPEL(message, obmcLogID, timestamp, severity, additionalData,
60 associations);
61 }
62}
63
64void Manager::addRawPEL(const std::string& rawPelPath, uint32_t obmcLogID)
65{
Matt Spinler89fa0822019-07-17 13:54:30 -050066 if (fs::exists(rawPelPath))
67 {
68 std::ifstream file(rawPelPath, std::ios::in | std::ios::binary);
69
70 auto data = std::vector<uint8_t>(std::istreambuf_iterator<char>(file),
71 std::istreambuf_iterator<char>());
72 if (file.fail())
73 {
74 log<level::ERR>("Filesystem error reading a raw PEL",
75 entry("PELFILE=%s", rawPelPath.c_str()),
76 entry("OBMCLOGID=%d", obmcLogID));
77 // TODO, Decide what to do here. Maybe nothing.
78 return;
79 }
80
81 file.close();
82
Matt Spinlera34ab722019-12-16 10:39:32 -060083 auto pel = std::make_unique<openpower::pels::PEL>(data, obmcLogID);
Matt Spinler89fa0822019-07-17 13:54:30 -050084 if (pel->valid())
85 {
86 // PELs created by others still need these fields set by us.
87 pel->assignID();
88 pel->setCommitTime();
89
90 try
91 {
92 _repo.add(pel);
93 }
94 catch (std::exception& e)
95 {
96 // Probably a full or r/o filesystem, not much we can do.
97 log<level::ERR>("Unable to add PEL to Repository",
98 entry("PEL_ID=0x%X", pel->id()));
99 }
100 }
101 else
102 {
Matt Spinlere95fd012020-01-07 12:53:16 -0600103 log<level::ERR>("Invalid PEL received from the host",
Matt Spinler89fa0822019-07-17 13:54:30 -0500104 entry("PELFILE=%s", rawPelPath.c_str()),
105 entry("OBMCLOGID=%d", obmcLogID));
Matt Spinlere95fd012020-01-07 12:53:16 -0600106
107 AdditionalData ad;
108 ad.add("PLID", getNumberString("0x%08X", pel->plid()));
109 ad.add("OBMC_LOG_ID", std::to_string(obmcLogID));
110 ad.add("RAW_PEL_FILENAME", rawPelPath);
111 ad.add("PEL_SIZE", std::to_string(data.size()));
112
113 std::string asciiString;
114 auto src = pel->primarySRC();
115 if (src)
116 {
117 asciiString = (*src)->asciiString();
118 }
119
120 ad.add("SRC", asciiString);
121
122 _eventLogger.log("org.open_power.Logging.Error.BadHostPEL",
123 Entry::Level::Error, ad);
Matt Spinler89fa0822019-07-17 13:54:30 -0500124 }
125 }
126 else
127 {
128 log<level::ERR>("Raw PEL file from BMC event log does not exist",
129 entry("PELFILE=%s", (rawPelPath).c_str()),
130 entry("OBMCLOGID=%d", obmcLogID));
131 }
Matt Spinler4e8078c2019-07-09 13:22:32 -0500132}
133
134void Manager::erase(uint32_t obmcLogID)
135{
Matt Spinler475e5742019-07-18 16:09:49 -0500136 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
137
138 _repo.remove(id);
Matt Spinler4e8078c2019-07-09 13:22:32 -0500139}
140
141bool Manager::isDeleteProhibited(uint32_t obmcLogID)
142{
143 return false;
144}
145
146void Manager::createPEL(const std::string& message, uint32_t obmcLogID,
147 uint64_t timestamp,
148 phosphor::logging::Entry::Level severity,
149 const std::vector<std::string>& additionalData,
150 const std::vector<std::string>& associations)
151{
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800152 auto entry = _registry.lookup(message, rg::LookupType::name);
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600153 std::string msg;
Matt Spinler67456c22019-10-21 12:22:49 -0500154
155 if (entry)
156 {
157 AdditionalData ad{additionalData};
158
Matt Spinlera34ab722019-12-16 10:39:32 -0600159 auto pel = std::make_unique<openpower::pels::PEL>(
160 *entry, obmcLogID, timestamp, severity, ad, *_dataIface);
Matt Spinler67456c22019-10-21 12:22:49 -0500161
162 _repo.add(pel);
Matt Spinler67456c22019-10-21 12:22:49 -0500163
Matt Spinler1d4c74a2019-12-16 14:40:21 -0600164 auto src = pel->primarySRC();
165 if (src)
166 {
167 using namespace std::literals::string_literals;
168 char id[11];
169 sprintf(id, "0x%08X", pel->id());
170 msg = "Created PEL "s + id + " with SRC "s + (*src)->asciiString();
171 while (msg.back() == ' ')
172 {
173 msg.pop_back();
174 }
175 log<level::INFO>(msg.c_str());
176 }
177 }
178 else
179 {
180 // TODO ibm-openbmc/dev/1151: Create a new PEL for this case.
181 // For now, just trace it.
182 msg = "Event not found in PEL message registry: " + message;
183 log<level::INFO>(msg.c_str());
184 }
Matt Spinler4e8078c2019-07-09 13:22:32 -0500185}
186
Matt Spinlera34ab722019-12-16 10:39:32 -0600187sdbusplus::message::unix_fd Manager::getPEL(uint32_t pelID)
188{
189 Repository::LogID id{Repository::LogID::Pel(pelID)};
190 std::optional<int> fd;
191
192 try
193 {
194 fd = _repo.getPELFD(id);
195 }
196 catch (std::exception& e)
197 {
198 throw common_error::InternalFailure();
199 }
200
201 if (!fd)
202 {
203 throw common_error::InvalidArgument();
204 }
205
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600206 scheduleFDClose(*fd);
207
Matt Spinlera34ab722019-12-16 10:39:32 -0600208 return *fd;
209}
210
Matt Spinler6b1a5c82020-01-07 08:48:53 -0600211void Manager::scheduleFDClose(int fd)
212{
213 _fdCloserEventSource = std::make_unique<sdeventplus::source::Defer>(
214 _logManager.getBus().get_event(),
215 std::bind(std::mem_fn(&Manager::closeFD), this, fd,
216 std::placeholders::_1));
217}
218
219void Manager::closeFD(int fd, sdeventplus::source::EventBase& source)
220{
221 close(fd);
222 _fdCloserEventSource.reset();
223}
224
Matt Spinlera34ab722019-12-16 10:39:32 -0600225std::vector<uint8_t> Manager::getPELFromOBMCID(uint32_t obmcLogID)
226{
227 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
228 std::optional<std::vector<uint8_t>> data;
229
230 try
231 {
232 data = _repo.getPELData(id);
233 }
234 catch (std::exception& e)
235 {
236 throw common_error::InternalFailure();
237 }
238
239 if (!data)
240 {
241 throw common_error::InvalidArgument();
242 }
243
244 return *data;
245}
246
247void Manager::hostAck(uint32_t pelID)
248{
249 Repository::LogID id{Repository::LogID::Pel(pelID)};
250
251 if (!_repo.hasPEL(id))
252 {
253 throw common_error::InvalidArgument();
254 }
255
256 if (_hostNotifier)
257 {
258 _hostNotifier->ackPEL(pelID);
259 }
260}
261
262void Manager::hostReject(uint32_t pelID, RejectionReason reason)
263{
264 Repository::LogID id{Repository::LogID::Pel(pelID)};
265
266 if (!_repo.hasPEL(id))
267 {
268 throw common_error::InvalidArgument();
269 }
270
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600271 if (reason == RejectionReason::BadPEL)
Matt Spinlera34ab722019-12-16 10:39:32 -0600272 {
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600273 AdditionalData data;
274 data.add("BAD_ID", getNumberString("0x%08X", pelID));
275 _eventLogger.log("org.open_power.Logging.Error.SentBadPELToHost",
276 Entry::Level::Informational, data);
277 if (_hostNotifier)
Matt Spinlera34ab722019-12-16 10:39:32 -0600278 {
279 _hostNotifier->setBadPEL(pelID);
280 }
Matt Spinler05c2c6c2019-12-18 14:02:09 -0600281 }
282 else if ((reason == RejectionReason::HostFull) && _hostNotifier)
283 {
284 _hostNotifier->setHostFull(pelID);
Matt Spinlera34ab722019-12-16 10:39:32 -0600285 }
286}
287
Matt Spinler4e8078c2019-07-09 13:22:32 -0500288} // namespace pels
289} // namespace openpower