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
10 changes: 9 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update && sudo apt-get install -yq \
clang
clang-15
sudo ln -sf /usr/bin/clang-15 /usr/bin/clang
sudo ln -sf /usr/bin/clang++-15 /usr/bin/clang++

- name: Mount bazel cache
uses: actions/cache/restore@v4
Expand All @@ -50,8 +52,14 @@ jobs:
format: X

- name: Build
env:
CC: clang-15
CXX: clang++-15
run: bazel build --test_output=errors //...
- name: Test
env:
CC: clang-15
CXX: clang++-15
run: bazel test --test_output=errors //...

- name: Save end time
Expand Down
28 changes: 28 additions & 0 deletions netkat/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,34 @@ cc_test(
],
)

cc_library(
name = "table_builder",
srcs = ["table_builder.cc"],
hdrs = ["table_builder.h"],
deps = [
":table",
"@com_google_absl//absl/log",
"@com_google_absl//absl/log:check",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@com_google_gutil//gutil:proto",
],
)

cc_test(
name = "table_builder_test",
srcs = ["table_builder_test.cc"],
deps = [
":analysis_engine",
":frontend",
":table",
":table_builder",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:status_matchers",
"@com_google_googletest//:gtest_main",
],
)

cc_test(
name = "netkat_test",
srcs = ["netkat_test.cc"],
Expand Down
29 changes: 19 additions & 10 deletions netkat/manager_handle_pattern.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,28 @@ combining them, or inspecting the underlying sets, one must call methods on the
manager class, which acts as an arena allocator that owns all memory associated
with the handles.

For example: ``` // We need a manager to construct handles. PacketSetManager
manager; PacketSetHandle a = manager.EmptySet() PacketSetHandle b =
manager.Match("src_mac", 0xFF'FF'FF'FF);
For example:

// Handles can be compared and hashed without the help of the manager, // but
that's about it. CHECK(a != b); absl::flat_hash_map<PacketSetHandle> ab_set{a,
b};
```
// We need a manager to construct handles.
PacketSetManager manager;
PacketSetHandle a = manager.EmptySet()
PacketSetHandle b = manager.Match("src_mac", 0xFF'FF'FF'FF);

// Handles can be compared and hashed without the help of the manager,
// but that's about it.
CHECK(a != b);
absl::flat_hash_map<PacketSetHandle> ab_set{a, b};

// To do interesting things with the handles, we need the manager.
PacketSetHandle c = manager.And(a, b); // The set union of `a` and `b`.
PacketSetHandle not_c = manager.Not(c); // The set complement of `c`. if
(manager.Contains(c, packet)) { CHECK(!manager.Contains(not_c, packet)); } else
{ CHECK(manager.Contains(not_c, packet)); } ```
PacketSetHandle c = manager.And(a, b); // The set union of `a` and `b`.
PacketSetHandle not_c = manager.Not(c); // The set complement of `c`.
if (manager.Contains(c, packet)) {
CHECK(!manager.Contains(not_c, packet));
} else {
CHECK(manager.Contains(not_c, packet));
}
```

## Motivation for Using the Pattern

Expand Down
4 changes: 4 additions & 0 deletions netkat/table.cc
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ absl::Status NetkatTable::AddRule(int priority, Predicate match,
return absl::OkStatus();
}

absl::Status NetkatTable::AddRule(Rule rule) {
return AddRule(rule.priority, std::move(rule.match), std::move(rule.action));
}

Policy NetkatTable::GetPolicy() const& {
return GetPolicyInternal(rules_,
accept_default_ ? Policy::Accept() : Policy::Deny());
Expand Down
11 changes: 11 additions & 0 deletions netkat/table.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ class NetkatTable {
const Policy* existing_policy;
};

// A rule to be added to the table.
struct Rule {
// The priority the rule is being added for.
int priority;
// The predicate that the rule will match against.
Predicate match;
// The policy that the rule will apply to any matching packets.
Policy action;
};

// A functor that represents some constraint to be applied or evaluated
// against a pending rule of the table. The constraint must return either an
// error detailing the cause of the violation or OK if there is none.
Expand Down Expand Up @@ -131,6 +141,7 @@ class NetkatTable {
// TODO(anthonyroy): Consider a more API-friendly way to disallow `action`
// from being more restrictive than `match`.
absl::Status AddRule(int priority, Predicate match, Policy action);
absl::Status AddRule(Rule rule);

// Returns a unified policy representing all rules in the NetkatTable. The
// returned policy will emulate a priority based match-action table of a
Expand Down
73 changes: 73 additions & 0 deletions netkat/table_builder.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2026 The NetKAT authors
//
// 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
//
// https://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 "netkat/table_builder.h"

#include <source_location> // NOLINT - absl::SourceLocation not available yet.
#include <string>
#include <utility>

#include "absl/log/check.h"
#include "absl/log/log.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "gutil/proto.h"
#include "netkat/table.h"

namespace netkat {

NetkatTableBuilder::NetkatTableBuilder(NetkatTable& table) : table_(table) {}

NetkatTableBuilder& NetkatTableBuilder::LogRules() {
LOG(INFO) << "Rules in the table builder: \n"
<< absl::StrJoin(
located_rules_, "\n",
[](std::string* out, const LocatedRule& located_rule) {
const NetkatTable::Rule& rule = located_rule.rule;
absl::StrAppend(
out, "priority: ", rule.priority, "\nmatch: ",
gutil::PrintTextProto(rule.match.GetProto()),
"action: ",
gutil::PrintTextProto(rule.action.GetProto()));
});
return *this;
}

NetkatTableBuilder& NetkatTableBuilder::AddRule(NetkatTable::Rule rule,
std::source_location loc) {
located_rules_.push_back({std::move(rule), loc});
return *this;
}

absl::Status NetkatTableBuilder::InstallRules() {
NetkatTable temp_table(table_);
for (LocatedRule& located_rule : located_rules_) {
std::source_location location = located_rule.location;
absl::Status status = temp_table.AddRule(std::move(located_rule.rule));
if (!status.ok()) {
// Clear all the located rules in the table builder to avoid installing an
// invalid table entry accidentally in a later call to `InstallRules`.
located_rules_.clear();
return absl::Status(
status.code(),
absl::StrCat(location.file_name(), ":", location.line(),
": Failed to install table rule: ", status.message()));
}
}
table_ = std::move(temp_table);
return absl::OkStatus();
}

} // namespace netkat
69 changes: 69 additions & 0 deletions netkat/table_builder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2026 The NetKAT authors
//
// 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
//
// https://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 GOOGLE_NETKAT_NETKAT_TABLE_BUILDER_H_
#define GOOGLE_NETKAT_NETKAT_TABLE_BUILDER_H_

#include <source_location> // NOLINT - absl::SourceLocation not available yet.
#include <vector>

#include "absl/status/status.h"
#include "netkat/table.h"

namespace netkat {

// A builder class for modifying an existing NetkatTable using a fluent
// interface. Modifications are applied atomically: if any rule fails to be
// installed (e.g., due to a constraint violation), the underlying table remains
// completely unmodified.
class NetkatTableBuilder {
public:
// Creates a NetkatTableBuilder that modifies the given `table`. Note that
// NetkatTable must outlive the NetkatTableBuilder.
explicit NetkatTableBuilder(NetkatTable& table);

// Logs the current rules in the NetkatTableBuilder to LOG(INFO).
NetkatTableBuilder& LogRules();

// Adds a rule to be inserted into the table at the given priority.
NetkatTableBuilder& AddRule(
NetkatTable::Rule rule,
std::source_location loc = std::source_location::current());

// Moves all buffered rules into the table atomically. Returns an error
// with the source location of the caller if any rule cannot be successfully
// added. If any rule fails to be installed (e.g., due to a constraint
// violation), the underlying table remains completely unmodified,
// NetkatTableBuilder dumps all the rules that were added to it, and an error
// is returned.
absl::Status InstallRules();

private:
friend class NetkatTable;

// A rule with its source location, for error reporting.
struct LocatedRule {
// A rule to be installed in the table.
NetkatTable::Rule rule;
// The source location of the rule, for error reporting.
std::source_location location;
};

std::vector<LocatedRule> located_rules_;
NetkatTable& table_;
};

} // namespace netkat

#endif // GOOGLE_NETKAT_NETKAT_TABLE_BUILDER_H_
Loading
Loading