Skip to content

Commit 317aa96

Browse files
Justin Kimfacebook-github-bot
Justin Kim
authored andcommitted
Better kmod extraction from lsmod
Summary: Parse the lsmod content to list of kmods. So we can full string comparison instead of sub-string that can be faulty some times. E.g kmod_x matches to kmod_x_y_z. Only dealing with kmod names. Reviewed By: somasun Differential Revision: D68463973 fbshipit-source-id: 36ab35ffecbc0b9035bdc5c61407a2da4b111812
1 parent 01bba30 commit 317aa96

File tree

6 files changed

+107
-22
lines changed

6 files changed

+107
-22
lines changed

fboss/platform/platform_manager/BUCK

+1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ cpp_library(
129129
"PkgManager.cpp",
130130
],
131131
exported_deps = [
132+
"fbsource//third-party/range-v3:range-v3",
132133
":platform_manager_config-cpp2-types",
133134
"//fb303:service_data",
134135
"//fboss/platform/helpers:platform_fs_utils",

fboss/platform/platform_manager/PkgManager.cpp

+34-15
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
#include <folly/FileUtil.h>
77
#include <folly/String.h>
88
#include <folly/logging/xlog.h>
9+
#include <range/v3/range/conversion.hpp>
10+
#include <range/v3/view/drop.hpp>
11+
#include <range/v3/view/filter.hpp>
12+
#include <range/v3/view/split.hpp>
913
#include <re2/re2.h>
1014
#include <sys/utsname.h>
1115
#include <thrift/lib/cpp2/protocol/Serializer.h>
1216

13-
#include "fboss/platform/helpers/PlatformUtils.h"
14-
1517
DEFINE_bool(
1618
enable_pkg_mgmnt,
1719
true,
@@ -37,14 +39,16 @@ const re2::RE2 kBspRpmNameRe = "(?P<KEYWORD>[a-z]+)_bsp_kmods";
3739
} // namespace
3840

3941
namespace package_manager {
40-
SystemInterface::SystemInterface() {}
42+
SystemInterface::SystemInterface(
43+
const std::shared_ptr<PlatformUtils>& platformUtils)
44+
: platformUtils_(platformUtils) {}
4145

4246
bool SystemInterface::loadKmod(const std::string& moduleName) const {
4347
int exitStatus{0};
4448
std::string standardOut{};
4549
auto unloadCmd = fmt::format("modprobe {}", moduleName);
4650
VLOG(1) << fmt::format("Running command ({})", unloadCmd);
47-
std::tie(exitStatus, standardOut) = PlatformUtils().execCommand(unloadCmd);
51+
std::tie(exitStatus, standardOut) = platformUtils_->execCommand(unloadCmd);
4852
return exitStatus == 0;
4953
}
5054

@@ -53,7 +57,7 @@ bool SystemInterface::unloadKmod(const std::string& moduleName) const {
5357
std::string standardOut{};
5458
auto unloadCmd = fmt::format("rmmod {}", moduleName);
5559
VLOG(1) << fmt::format("Running command ({})", unloadCmd);
56-
std::tie(exitStatus, standardOut) = PlatformUtils().execCommand(unloadCmd);
60+
std::tie(exitStatus, standardOut) = platformUtils_->execCommand(unloadCmd);
5761
return exitStatus == 0;
5862
}
5963

@@ -62,7 +66,7 @@ int SystemInterface::installRpm(const std::string& rpmFullName) const {
6266
std::string standardOut{};
6367
auto cmd = fmt::format("dnf install {} --assumeyes", rpmFullName);
6468
VLOG(1) << fmt::format("Running command ({})", cmd);
65-
std::tie(exitStatus, standardOut) = PlatformUtils().execCommand(cmd);
69+
std::tie(exitStatus, standardOut) = platformUtils_->execCommand(cmd);
6670
return exitStatus;
6771
}
6872

@@ -71,7 +75,7 @@ int SystemInterface::installLocalRpm() const {
7175
std::string standardOut{};
7276
auto cmd = fmt::format("rpm -i --force {}", FLAGS_local_rpm_path);
7377
VLOG(1) << fmt::format("Running command ({})", cmd);
74-
std::tie(exitStatus, standardOut) = PlatformUtils().execCommand(cmd);
78+
std::tie(exitStatus, standardOut) = platformUtils_->execCommand(cmd);
7579
return exitStatus;
7680
}
7781

@@ -80,7 +84,7 @@ int SystemInterface::depmod() const {
8084
std::string standardOut{};
8185
auto depmodCmd = "depmod -a";
8286
VLOG(1) << fmt::format("Running command ({})", depmodCmd);
83-
std::tie(exitStatus, standardOut) = PlatformUtils().execCommand(depmodCmd);
87+
std::tie(exitStatus, standardOut) = platformUtils_->execCommand(depmodCmd);
8488
return exitStatus;
8589
}
8690

@@ -90,7 +94,7 @@ std::vector<std::string> SystemInterface::getInstalledRpms(
9094
int exitStatus{0};
9195
auto cmd = fmt::format("rpm -qa | grep ^{}", rpmBaseName);
9296
VLOG(1) << fmt::format("Running command ({})", cmd);
93-
std::tie(exitStatus, standardOut) = PlatformUtils().execCommand(cmd);
97+
std::tie(exitStatus, standardOut) = platformUtils_->execCommand(cmd);
9498
if (exitStatus) {
9599
return {};
96100
}
@@ -107,14 +111,29 @@ int SystemInterface::removeRpms(
107111
fmt::format("rpm -e --allmatches {}", folly::join(" ", installedRpms));
108112
VLOG(1) << fmt::format("Running command ({})", removeOldRpmsCmd);
109113
std::tie(exitStatus, standardOut) =
110-
PlatformUtils().execCommand(removeOldRpmsCmd);
114+
platformUtils_->execCommand(removeOldRpmsCmd);
111115
return exitStatus;
112116
}
113117

114-
std::string SystemInterface::lsmod() const {
118+
std::set<std::string> SystemInterface::lsmod() const {
115119
VLOG(1) << "Running command (lsmod)";
116-
auto result = PlatformUtils().execCommand("lsmod");
117-
return result.second;
120+
auto result = platformUtils_->execCommand("lsmod");
121+
auto rows = result.second | ranges::views::split('\n') |
122+
ranges::views::drop(1) | ranges::to<std::vector<std::string>>;
123+
std::set<std::string> kmods;
124+
// row -> kmod | size | used by | dependent kmods
125+
for (const auto& row : rows) {
126+
auto tokens = row | ranges::views::split(' ') |
127+
ranges::views::filter(
128+
[](const auto& token) { return !token.empty(); }) |
129+
ranges::to<std::vector<std::string>>;
130+
if (tokens.empty()) {
131+
XLOG(WARNING) << fmt::format("Failed to scan lsmod row -- {}", row);
132+
continue;
133+
}
134+
kmods.emplace(tokens.front());
135+
}
136+
return kmods;
118137
}
119138

120139
std::string SystemInterface::getHostKernelVersion() const {
@@ -299,7 +318,7 @@ void PkgManager::unloadBspKmods() const {
299318
XLOG(INFO) << "Unloading kernel modules based on kmods.json";
300319
const auto loadedKmods = systemInterface_->lsmod();
301320
for (const auto& kmod : *bspKmodsFile.bspKmods()) {
302-
if (loadedKmods.find(kmod) != std::string::npos) {
321+
if (loadedKmods.contains(kmod)) {
303322
XLOG(INFO) << fmt::format("Unloading {}", kmod);
304323
if (!systemInterface_->unloadKmod(kmod)) {
305324
throw std::runtime_error(fmt::format("Failed to unload ({})", kmod));
@@ -311,7 +330,7 @@ void PkgManager::unloadBspKmods() const {
311330
}
312331
XLOG(INFO) << "Unloading shared kernel modules";
313332
for (const auto& kmod : *bspKmodsFile.sharedKmods()) {
314-
if (loadedKmods.find(kmod) != std::string::npos) {
333+
if (loadedKmods.contains(kmod)) {
315334
XLOG(INFO) << fmt::format("Unloading {}", kmod);
316335
if (!systemInterface_->unloadKmod(kmod)) {
317336
throw std::runtime_error(fmt::format("Failed to unload ({})", kmod));

fboss/platform/platform_manager/PkgManager.h

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#pragma once
44

55
#include "fboss/platform/helpers/PlatformFsUtils.h"
6+
#include "fboss/platform/helpers/PlatformUtils.h"
67
#include "fboss/platform/platform_manager/gen-cpp2/platform_manager_config_types.h"
78

89
DECLARE_bool(enable_pkg_mgmnt);
@@ -13,7 +14,9 @@ namespace facebook::fboss::platform::platform_manager {
1314
namespace package_manager {
1415
class SystemInterface {
1516
public:
16-
explicit SystemInterface();
17+
explicit SystemInterface(
18+
const std::shared_ptr<PlatformUtils>& platformUtils =
19+
std::make_shared<PlatformUtils>());
1720
virtual ~SystemInterface() = default;
1821
virtual bool loadKmod(const std::string& moduleName) const;
1922
virtual bool unloadKmod(const std::string& moduleName) const;
@@ -22,10 +25,13 @@ class SystemInterface {
2225
virtual std::vector<std::string> getInstalledRpms(
2326
const std::string& rpmBaseName) const;
2427
virtual int removeRpms(const std::vector<std::string>& installedRpms) const;
25-
virtual std::string lsmod() const;
28+
virtual std::set<std::string> lsmod() const;
2629
virtual bool isRpmInstalled(const std::string& rpmFullName) const;
2730
virtual std::string getHostKernelVersion() const;
2831
int installLocalRpm() const;
32+
33+
private:
34+
std::shared_ptr<PlatformUtils> platformUtils_;
2935
};
3036
} // namespace package_manager
3137

fboss/platform/platform_manager/tests/BUCK

+3
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,12 @@ cpp_unittest(
9999
name = "pkg_manager_test",
100100
srcs = [
101101
"PkgManagerTest.cpp",
102+
"SystemInterfaceTest.cpp",
102103
],
103104
deps = [
105+
"fbsource//third-party/fmt:fmt",
104106
"fbsource//third-party/googletest:gmock",
107+
"fbsource//third-party/range-v3:range-v3",
105108
"//fb303:service_data",
106109
"//fboss/platform/platform_manager:pkg_manager",
107110
"//thrift/lib/cpp2/protocol:protocol",

fboss/platform/platform_manager/tests/PkgManagerTest.cpp

+13-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include <fb303/ServiceData.h>
44
#include <gmock/gmock.h>
55
#include <gtest/gtest.h>
6+
#include <range/v3/range/conversion.hpp>
7+
#include <range/v3/view/concat.hpp>
68
#include <thrift/lib/cpp2/protocol/Serializer.h>
79

810
#include "fboss/platform/platform_manager/PkgManager.h"
@@ -21,7 +23,7 @@ class MockSystemInterface : public package_manager::SystemInterface {
2123
MOCK_METHOD(int, removeRpms, (const std::vector<std::string>&), (const));
2224
MOCK_METHOD(int, installRpm, (const std::string&), (const));
2325
MOCK_METHOD(int, depmod, (), (const));
24-
MOCK_METHOD(std::string, lsmod, (), (const));
26+
MOCK_METHOD(std::set<std::string>, lsmod, (), (const));
2527
MOCK_METHOD(bool, unloadKmod, (const std::string&), (const));
2628
MOCK_METHOD(bool, loadKmod, (const std::string&), (const));
2729
MOCK_METHOD(std::string, getHostKernelVersion, (), (const));
@@ -303,8 +305,10 @@ TEST_F(PkgManagerTest, unloadBspKmods) {
303305
EXPECT_CALL(*mockPlatformFsUtils_, getStringFileContent(_))
304306
.WillOnce(Return(jsonBspKmodsFile_));
305307
EXPECT_CALL(*mockSystemInterface_, lsmod())
306-
.WillOnce(
307-
Return(jsonBspKmodsFile_ /*any string containing kmods works*/));
308+
.WillOnce(Return(
309+
ranges::views::concat(
310+
*bspKmodsFile_.bspKmods(), *bspKmodsFile_.sharedKmods()) |
311+
ranges::to<std::set<std::string>>));
308312
EXPECT_CALL(*mockSystemInterface_, unloadKmod(_))
309313
.Times(
310314
bspKmodsFile_.sharedKmods()->size() +
@@ -317,15 +321,19 @@ TEST_F(PkgManagerTest, unloadBspKmods) {
317321
EXPECT_CALL(*mockPlatformFsUtils_, getStringFileContent(_))
318322
.WillOnce(Return(jsonBspKmodsFile_));
319323
EXPECT_CALL(*mockSystemInterface_, lsmod())
320-
.WillOnce(Return(jsonBspKmodsFile_));
324+
.WillOnce(Return(
325+
ranges::views::concat(
326+
*bspKmodsFile_.bspKmods(), *bspKmodsFile_.sharedKmods()) |
327+
ranges::to<std::set<std::string>>));
321328
EXPECT_CALL(*mockSystemInterface_, unloadKmod(_)).WillOnce(Return(false));
322329
EXPECT_THROW(pkgManager_.unloadBspKmods(), std::runtime_error);
323330
EXPECT_EQ(
324331
facebook::fb303::fbData->getCounter(PkgManager::kUnloadKmodsFailure), 1);
325332
// kmods.json exist and all kmods aren't loaded
326333
EXPECT_CALL(*mockPlatformFsUtils_, getStringFileContent(_))
327334
.WillOnce(Return(jsonBspKmodsFile_));
328-
EXPECT_CALL(*mockSystemInterface_, lsmod()).WillOnce(Return(""));
335+
EXPECT_CALL(*mockSystemInterface_, lsmod())
336+
.WillOnce(Return(std::set<std::string>{}));
329337
EXPECT_CALL(*mockSystemInterface_, unloadKmod(_)).Times(0);
330338
EXPECT_NO_THROW(pkgManager_.unloadBspKmods());
331339
EXPECT_EQ(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
2+
3+
#include <fmt/args.h>
4+
#include <gmock/gmock.h>
5+
#include <gtest/gtest.h>
6+
7+
#include "fboss/platform/platform_manager/PkgManager.h"
8+
9+
using namespace ::testing;
10+
11+
namespace facebook::fboss::platform::platform_manager {
12+
class MockPlatformUtils : public PlatformUtils {
13+
public:
14+
MOCK_METHOD(
15+
(std::pair<int, std::string>),
16+
execCommand,
17+
(const std::string&),
18+
(const));
19+
};
20+
21+
TEST(SystemInterfaceTest, lsmod) {
22+
auto lsmod =
23+
"Module Size Used by\n"
24+
"mp3_smbcpld 12288 0\n"
25+
"mp3_scmcpld 28672 0\n"
26+
"fboss_iob_xcvr 12288 0\n"
27+
"fboss_iob_led 12288 0\n"
28+
"led_class 20480 3 fboss_iob_led,mp3_scmcpld,mp3_fancpld\n"
29+
"autofs4 49152 2\n";
30+
auto expectedKmods = std::array<std::string, 6>{
31+
"mp3_smbcpld",
32+
"mp3_scmcpld",
33+
"fboss_iob_xcvr",
34+
"fboss_iob_led",
35+
"led_class",
36+
"autofs4"};
37+
auto platformUtils = std::make_shared<MockPlatformUtils>();
38+
EXPECT_CALL(*platformUtils, execCommand(_))
39+
.WillOnce(Return(std::pair{0, lsmod}));
40+
package_manager::SystemInterface interface(platformUtils);
41+
auto kmods = interface.lsmod();
42+
EXPECT_EQ(kmods.size(), expectedKmods.size());
43+
for (const auto& expectedKmod : expectedKmods) {
44+
EXPECT_TRUE(kmods.contains(expectedKmod));
45+
}
46+
}
47+
48+
}; // namespace facebook::fboss::platform::platform_manager

0 commit comments

Comments
 (0)