/* * This file is open source software, licensed to you under the terms * of the Apache License, Version 2.0 (the "License"). See the NOTICE file * distributed with this work for additional information regarding copyright * ownership. You may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include "include/str_map.h" #include "DPDK.h" #include "dpdk_rte.h" namespace dpdk { static inline std::vector string2vector(std::string str) { auto v = std::vector(str.begin(), str.end()); v.push_back('\0'); return v; } static int bitcount(unsigned long long n) { return std::bitset{n}.count(); } static int hex2bitcount(unsigned char c) { int val; if (isdigit(c)) val = c - '0'; else if (isupper(c)) val = c - 'A' + 10; else val = c - 'a' + 10; return bitcount(val); } static int coremask_bitcount(const char *buf) { int count = 0; if (buf[0] == '0' && ((buf[1] == 'x') || (buf[1] == 'X'))) buf += 2; for (int i = 0; buf[i] != '\0'; i++) { char c = buf[i]; if (isxdigit(c) == 0) return -EINVAL; count += hex2bitcount(c); } return count; } bool eal::rte_initialized = false; int eal::start() { if (initialized) { return 1; } bool done = false; auto coremask = cct->_conf.get_val("ms_dpdk_coremask"); int coremaskbit = coremask_bitcount(coremask.c_str()); if (coremaskbit <= 0 || static_cast(coremaskbit) < cct->_conf->ms_async_op_threads) return -EINVAL; t = std::thread([&]() { // TODO: Inherit these from the app parameters - "opts" std::vector> args { string2vector("ceph"), string2vector("-c"), string2vector(cct->_conf.get_val("ms_dpdk_coremask")), string2vector("-n"), string2vector(cct->_conf->ms_dpdk_memory_channel), }; std::optional hugepages_path; if (!cct->_conf->ms_dpdk_hugepages.empty()) { hugepages_path.emplace(cct->_conf->ms_dpdk_hugepages); } // If "hugepages" is not provided and DPDK PMD drivers mode is requested - // use the default DPDK huge tables configuration. if (hugepages_path) { args.push_back(string2vector("--huge-dir")); args.push_back(string2vector(*hugepages_path)); // // We don't know what is going to be our networking configuration so we // assume there is going to be a queue per-CPU. Plus we'll give a DPDK // 64MB for "other stuff". // unsigned int x; std::stringstream ss; ss << std::hex << "fffefffe"; ss >> x; size_t size_MB = mem_size(bitcount(x)) >> 20; std::stringstream size_MB_str; size_MB_str << size_MB; args.push_back(string2vector("-m")); args.push_back(string2vector(size_MB_str.str())); } else if (!cct->_conf->ms_dpdk_pmd.empty()) { args.push_back(string2vector("--no-huge")); } for_each_pair(cct->_conf.get_val("ms_dpdk_devs_allowlist"), " ", [&args] (std::string_view key, std::string_view val) { args.push_back(string2vector(std::string(key))); if (!val.empty()) { args.push_back(string2vector(std::string(val))); } }); std::string rte_file_prefix; rte_file_prefix = "rte_"; rte_file_prefix += cct->_conf->name.to_str(); args.push_back(string2vector("--file-prefix")); args.push_back(string2vector(rte_file_prefix)); std::vector cargs; for (auto&& a: args) { cargs.push_back(a.data()); } if (!rte_initialized) { /* initialise the EAL for all */ int ret = rte_eal_init(cargs.size(), cargs.data()); if (ret < 0) { std::unique_lock locker(lock); done = true; cond.notify_all(); return ret; } rte_initialized = true; } std::unique_lock locker(lock); initialized = true; done = true; cond.notify_all(); while (!stopped) { cond.wait(locker, [this] { return !funcs.empty() || stopped; }); if (!funcs.empty()) { auto f = std::move(funcs.front()); funcs.pop_front(); f(); cond.notify_all(); } } }); std::unique_lock locker(lock); cond.wait(locker, [&] { return done; }); return initialized ? 0 : -EIO; } size_t eal::mem_size(int num_cpus) { size_t memsize = 0; // // PMD mempool memory: // // We don't know what is going to be our networking configuration so we // assume there is going to be a queue per-CPU. // memsize += num_cpus * qp_mempool_obj_size(); // Plus we'll give a DPDK 64MB for "other stuff". memsize += (64UL << 20); return memsize; } void eal::stop() { assert(initialized); assert(!stopped); stopped = true; cond.notify_all(); t.join(); } } // namespace dpdk