Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion base/cvd/allocd/net/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
load("//cuttlefish/bazel:rules.bzl", "cf_cc_library")
load("//cuttlefish/bazel:rules.bzl", "cf_cc_library", "cf_cc_test")

package(
default_visibility = ["//:android_cuttlefish"],
Expand All @@ -19,3 +19,42 @@ cf_cc_library(
"@abseil-cpp//absl/log",
],
)

cf_cc_library(
Comment thread
dxapd marked this conversation as resolved.
name = "nftables",
srcs = [
"nft_rule.cc",
"nftables_nft.cc",
],
hdrs = [
"nft_rule.h",
"nftables.h",
"nftables_nft.h",
],
target_compatible_with = [
"@platforms//os:linux",
],
deps = [
"//cuttlefish/common/libs/utils:files",
"//cuttlefish/common/libs/utils:json",
"//cuttlefish/process:command",
"//cuttlefish/process:managed_stdio",
"//cuttlefish/process:subprocess",
"//cuttlefish/result",
"@abseil-cpp//absl/base:no_destructor",
"@abseil-cpp//absl/log",
"@abseil-cpp//absl/strings",
"@jsoncpp",
],
)

cf_cc_test(
name = "nft_rule_test",
srcs = ["nft_rule_test.cc"],
deps = [
":nftables",
"//allocd/test:fake_nftables",
"//cuttlefish/result",
"//cuttlefish/result:result_matchers",
],
)
72 changes: 72 additions & 0 deletions base/cvd/allocd/net/nft_rule.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright (C) 2026 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* 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 "allocd/net/nft_rule.h"

#include <string>
#include <string_view>
#include <utility>

#include "absl/log/log.h"
#include "absl/strings/str_cat.h"

#include "allocd/net/nftables.h"
#include "cuttlefish/result/result.h"

namespace cuttlefish {
namespace {

// Namespace prefix applied to every dynamic cvdalloc rule comment.
constexpr std::string_view kCvdallocCommentPrefix = "cvdalloc-";

} // namespace

Result<NftRule> NftRule::Create(Nftables& nft, std::string_view family,
std::string_view table, std::string_view chain,
std::string_view content,
std::string_view tag) {
std::string comment = absl::StrCat(kCvdallocCommentPrefix, tag);
CF_EXPECT(nft.AddRule(family, table, chain, content, comment));
return NftRule(&nft, family, table, chain, std::move(comment));
}

NftRule::NftRule(Nftables* nft, std::string_view family, std::string_view table,
std::string_view chain, std::string comment)
: nft_(nft),
family_(family),
table_(table),
chain_(chain),
comment_(std::move(comment)) {}

NftRule::NftRule(NftRule&& r) noexcept
: nft_(std::exchange(r.nft_, nullptr)),
family_(std::move(r.family_)),
table_(std::move(r.table_)),
chain_(std::move(r.chain_)),
comment_(std::move(r.comment_)) {}

NftRule::~NftRule() {
// nft_ is nulled on move, so a moved-from rule is inert and never deletes.
if (nft_ != nullptr) {
auto res = nft_->DeleteRulesByComment(family_, table_, chain_, comment_);
if (!res.has_value()) {
LOG(ERROR) << "Failed to delete nft rule(s) in NftRule destructor: "
<< res.error();
}
}
}

} // namespace cuttlefish
55 changes: 55 additions & 0 deletions base/cvd/allocd/net/nft_rule.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2026 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* 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.
*/

#ifndef ALLOCD_NET_NFT_RULE_H_
#define ALLOCD_NET_NFT_RULE_H_

#include <string>
#include <string_view>

#include "allocd/net/nftables.h"
#include "cuttlefish/result/result.h"

namespace cuttlefish {

class NftRule {
public:
// `tag` is a caller-supplied unique identifier (e.g. an interface name).
static Result<NftRule> Create(Nftables& nft, std::string_view family,
std::string_view table, std::string_view chain,
std::string_view content, std::string_view tag);

~NftRule();

NftRule(NftRule&& r) noexcept;
NftRule& operator=(NftRule&& r) = delete;
NftRule(const NftRule& r) = delete;
NftRule& operator=(const NftRule& r) = delete;

private:
NftRule(Nftables* nft, std::string_view family, std::string_view table,
std::string_view chain, std::string comment);

Nftables* nft_ = nullptr;
std::string family_;
std::string table_;
std::string chain_;
std::string comment_;
};

} // namespace cuttlefish

