blob: 0b474711aad0d8a3422244fcebf2d14ff1b17306 [file] [log] [blame]
manojkiraneda0b631ae2019-12-03 17:54:28 +05301#pragma once
2
manojkiraneda0b631ae2019-12-03 17:54:28 +05303#include <boost/algorithm/string.hpp>
4#include <boost/container/flat_map.hpp>
Manojkiran Eda55fd1a92020-04-30 19:06:48 +05305#include <boost/endian/conversion.hpp>
Sunitha Harish3e919b52020-10-13 01:21:48 -05006#include <include/ibm/utils.hpp>
Ed Tanous04e438c2020-10-03 08:06:26 -07007#include <logging.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -05008#include <nlohmann/json.hpp>
9
manojkiraneda0b631ae2019-12-03 17:54:28 +053010#include <filesystem>
Sunitha Harish8a3bb712019-12-13 03:48:09 -060011#include <fstream>
manojkiraneda0b631ae2019-12-03 17:54:28 +053012
13namespace crow
14{
15namespace ibm_mc_lock
16{
17
manojkiraneda0b631ae2019-12-03 17:54:28 +053018using SType = std::string;
19
20/*----------------------------------------
21|Segment flags : LockFlag | SegmentLength|
22------------------------------------------*/
23
24using SegmentFlags = std::vector<std::pair<SType, uint32_t>>;
25
26// Lockrequest = session-id | hmc-id | locktype | resourceid | segmentinfo
27using LockRequest = std::tuple<SType, SType, SType, uint64_t, SegmentFlags>;
manojkiraneda0b631ae2019-12-03 17:54:28 +053028using LockRequests = std::vector<LockRequest>;
29using Rc =
30 std::pair<bool, std::variant<uint32_t, std::pair<uint32_t, LockRequest>>>;
manojkiraneda3b6dea62019-12-13 17:05:36 +053031using RcRelaseLock = std::pair<bool, std::pair<uint32_t, LockRequest>>;
manojkiraneda402b5712019-12-13 17:07:09 +053032using RcGetLockList =
33 std::variant<std::string, std::vector<std::pair<uint32_t, LockRequests>>>;
manojkiraneda3b6dea62019-12-13 17:05:36 +053034using ListOfTransactionIds = std::vector<uint32_t>;
manojkiraneda0b631ae2019-12-03 17:54:28 +053035using RcAcquireLock = std::pair<bool, std::variant<Rc, std::pair<bool, int>>>;
manojkiraneda3b6dea62019-12-13 17:05:36 +053036using RcReleaseLockApi = std::pair<bool, std::variant<bool, RcRelaseLock>>;
37using SessionFlags = std::pair<SType, SType>;
manojkiraneda402b5712019-12-13 17:07:09 +053038using ListOfSessionIds = std::vector<std::string>;
Gunnar Mills1214b7e2020-06-04 10:11:30 -050039static constexpr const char* fileName =
Sunitha Harish3e919b52020-10-13 01:21:48 -050040 "/var/lib/bmcweb/ibm-management-console/locks/"
41 "ibm_mc_persistent_lock_data.json";
manojkiraneda0b631ae2019-12-03 17:54:28 +053042
43class Lock
44{
45 uint32_t transactionId;
46 boost::container::flat_map<uint32_t, LockRequests> lockTable;
47
48 /*
Sunitha Harish8a3bb712019-12-13 03:48:09 -060049 * This API implements the logic to load the locks that are present in the
50 * json file into the lock table.
51 */
52 void loadLocks();
53
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053054 protected:
55 /*
Sunitha Harish3e919b52020-10-13 01:21:48 -050056 * This API implements the logic to persist the locks that are contained in
57 * the lock table into a json file.
58 */
59 void saveLocks();
60
61 /*
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053062 * This function implements the logic for validating an incoming
63 * lock request/requests.
64 *
65 * Returns : True (if Valid)
66 * Returns : False (if not a Valid lock request)
67 */
68
Ed Tanousb5a76932020-09-29 16:16:58 -070069 virtual bool isValidLockRequest(const LockRequest&);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053070
71 /*
72 * This function implements the logic of checking if the incoming
73 * multi-lock request is not having conflicting requirements.
74 *
75 * Returns : True (if conflicting)
76 * Returns : False (if not conflicting)
77 */
78
Ed Tanousb5a76932020-09-29 16:16:58 -070079 virtual bool isConflictRequest(const LockRequests&);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053080 /*
81 * Implements the core algorithm to find the conflicting
82 * lock requests.
83 *
84 * This functions takes two lock requests and check if both
85 * are conflicting to each other.
86 *
87 * Returns : True (if conflicting)
88 * Returns : False (if not conflicting)
89 */
Ed Tanousb5a76932020-09-29 16:16:58 -070090 virtual bool isConflictRecord(const LockRequest&, const LockRequest&);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053091
92 /*
93 * This function implements the logic of checking the conflicting
94 * locks from a incoming single/multi lock requests with the already
95 * existing lock request in the lock table.
96 *
97 */
98
Ed Tanousb5a76932020-09-29 16:16:58 -070099 virtual Rc isConflictWithTable(const LockRequests&);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530100 /*
101 * This function implements the logic of checking the ownership of the
102 * lock from the releaselock request.
103 *
104 * Returns : True (if the requesting HMC & Session owns the lock(s))
105 * Returns : False (if the request HMC or Session does not own the lock(s))
106 */
107
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500108 virtual RcRelaseLock isItMyLock(const ListOfTransactionIds&,
109 const SessionFlags&);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530110
111 /*
112 * This function validates the the list of transactionID's and returns false
113 * if the transaction ID is not valid & not present in the lock table
114 */
115
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500116 virtual bool validateRids(const ListOfTransactionIds&);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530117
118 /*
119 * This function releases the locks that are already obtained by the
120 * requesting Management console.
121 */
122
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500123 void releaseLock(const ListOfTransactionIds&);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530124
125 Lock()
126 {
127 loadLocks();
128 transactionId = lockTable.empty() ? 0 : prev(lockTable.end())->first;
129 }
130
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600131 /*
manojkiraneda0b631ae2019-12-03 17:54:28 +0530132 * This function implements the algorithm for checking the respective
133 * bytes of the resource id based on the lock management algorithm.
134 */
135
136 bool checkByte(uint64_t, uint64_t, uint32_t);
137
138 /*
139 * This functions implements a counter that generates a unique 32 bit
140 * number for every successful transaction. This number will be used by
141 * the Management Console for debug.
142 */
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530143 virtual uint32_t generateTransactionId();
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600144
manojkiraneda0b631ae2019-12-03 17:54:28 +0530145 public:
146 /*
147 * This function implements the logic for acquiring a lock on a
Manojkiran Eda5bb0ece2020-01-20 20:22:36 +0530148 * resource if the incoming request is legitimate without any
manojkiraneda0b631ae2019-12-03 17:54:28 +0530149 * conflicting requirements & without any conflicting requirement
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500150 * with the existing locks in the lock table.
manojkiraneda0b631ae2019-12-03 17:54:28 +0530151 *
152 */
153
Ed Tanousb5a76932020-09-29 16:16:58 -0700154 RcAcquireLock acquireLock(const LockRequests&);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530155
manojkiraneda3b6dea62019-12-13 17:05:36 +0530156 /*
157 * This function implements the logic for releasing the lock that are
158 * owned by a management console session.
159 *
160 * The locks can be released by two ways
161 * - Using list of transaction ID's
162 * - Using a Session ID
163 *
164 * Client can choose either of the ways by using `Type` JSON key.
165 *
166 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500167 RcReleaseLockApi releaseLock(const ListOfTransactionIds&,
168 const SessionFlags&);
manojkiraneda3b6dea62019-12-13 17:05:36 +0530169
manojkiraneda402b5712019-12-13 17:07:09 +0530170 /*
171 * This function implements the logic for getting the list of locks obtained
172 * by a particular management console.
173 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500174 RcGetLockList getLockList(const ListOfSessionIds&);
manojkiraneda402b5712019-12-13 17:07:09 +0530175
Ratan Gupta07386c62019-12-14 14:06:09 +0530176 /*
177 * This function is releases all the locks obtained by a particular
178 * session.
179 */
180
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500181 void releaseLock(const std::string&);
Ratan Gupta07386c62019-12-14 14:06:09 +0530182
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500183 static Lock& getInstance()
Ratan Gupta07386c62019-12-14 14:06:09 +0530184 {
185 static Lock lockObject;
186 return lockObject;
187 }
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530188
Ed Tanous4e087512020-09-28 18:41:25 -0700189 virtual ~Lock() = default;
Ratan Gupta07386c62019-12-14 14:06:09 +0530190};
manojkiraneda0b631ae2019-12-03 17:54:28 +0530191
Ratan Gupta07386c62019-12-14 14:06:09 +0530192inline void Lock::loadLocks()
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600193{
194 std::ifstream persistentFile(fileName);
195 if (persistentFile.is_open())
196 {
197 auto data = nlohmann::json::parse(persistentFile, nullptr, false);
198 if (data.is_discarded())
199 {
200 BMCWEB_LOG_ERROR << "Error parsing persistent data in json file.";
201 return;
202 }
203 BMCWEB_LOG_DEBUG << "The persistent lock data is available";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500204 for (const auto& item : data.items())
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600205 {
206 BMCWEB_LOG_DEBUG << item.key();
207 BMCWEB_LOG_DEBUG << item.value();
208 LockRequests locks = item.value();
Ratan Gupta07386c62019-12-14 14:06:09 +0530209 lockTable.emplace(std::pair<uint32_t, LockRequests>(
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600210 std::stoul(item.key()), locks));
211 BMCWEB_LOG_DEBUG << "The persistent lock data loaded";
212 }
213 }
214}
215
Ratan Gupta07386c62019-12-14 14:06:09 +0530216inline void Lock::saveLocks()
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600217{
218 std::error_code ec;
Sunitha Harish3e919b52020-10-13 01:21:48 -0500219 std::string_view path = "/var/lib/bmcweb/ibm-management-console/locks";
220 if (!crow::ibm_utils::createDirectory(path))
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600221 {
Sunitha Harish3e919b52020-10-13 01:21:48 -0500222 BMCWEB_LOG_DEBUG << "Failed to create lock persistent path";
223 return;
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600224 }
225 std::ofstream persistentFile(fileName);
Sunitha Harish3e919b52020-10-13 01:21:48 -0500226 // set the permission of the file to 600
Ed Tanousb5a76932020-09-29 16:16:58 -0700227 std::filesystem::perms permission = std::filesystem::perms::owner_read |
Sunitha Harish3e919b52020-10-13 01:21:48 -0500228 std::filesystem::perms::owner_write;
Ed Tanousb5a76932020-09-29 16:16:58 -0700229 std::filesystem::permissions(fileName, permission);
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600230 nlohmann::json data;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500231 for (const auto& it : lockTable)
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600232 {
233 data[std::to_string(it.first)] = it.second;
234 }
235 BMCWEB_LOG_DEBUG << "data is " << data;
236 persistentFile << data;
237}
238
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500239inline RcGetLockList Lock::getLockList(const ListOfSessionIds& listSessionId)
manojkiraneda402b5712019-12-13 17:07:09 +0530240{
241
242 std::vector<std::pair<uint32_t, LockRequests>> lockList;
243
244 if (!lockTable.empty())
245 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500246 for (const auto& i : listSessionId)
manojkiraneda402b5712019-12-13 17:07:09 +0530247 {
248 auto it = lockTable.begin();
249 while (it != lockTable.end())
250 {
251 // Check if session id of this entry matches with session id
252 // given
253 if (std::get<0>(it->second[0]) == i)
254 {
255 BMCWEB_LOG_DEBUG << "Session id is found in the locktable";
256
257 // Push the whole lock record into a vector for returning
258 // the json
Ed Tanous4e087512020-09-28 18:41:25 -0700259 lockList.emplace_back(it->first, it->second);
manojkiraneda402b5712019-12-13 17:07:09 +0530260 }
261 // Go to next entry in map
262 it++;
263 }
264 }
265 }
266 // we may have found at least one entry with the given session id
267 // return the json list of lock records pertaining to the given
268 // session id, or send an empty list if lock table is empty
Ed Tanous02379d32020-09-15 21:15:44 -0700269 return {lockList};
manojkiraneda402b5712019-12-13 17:07:09 +0530270}
271
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500272inline RcReleaseLockApi Lock::releaseLock(const ListOfTransactionIds& p,
273 const SessionFlags& ids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530274{
275
276 bool status = validateRids(p);
277
278 if (!status)
279 {
280 // Validation of rids failed
281 BMCWEB_LOG_DEBUG << "Not a Valid request id";
282 return std::make_pair(false, status);
283 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700284 // Validation passed, check if all the locks are owned by the
285 // requesting HMC
286 auto status2 = isItMyLock(p, ids);
287 if (status2.first)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530288 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700289 // The current hmc owns all the locks, so we can release
290 // them
291 releaseLock(p);
manojkiraneda3b6dea62019-12-13 17:05:36 +0530292 }
Manojkiran Edaa1ffbb82020-10-28 17:42:21 +0530293 return std::make_pair(true, status2);
manojkiraneda3b6dea62019-12-13 17:05:36 +0530294}
295
Ed Tanousb5a76932020-09-29 16:16:58 -0700296inline RcAcquireLock Lock::acquireLock(const LockRequests& lockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530297{
298
299 // validate the lock request
300
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500301 for (auto& lockRecord : lockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530302 {
303 bool status = isValidLockRequest(lockRecord);
304 if (!status)
305 {
306 BMCWEB_LOG_DEBUG << "Not a Valid record";
307 BMCWEB_LOG_DEBUG << "Bad json in request";
308 return std::make_pair(true, std::make_pair(status, 0));
309 }
310 }
311 // check for conflict record
312
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500313 const LockRequests& multiRequest = lockRequestStructure;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530314 bool status = isConflictRequest(multiRequest);
315
316 if (status)
317 {
318 BMCWEB_LOG_DEBUG << "There is a conflict within itself";
319 return std::make_pair(true, std::make_pair(status, 1));
320 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700321 BMCWEB_LOG_DEBUG << "The request is not conflicting within itself";
manojkiraneda0b631ae2019-12-03 17:54:28 +0530322
Ed Tanous3174e4d2020-10-07 11:41:22 -0700323 // Need to check for conflict with the locktable entries.
manojkiraneda0b631ae2019-12-03 17:54:28 +0530324
Ed Tanous3174e4d2020-10-07 11:41:22 -0700325 auto conflict = isConflictWithTable(multiRequest);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530326
Sunitha Harish3e919b52020-10-13 01:21:48 -0500327 // save the lock in the persistent file
328 saveLocks();
329
Ed Tanous3174e4d2020-10-07 11:41:22 -0700330 BMCWEB_LOG_DEBUG << "Done with checking conflict with the locktable";
331 return std::make_pair(false, conflict);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530332}
333
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500334inline void Lock::releaseLock(const ListOfTransactionIds& refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530335{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500336 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530337 {
338 if (lockTable.erase(id))
339 {
340 BMCWEB_LOG_DEBUG << "Removing the locks with transaction ID : "
341 << id;
342 }
343
344 else
345 {
346 BMCWEB_LOG_DEBUG << "Removing the locks from the lock table "
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500347 "failed, transaction ID: "
manojkiraneda3b6dea62019-12-13 17:05:36 +0530348 << id;
349 }
350 }
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600351
352 saveLocks();
manojkiraneda3b6dea62019-12-13 17:05:36 +0530353}
354
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500355inline void Lock::releaseLock(const std::string& sessionId)
Ratan Gupta07386c62019-12-14 14:06:09 +0530356{
357 bool isErased = false;
358 if (!lockTable.empty())
359 {
360 auto it = lockTable.begin();
361 while (it != lockTable.end())
362 {
363 if (it->second.size() != 0)
364 {
365 // Check if session id of this entry matches with session id
366 // given
367 if (std::get<0>(it->second[0]) == sessionId)
368 {
369 BMCWEB_LOG_DEBUG << "Remove the lock from the locktable "
370 "having sessionID="
371 << sessionId;
372 BMCWEB_LOG_DEBUG << "TransactionID =" << it->first;
373 it = lockTable.erase(it);
374 isErased = true;
375 }
376 else
377 {
378 it++;
379 }
380 }
381 }
382 if (isErased)
383 {
384 // save the lock in the persistent file
385 saveLocks();
386 }
387 }
388}
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500389inline RcRelaseLock Lock::isItMyLock(const ListOfTransactionIds& refRids,
390 const SessionFlags& ids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530391{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500392 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530393 {
394 // Just need to compare the client id of the first lock records in the
395 // complete lock row(in the map), because the rest of the lock records
396 // would have the same client id
397
398 std::string expectedClientId = std::get<1>(lockTable[id][0]);
399 std::string expectedSessionId = std::get<0>(lockTable[id][0]);
400
401 if ((expectedClientId == ids.first) &&
402 (expectedSessionId == ids.second))
403 {
404 // It is owned by the currently request hmc
405 BMCWEB_LOG_DEBUG << "Lock is owned by the current hmc";
406 }
407 else
408 {
409 BMCWEB_LOG_DEBUG << "Lock is not owned by the current hmc";
410 return std::make_pair(false, std::make_pair(id, lockTable[id][0]));
411 }
412 }
413 return std::make_pair(true, std::make_pair(0, LockRequest()));
414}
415
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500416inline bool Lock::validateRids(const ListOfTransactionIds& refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530417{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500418 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530419 {
420 auto search = lockTable.find(id);
421
422 if (search != lockTable.end())
423 {
424 BMCWEB_LOG_DEBUG << "Valid Transaction id";
425 // continue for the next rid
426 }
427 else
428 {
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500429 BMCWEB_LOG_DEBUG << "At least 1 inValid Request id";
manojkiraneda3b6dea62019-12-13 17:05:36 +0530430 return false;
431 }
432 }
433 return true;
434}
435
Ed Tanousb5a76932020-09-29 16:16:58 -0700436inline bool Lock::isValidLockRequest(const LockRequest& refLockRecord)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530437{
438
439 // validate the locktype
440
441 if (!((boost::equals(std::get<2>(refLockRecord), "Read") ||
442 (boost::equals(std::get<2>(refLockRecord), "Write")))))
443 {
444 BMCWEB_LOG_DEBUG << "Validation of LockType Failed";
445 BMCWEB_LOG_DEBUG << "Locktype : " << std::get<2>(refLockRecord);
446 return false;
447 }
448
449 BMCWEB_LOG_DEBUG << static_cast<int>(std::get<4>(refLockRecord).size());
450
451 // validate the number of segments
452 // Allowed No of segments are between 2 and 6
453 if ((static_cast<int>(std::get<4>(refLockRecord).size()) > 6) ||
454 (static_cast<int>(std::get<4>(refLockRecord).size()) < 2))
455 {
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500456 BMCWEB_LOG_DEBUG << "Validation of Number of Segments Failed";
manojkiraneda0b631ae2019-12-03 17:54:28 +0530457 BMCWEB_LOG_DEBUG << "Number of Segments provied : "
Ed Tanous7cd94e42020-09-29 16:03:02 -0700458 << std::get<4>(refLockRecord).size();
manojkiraneda0b631ae2019-12-03 17:54:28 +0530459 return false;
460 }
461
462 int lockFlag = 0;
463 // validate the lockflags & segment length
464
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500465 for (const auto& p : std::get<4>(refLockRecord))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530466 {
467
468 // validate the lock flags
469 // Allowed lockflags are locksame,lockall & dontlock
470
471 if (!((boost::equals(p.first, "LockSame") ||
472 (boost::equals(p.first, "LockAll")) ||
473 (boost::equals(p.first, "DontLock")))))
474 {
475 BMCWEB_LOG_DEBUG << "Validation of lock flags failed";
476 BMCWEB_LOG_DEBUG << p.first;
477 return false;
478 }
479
480 // validate the segment length
481 // Allowed values of segment length are between 1 and 4
482
483 if (p.second < 1 || p.second > 4)
484 {
485 BMCWEB_LOG_DEBUG << "Validation of Segment Length Failed";
486 BMCWEB_LOG_DEBUG << p.second;
487 return false;
488 }
489
490 if ((boost::equals(p.first, "LockSame") ||
491 (boost::equals(p.first, "LockAll"))))
492 {
493 ++lockFlag;
494 if (lockFlag >= 2)
495 {
496 return false;
497 }
498 }
499 }
500
manojkiraneda0b631ae2019-12-03 17:54:28 +0530501 return true;
502}
503
Ed Tanousb5a76932020-09-29 16:16:58 -0700504inline Rc Lock::isConflictWithTable(const LockRequests& refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530505{
506
507 uint32_t transactionId;
508
509 if (lockTable.empty())
510 {
511 transactionId = generateTransactionId();
512 BMCWEB_LOG_DEBUG << transactionId;
513 // Lock table is empty, so we are safe to add the lockrecords
514 // as there will be no conflict
515 BMCWEB_LOG_DEBUG << "Lock table is empty, so adding the lockrecords";
516 lockTable.emplace(std::pair<uint32_t, LockRequests>(
517 transactionId, refLockRequestStructure));
518
519 return std::make_pair(false, transactionId);
520 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700521 BMCWEB_LOG_DEBUG
522 << "Lock table is not empty, check for conflict with lock table";
523 // Lock table is not empty, compare the lockrequest entries with
524 // the entries in the lock table
manojkiraneda0b631ae2019-12-03 17:54:28 +0530525
Ed Tanous3174e4d2020-10-07 11:41:22 -0700526 for (const auto& lockRecord1 : refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530527 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700528 for (const auto& map : lockTable)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530529 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700530 for (const auto& lockRecord2 : map.second)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530531 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700532 bool status = isConflictRecord(lockRecord1, lockRecord2);
533 if (status)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530534 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700535 return std::make_pair(
536 true, std::make_pair(map.first, lockRecord2));
manojkiraneda0b631ae2019-12-03 17:54:28 +0530537 }
538 }
539 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530540 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700541
542 // Reached here, so no conflict with the locktable, so we are safe to
543 // add the request records into the lock table
544
545 // Lock table is empty, so we are safe to add the lockrecords
546 // as there will be no conflict
547 BMCWEB_LOG_DEBUG << " Adding elements into lock table";
548 transactionId = generateTransactionId();
549 lockTable.emplace(std::make_pair(transactionId, refLockRequestStructure));
550
manojkiraneda0b631ae2019-12-03 17:54:28 +0530551 return std::make_pair(false, transactionId);
552}
553
Ed Tanousb5a76932020-09-29 16:16:58 -0700554inline bool Lock::isConflictRequest(const LockRequests& refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530555{
556 // check for all the locks coming in as a part of single request
557 // return conflict if any two lock requests are conflicting
558
559 if (refLockRequestStructure.size() == 1)
560 {
561 BMCWEB_LOG_DEBUG << "Only single lock request, so there is no conflict";
562 // This means , we have only one lock request in the current
563 // request , so no conflict within the request
564 return false;
565 }
566
Ed Tanous3174e4d2020-10-07 11:41:22 -0700567 BMCWEB_LOG_DEBUG
568 << "There are multiple lock requests coming in a single request";
569
570 // There are multiple requests a part of one request
571
572 for (uint32_t i = 0; i < refLockRequestStructure.size(); i++)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530573 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700574 for (uint32_t j = i + 1; j < refLockRequestStructure.size(); j++)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530575 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700576 const LockRequest& p = refLockRequestStructure[i];
577 const LockRequest& q = refLockRequestStructure[j];
578 bool status = isConflictRecord(p, q);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530579
Ed Tanous3174e4d2020-10-07 11:41:22 -0700580 if (status)
581 {
582 return true;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530583 }
584 }
585 }
586 return false;
587}
588
589// This function converts the provided uint64_t resource id's from the two
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500590// lock requests subjected for comparison, and this function also compares
manojkiraneda0b631ae2019-12-03 17:54:28 +0530591// the content by bytes mentioned by a uint32_t number.
592
593// If all the elements in the lock requests which are subjected for comparison
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500594// are same, then the last comparison would be to check for the respective
manojkiraneda0b631ae2019-12-03 17:54:28 +0530595// bytes in the resourceid based on the segment length.
596
Ratan Gupta07386c62019-12-14 14:06:09 +0530597inline bool Lock::checkByte(uint64_t resourceId1, uint64_t resourceId2,
598 uint32_t position)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530599{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500600 uint8_t* p = reinterpret_cast<uint8_t*>(&resourceId1);
601 uint8_t* q = reinterpret_cast<uint8_t*>(&resourceId2);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530602
603 BMCWEB_LOG_DEBUG << "Comparing bytes " << std::to_string(p[position]) << ","
604 << std::to_string(q[position]);
605 if (p[position] != q[position])
606 {
607 return false;
608 }
609
manojkiraneda0b631ae2019-12-03 17:54:28 +0530610 return true;
611}
612
Ed Tanousb5a76932020-09-29 16:16:58 -0700613inline bool Lock::isConflictRecord(const LockRequest& refLockRecord1,
614 const LockRequest& refLockRecord2)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530615{
616 // No conflict if both are read locks
617
618 if (boost::equals(std::get<2>(refLockRecord1), "Read") &&
619 boost::equals(std::get<2>(refLockRecord2), "Read"))
620 {
621 BMCWEB_LOG_DEBUG << "Both are read locks, no conflict";
622 return false;
623 }
624
Ed Tanous3174e4d2020-10-07 11:41:22 -0700625 uint32_t i = 0;
626 for (const auto& p : std::get<4>(refLockRecord1))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530627 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700628
629 // return conflict when any of them is try to lock all resources
630 // under the current resource level.
631 if (boost::equals(p.first, "LockAll") ||
632 boost::equals(std::get<4>(refLockRecord2)[i].first, "LockAll"))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530633 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700634 BMCWEB_LOG_DEBUG
635 << "Either of the Comparing locks are trying to lock all "
636 "resources under the current resource level";
637 return true;
638 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530639
Ed Tanous3174e4d2020-10-07 11:41:22 -0700640 // determine if there is a lock-all-with-same-segment-size.
641 // If the current segment sizes are the same,then we should fail.
642
643 if ((boost::equals(p.first, "LockSame") ||
644 boost::equals(std::get<4>(refLockRecord2)[i].first, "LockSame")) &&
645 (p.second == std::get<4>(refLockRecord2)[i].second))
646 {
647 return true;
648 }
649
650 // if segment lengths are not the same, it means two different locks
651 // So no conflict
652 if (p.second != std::get<4>(refLockRecord2)[i].second)
653 {
654 BMCWEB_LOG_DEBUG << "Segment lengths are not same";
655 BMCWEB_LOG_DEBUG << "Segment 1 length : " << p.second;
656 BMCWEB_LOG_DEBUG << "Segment 2 length : "
657 << std::get<4>(refLockRecord2)[i].second;
658 return false;
659 }
660
661 // compare segment data
662
663 for (uint32_t i = 0; i < p.second; i++)
664 {
665 // if the segment data is different , then the locks is on a
666 // different resource So no conflict between the lock
667 // records.
668 // BMC is little endian , but the resourceID is formed by
669 // the Management Console in such a way that, the first byte
670 // from the MSB Position corresponds to the First Segment
671 // data. Therefore we need to convert the in-comming
672 // resourceID into Big Endian before processing further.
673 if (!(checkByte(
674 boost::endian::endian_reverse(std::get<3>(refLockRecord1)),
675 boost::endian::endian_reverse(std::get<3>(refLockRecord2)),
676 i)))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530677 {
manojkiraneda0b631ae2019-12-03 17:54:28 +0530678 return false;
679 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530680 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700681
682 ++i;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530683 }
684
685 return false;
686}
687
Ratan Gupta07386c62019-12-14 14:06:09 +0530688inline uint32_t Lock::generateTransactionId()
manojkiraneda0b631ae2019-12-03 17:54:28 +0530689{
690 ++transactionId;
691 return transactionId;
692}
693
694} // namespace ibm_mc_lock
695} // namespace crow