#endif // ALLOCD_NET_NFT_RULE_H_
78 changes: 78 additions & 0 deletions base/cvd/allocd/net/nft_rule_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright (C) 2026 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* 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 "allocd/net/nft_rule.h"

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <utility>

#include "allocd/test/fake_nftables.h"
#include "cuttlefish/result/result.h"
#include "cuttlefish/result/result_matchers.h"

namespace cuttlefish {
namespace {

class NftRuleTest : public ::testing::Test {
protected:
void SetUp() override {
ASSERT_THAT(fake_.EnsureTable("ip", "table1"), IsOk());
ASSERT_THAT(fake_.EnsureChain("ip", "table1", "chain1", ""), IsOk());
}

FakeNftables fake_;
};

TEST_F(NftRuleTest, CreateAddsRuleWithPrefixedComment) {
Result<NftRule> rule =
NftRule::Create(fake_, "ip", "table1", "chain1", "content1", "tag1");
ASSERT_THAT(rule, IsOk());
EXPECT_TRUE(
fake_.HasRuleWithComment("ip", "table1", "chain1", "cvdalloc-tag1"));
}

TEST_F(NftRuleTest, DeletesRuleOnDestruction) {
{
Result<NftRule> rule =
NftRule::Create(fake_, "ip", "table1", "chain1", "content1", "tag1");
ASSERT_THAT(rule, IsOk());
EXPECT_TRUE(
fake_.HasRuleWithComment("ip", "table1", "chain1", "cvdalloc-tag1"));
}
EXPECT_FALSE(
fake_.HasRuleWithComment("ip", "table1", "chain1", "cvdalloc-tag1"));
EXPECT_EQ(fake_.RuleCount("ip", "table1", "chain1"), 0);
}

TEST_F(NftRuleTest, MoveConstructorTransfersOwnership) {
{
Result<NftRule> rule1 =
NftRule::Create(fake_, "ip", "table1", "chain1", "content1", "tag1");
ASSERT_THAT(rule1, IsOk());

NftRule rule2(std::move(*rule1));
EXPECT_TRUE(
fake_.HasRuleWithComment("ip", "table1", "chain1", "cvdalloc-tag1"));
}
EXPECT_FALSE(
fake_.HasRuleWithComment("ip", "table1", "chain1", "cvdalloc-tag1"));
EXPECT_EQ(fake_.RuleCount("ip", "table1", "chain1"), 0);
}

} // namespace
} // namespace cuttlefish
56 changes: 56 additions & 0 deletions base/cvd/allocd/net/nftables.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (C) 2026 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* 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.
*/

#ifndef ALLOCD_NET_NFTABLES_H_
#define ALLOCD_NET_NFTABLES_H_

#include <stdint.h>

#include <string_view>

#include "cuttlefish/result/result.h"

namespace cuttlefish {

class Nftables {
public:
virtual ~Nftables() = default;

virtual Result<void> EnsureTable(std::string_view family,
std::string_view table) = 0;
virtual Result<void> DeleteTable(std::string_view family,
std::string_view table) = 0;
virtual Result<void> EnsureChain(std::string_view family,
std::string_view table,
std::string_view chain,
std::string_view content) = 0;
virtual Result<uint64_t> AddRule(std::string_view family,
std::string_view table,
std::string_view chain,
std::string_view content,
std::string_view comment) = 0;
virtual Result<void> DeleteRule(std::string_view family,
std::string_view table,
std::string_view chain, uint64_t handle) = 0;
virtual Result<void> DeleteRulesByComment(std::string_view family,
std::string_view table,
std::string_view chain,
std::string_view comment) = 0;
};

} // namespace cuttlefish

#endif // ALLOCD_NET_NFTABLES_H_
Loading
Loading