[PATCH bpf-next v3 15/16] bpfilter: add filter table

From: Quentin Deslandes
Date: Fri Dec 23 2022 - 19:06:32 EST


Introduce filter table support for INPUT, FORWARD, and OUTPUT chains.
All those chains are supported by SCHED_CLS_BPF.

INPUT and FORWARD programs are attached to TC_INGRESS hook and leverage
generate_inline_forward_packet_assessment() to check whether they should
or not process the incoming packet.

OUTPUT program is attached to TC_EGRESS hook.

create_filter_table() is used to create a default filter table
(statically stored in filter_table_replace_blob). This table doesn't
contain any rule and defaults to ACCEPTing packets on each chain.

Co-developed-by: Dmitrii Banshchikov <me@xxxxxxxxxxxxx>
Signed-off-by: Dmitrii Banshchikov <me@xxxxxxxxxxxxx>
Signed-off-by: Quentin Deslandes <qde@xxxxxxxx>
---
net/bpfilter/Makefile | 1 +
net/bpfilter/context.c | 3 +-
net/bpfilter/filter-table.c | 344 ++++++++++++++++++
net/bpfilter/filter-table.h | 18 +
.../testing/selftests/bpf/bpfilter/.gitignore | 1 +
tools/testing/selftests/bpf/bpfilter/Makefile | 3 +
.../selftests/bpf/bpfilter/bpfilter_util.h | 27 ++
.../selftests/bpf/bpfilter/test_codegen.c | 338 +++++++++++++++++
8 files changed, 734 insertions(+), 1 deletion(-)
create mode 100644 net/bpfilter/filter-table.c
create mode 100644 net/bpfilter/filter-table.h
create mode 100644 tools/testing/selftests/bpf/bpfilter/test_codegen.c

diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile
index 4a78a665b3f1..7def305f0af3 100644
--- a/net/bpfilter/Makefile
+++ b/net/bpfilter/Makefile
@@ -15,6 +15,7 @@ bpfilter_umh-objs := main.o logger.o map-common.o
bpfilter_umh-objs += context.o codegen.o
bpfilter_umh-objs += match.o xt_udp.o target.o rule.o table.o
bpfilter_umh-objs += sockopt.o
+bpfilter_umh-objs += filter-table.o
bpfilter_umh-userldlibs := $(LIBBPF_A) -lelf -lz
userccflags += -I $(srctree)/tools/include/ -I $(srctree)/tools/include/uapi

diff --git a/net/bpfilter/context.c b/net/bpfilter/context.c
index 81c9751a2a2d..6bb0362a79c8 100644
--- a/net/bpfilter/context.c
+++ b/net/bpfilter/context.c
@@ -13,6 +13,7 @@

#include <string.h>

+#include "filter-table.h"
#include "logger.h"
#include "map-common.h"
#include "match.h"
@@ -73,7 +74,7 @@ static int init_target_ops_map(struct context *ctx)
return 0;
}

-static const struct table_ops *table_ops[] = {};
+static const struct table_ops *table_ops[] = { &filter_table_ops };

static int init_table_ops_map(struct context *ctx)
{
diff --git a/net/bpfilter/filter-table.c b/net/bpfilter/filter-table.c
new file mode 100644
index 000000000000..452a6d5b2fd0
--- /dev/null
+++ b/net/bpfilter/filter-table.c
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 Telegram FZ-LLC
+ * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
+ */
+
+#define _GNU_SOURCE
+
+#include "filter-table.h"
+
+#include "../../include/uapi/linux/bpfilter.h"
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <bpf/bpf.h>
+
+#include "codegen.h"
+#include "context.h"
+#include "logger.h"
+#include "msgfmt.h"
+#include "rule.h"
+#include "sockopt.h"
+
+struct filter_table_context {
+ struct shared_codegen shared;
+ struct codegen local_in;
+ struct codegen forward;
+ struct codegen local_out;
+};
+
+static struct table *filter_table_create(struct context *ctx,
+ const struct bpfilter_ipt_replace *ipt_replace)
+{
+ struct table *t = create_table(ctx, ipt_replace);
+
+ if (!IS_ERR_OR_NULL(t))
+ t->table_ops = &filter_table_ops;
+
+ return t;
+}
+
+static int filter_table_codegen(struct context *ctx, struct table *table)
+{
+ struct filter_table_context *table_ctx;
+ int r;
+
+ BUG_ON(table->table_ops != &filter_table_ops);
+
+ if (table->ctx) {
+ BFLOG_ERR("filter table has no context");
+ return -EINVAL;
+ }
+
+ table_ctx = calloc(1, sizeof(*table_ctx));
+ if (!table_ctx) {
+ BFLOG_ERR("out of memory");
+ return -ENOMEM;
+ }
+
+ create_shared_codegen(&table_ctx->shared);
+
+ // INPUT chain
+ r = create_codegen(&table_ctx->local_in, BPF_PROG_TYPE_SCHED_CLS);
+ if (r) {
+ BFLOG_ERR("TC codegen for INPUT chain creation failed");
+ goto err_free_table_ctx;
+ }
+
+ table_ctx->local_in.ctx = ctx;
+ table_ctx->local_in.shared_codegen = &table_ctx->shared;
+ table_ctx->local_in.iptables_hook = BPFILTER_INET_HOOK_LOCAL_IN;
+ table_ctx->local_in.bpf_tc_hook = BPF_TC_INGRESS;
+
+ r = try_codegen(&table_ctx->local_in, table);
+ if (r) {
+ BFLOG_ERR("failed to generate LOCAL_IN code");
+ goto err_free_local_in;
+ }
+
+ // FORWARD chain
+ r = create_codegen(&table_ctx->forward, BPF_PROG_TYPE_SCHED_CLS);
+ if (r) {
+ BFLOG_ERR("TC codegen for FORWARD chain create failed");
+ goto err_free_local_in;
+ }
+
+ table_ctx->forward.ctx = ctx;
+ table_ctx->forward.shared_codegen = &table_ctx->shared;
+ table_ctx->forward.iptables_hook = BPFILTER_INET_HOOK_FORWARD;
+ table_ctx->forward.bpf_tc_hook = BPF_TC_INGRESS;
+
+ r = try_codegen(&table_ctx->forward, table);
+ if (r) {
+ BFLOG_ERR("failed to generate LOCAL_FORWARD code");
+ goto err_free_local_fwd;
+ }
+
+ // OUTPUT chain
+ r = create_codegen(&table_ctx->local_out, BPF_PROG_TYPE_SCHED_CLS);
+ if (r) {
+ BFLOG_ERR("TC codegen for OUTPUT chain creation failed");
+ goto err_free_local_fwd;
+ }
+
+ table_ctx->local_out.ctx = ctx;
+ table_ctx->local_out.shared_codegen = &table_ctx->shared;
+ table_ctx->local_out.iptables_hook = BPFILTER_INET_HOOK_LOCAL_OUT;
+ table_ctx->local_out.bpf_tc_hook = BPF_TC_EGRESS;
+
+ r = try_codegen(&table_ctx->local_out, table);
+ if (r) {
+ BFLOG_ERR("failed to generate LOCAL_OUT code");
+ goto err_free_local_out;
+ }
+
+ table->ctx = table_ctx;
+
+ return 0;
+
+err_free_local_out:
+ free_codegen(&table_ctx->local_out);
+err_free_local_fwd:
+ free_codegen(&table_ctx->forward);
+err_free_local_in:
+ free_codegen(&table_ctx->local_in);
+err_free_table_ctx:
+ free(table_ctx);
+
+ return r;
+}
+
+static int filter_table_install(struct context *ctx, struct table *table)
+{
+ struct filter_table_context *table_ctx;
+ int r;
+
+ if (!table->ctx)
+ return -EINVAL;
+
+ table_ctx = (struct filter_table_context *)table->ctx;
+
+ r = table_ctx->local_in.codegen_ops->load_img(&table_ctx->local_in);
+ if (r < 0) {
+ BFLOG_ERR("failed to load chain INPUT in table filter: %s",
+ table_ctx->local_in.log_buf);
+ return r;
+ }
+
+ r = table_ctx->forward.codegen_ops->load_img(&table_ctx->forward);
+ if (r < 0) {
+ BFLOG_ERR("failed to load chain FORWARD in table filter: %s",
+ table_ctx->forward.log_buf);
+ goto err_unload_local_in;
+ }
+
+ r = table_ctx->local_out.codegen_ops->load_img(&table_ctx->local_out);
+ if (r < 0) {
+ BFLOG_ERR("failed to load chain OUTPUT in table filter: %s",
+ table_ctx->local_out.log_buf);
+ goto err_unload_forward;
+ }
+
+ BFLOG_DBG("installed filter table");
+
+ return 0;
+
+err_unload_forward:
+ table_ctx->forward.codegen_ops->unload_img(&table_ctx->forward);
+err_unload_local_in:
+ table_ctx->local_in.codegen_ops->unload_img(&table_ctx->local_in);
+
+ return r;
+}
+
+static void filter_table_uninstall(struct context *ctx, struct table *table)
+{
+ struct filter_table_context *table_ctx;
+
+ BUG_ON(!table->ctx);
+
+ table_ctx = (struct filter_table_context *)table->ctx;
+
+ table_ctx->local_in.codegen_ops->unload_img(&table_ctx->local_in);
+ table_ctx->forward.codegen_ops->unload_img(&table_ctx->forward);
+ table_ctx->local_out.codegen_ops->unload_img(&table_ctx->local_out);
+}
+
+static void filter_table_free(struct table *table)
+{
+ if (table->ctx) {
+ struct filter_table_context *table_ctx;
+
+ table_ctx = (struct filter_table_context *)table->ctx;
+
+ free_codegen(&table_ctx->local_in);
+ free_codegen(&table_ctx->forward);
+ free_codegen(&table_ctx->local_out);
+ free(table_ctx);
+ }
+
+ free_table(table);
+}
+
+static void filter_table_update_counters(struct table *table)
+{
+ int r;
+ struct rule *rule;
+ struct filter_table_context *ctx = table->ctx;
+ struct shared_codegen *shared = &ctx->shared;
+ int map_fd = shared->maps_fd[CODEGEN_MAP_COUNTERS];
+
+ for (uint32_t i = 0; i < table->num_rules; ++i) {
+ rule = &table->rules[i];
+
+ r = bpf_map_lookup_elem(map_fd, &rule->index,
+ (void *)&rule->ipt_entry->counters);
+ if (r < 0) {
+ BFLOG_DBG("couldn't fetch counter for rule at %p",
+ rule);
+ }
+ }
+}
+
+const struct table_ops filter_table_ops = {
+ .name = "filter",
+ .create = filter_table_create,
+ .codegen = filter_table_codegen,
+ .install = filter_table_install,
+ .uninstall = filter_table_uninstall,
+ .free = filter_table_free,
+ .update_counters = filter_table_update_counters
+};
+
+static uint8_t filter_table_replace_blob[] = {
+ 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+ 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x98, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x10, 0x32, 0x40, 0x36, 0x43, 0x56, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x40, 0x00, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x45, 0x52, 0x52, 0x4f, 0x52, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+int create_filter_table(struct context *ctx)
+{
+ struct mbox_request req;
+
+ req.addr = (__u64)filter_table_replace_blob;
+ req.len = ARRAY_SIZE(filter_table_replace_blob);
+ req.is_set = 1;
+ req.cmd = BPFILTER_IPT_SO_SET_REPLACE;
+ req.pid = getpid();
+
+ return handle_sockopt_request(ctx, &req);
+}
diff --git a/net/bpfilter/filter-table.h b/net/bpfilter/filter-table.h
new file mode 100644
index 000000000000..7d5a8464456f
--- /dev/null
+++ b/net/bpfilter/filter-table.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 Telegram FZ-LLC
+ * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
+ */
+
+#ifndef NET_BPFILTER_FILTER_TABLE_H
+#define NET_BPFILTER_FILTER_TABLE_H
+
+#include "table.h"
+
+struct context;
+
+extern const struct table_ops filter_table_ops;
+
+int create_filter_table(struct context *ctx);
+
+#endif // NET_BPFILTER_FILTER_TABLE_H
diff --git a/tools/testing/selftests/bpf/bpfilter/.gitignore b/tools/testing/selftests/bpf/bpfilter/.gitignore
index a934ddef58d2..926cbb0cfb59 100644
--- a/tools/testing/selftests/bpf/bpfilter/.gitignore
+++ b/tools/testing/selftests/bpf/bpfilter/.gitignore
@@ -5,3 +5,4 @@ test_match
test_xt_udp
test_target
test_rule
+test_codegen
diff --git a/tools/testing/selftests/bpf/bpfilter/Makefile b/tools/testing/selftests/bpf/bpfilter/Makefile
index 53634699d427..9eb558dfc99a 100644
--- a/tools/testing/selftests/bpf/bpfilter/Makefile
+++ b/tools/testing/selftests/bpf/bpfilter/Makefile
@@ -15,6 +15,7 @@ TEST_GEN_PROGS += test_match
TEST_GEN_PROGS += test_xt_udp
TEST_GEN_PROGS += test_target
TEST_GEN_PROGS += test_rule
+TEST_GEN_PROGS += test_codegen

KSFT_KHDR_INSTALL := 1

@@ -46,9 +47,11 @@ BPFILTER_COMMON_SRCS := $(BPFILTER_MAP_SRCS) $(BPFILTER_CODEGEN_SRCS)
BPFILTER_COMMON_SRCS += $(BPFILTERSRCDIR)/context.c $(BPFILTERSRCDIR)/logger.c
BPFILTER_COMMON_SRCS += $(BPFILTER_MATCH_SRCS) $(BPFILTER_TARGET_SRCS)
BPFILTER_COMMON_SRCS += $(BPFILTER_RULE_SRCS) $(BPFILTERSRCDIR)/table.c
+BPFILTER_COMMON_SRCS += $(BPFILTERSRCDIR)/filter-table.c $(BPFILTERSRCDIR)/sockopt.c

$(OUTPUT)/test_map: test_map.c $(BPFILTER_MAP_SRCS)
$(OUTPUT)/test_match: test_match.c $(BPFILTER_COMMON_SRCS)
$(OUTPUT)/test_xt_udp: test_xt_udp.c $(BPFILTER_COMMON_SRCS)
$(OUTPUT)/test_target: test_target.c $(BPFILTER_COMMON_SRCS)
$(OUTPUT)/test_rule: test_rule.c $(BPFILTER_COMMON_SRCS)
+$(OUTPUT)/test_codegen: test_codegen.c $(BPFILTER_COMMON_SRCS)
diff --git a/tools/testing/selftests/bpf/bpfilter/bpfilter_util.h b/tools/testing/selftests/bpf/bpfilter/bpfilter_util.h
index 8dd7911fa06f..846b50bdab07 100644
--- a/tools/testing/selftests/bpf/bpfilter/bpfilter_util.h
+++ b/tools/testing/selftests/bpf/bpfilter/bpfilter_util.h
@@ -3,12 +3,39 @@
#ifndef BPFILTER_UTIL_H
#define BPFILTER_UTIL_H

+#include <linux/bpf.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>

#include <stdio.h>
#include <stdint.h>
#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+static inline int sys_bpf(int cmd, union bpf_attr *attr, unsigned int size)
+{
+ return syscall(SYS_bpf, cmd, attr, size);
+}
+
+static inline int bpf_prog_test_run(int fd, const void *data,
+ unsigned int data_size, uint32_t *retval)
+{
+ union bpf_attr attr = {};
+ int r;
+
+ attr.test.prog_fd = fd;
+ attr.test.data_in = (uintptr_t)data;
+ attr.test.data_size_in = data_size;
+ attr.test.repeat = 1000000;
+
+ r = sys_bpf(BPF_PROG_TEST_RUN, &attr, sizeof(attr));
+
+ if (retval)
+ *retval = attr.test.retval;
+
+ return r;
+}

static inline void init_entry_match(struct xt_entry_match *match,
uint16_t size, uint8_t revision,
diff --git a/tools/testing/selftests/bpf/bpfilter/test_codegen.c b/tools/testing/selftests/bpf/bpfilter/test_codegen.c
new file mode 100644
index 000000000000..9f11b7b8a126
--- /dev/null
+++ b/tools/testing/selftests/bpf/bpfilter/test_codegen.c
@@ -0,0 +1,338 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define _GNU_SOURCE
+
+#include <linux/bpf.h>
+#include <linux/bpfilter.h>
+
+#include <linux/err.h>
+#include <linux/pkt_cls.h>
+
+#include "../../kselftest_harness.h"
+
+#include <stdint.h>
+
+#include "codegen.h"
+#include "context.h"
+#include "filter-table.h"
+#include "logger.h"
+#include "table.h"
+
+#include "bpfilter_util.h"
+
+FIXTURE(test_codegen)
+{
+ struct context ctx;
+ struct shared_codegen shared_codegen;
+ struct codegen codegen;
+ struct table *table;
+ int prog_fd;
+ uint32_t retval;
+ union bpf_attr attr;
+};
+
+FIXTURE_VARIANT(test_codegen)
+{
+ const struct bpfilter_ipt_replace *replace_blob;
+ size_t replace_blob_size;
+ const uint8_t *packet;
+ size_t packet_size;
+ enum bpf_prog_type prog_type;
+ int hook;
+ int expected_retval;
+};
+
+/*
+ * Generated by iptables-save v1.8.2 on Sat May 8 05:22:41 2021
+ * *filter
+ * :INPUT ACCEPT [0:0]
+ * :FORWARD ACCEPT [0:0]
+ * :OUTPUT ACCEPT [0:0]
+ * -A INPUT -s 1.1.1.1/32 -d 2.2.2.2/32 -j DROP
+ * -A INPUT -s 2.2.0.0/16 -d 3.0.0.0/8 -j DROP
+ * -A INPUT -p udp -m udp --sport 100 --dport 500 -j DROP
+ * COMMIT
+ */
+
+static const uint8_t user_defined_chain_blob[] = {
+ 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x70, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x90, 0x02, 0x00, 0x00,
+ 0x28, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00,
+ 0x90, 0x02, 0x00, 0x00, 0x28, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0xe0, 0x26, 0x99, 0xca, 0x67, 0x55, 0x00, 0x00,
+ 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xa0, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x75, 0x64, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x64, 0x00, 0xf4, 0x01, 0xf4, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x40, 0x00, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x45, 0x52, 0x52, 0x4f, 0x52, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// Generated by scapy
+// Ether(src='00:11:22:33:44:55',dst='66:77:88:99:aa:bb')/IP(src='1.1.1.1',dst='2.2.2.2')/UDP(sport=100,dport=200)
+static const uint8_t udp_packet_1[] = {
+ 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0x00, 0x11,
+ 0x22, 0x33, 0x44, 0x55, 0x08, 0x00, 0x45, 0x00,
+ 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
+ 0x74, 0xcb, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02,
+ 0x02, 0x02, 0x00, 0x64, 0x00, 0xc8, 0x00, 0x08,
+ 0xf8, 0xac,
+};
+
+// Ether(src='00:11:22:33:44:55',dst='66:77:88:99:aa:bb')/IP(src='2.2.2.2',dst='3.1.4.1')/UDP(sport=100,dport=200)
+static const uint8_t udp_packet_2[] = {
+ 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0x00, 0x11,
+ 0x22, 0x33, 0x44, 0x55, 0x08, 0x00, 0x45, 0x00,
+ 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
+ 0x6f, 0xcb, 0x02, 0x02, 0x02, 0x02, 0x03, 0x01,
+ 0x04, 0x01, 0x00, 0x64, 0x00, 0xc8, 0x00, 0x08,
+ 0xf3, 0xac,
+};
+
+// Ether(src='00:11:22:33:44:55',dst='66:77:88:99:aa:bb')/IP(src='2.7.1.8',dst='3.1.4.1')/UDP(sport=100,dport=500)
+static const uint8_t udp_packet_3[] = {
+ 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0x00, 0x11,
+ 0x22, 0x33, 0x44, 0x55, 0x08, 0x00, 0x45, 0x00,
+ 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
+ 0x70, 0xc0, 0x02, 0x07, 0x01, 0x08, 0x03, 0x01,
+ 0x04, 0x01, 0x00, 0x64, 0x01, 0xf4, 0x00, 0x08,
+ 0xf3, 0x75,
+};
+
+// Ether(src='00:11:22:33:44:55',dst='66:77:88:99:aa:bb')/IP(src='5.5.5.5',dst='5.5.5.5')/UDP(sport=300,dport=300)
+static const uint8_t udp_packet_4[] = {
+ 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0x00, 0x11,
+ 0x22, 0x33, 0x44, 0x55, 0x08, 0x00, 0x45, 0x00,
+ 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
+ 0x66, 0xbd, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x01, 0x2c, 0x01, 0x2c, 0x00, 0x08,
+ 0xe9, 0x72,
+};
+
+FIXTURE_VARIANT_ADD(test_codegen, drop_by_ip_tc) {
+ .replace_blob = (const struct bpfilter_ipt_replace *)user_defined_chain_blob,
+ .replace_blob_size = ARRAY_SIZE(user_defined_chain_blob),
+ .packet = udp_packet_1,
+ .packet_size = ARRAY_SIZE(udp_packet_1),
+ .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+ .hook = BPFILTER_INET_HOOK_LOCAL_IN,
+ .expected_retval = TC_ACT_SHOT,
+};
+
+FIXTURE_VARIANT_ADD(test_codegen, drop_by_net_tc) {
+ .replace_blob = (const struct bpfilter_ipt_replace *)user_defined_chain_blob,
+ .replace_blob_size = ARRAY_SIZE(user_defined_chain_blob),
+ .packet = udp_packet_2,
+ .packet_size = ARRAY_SIZE(udp_packet_2),
+ .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+ .hook = BPFILTER_INET_HOOK_LOCAL_IN,
+ .expected_retval = TC_ACT_SHOT,
+};
+
+FIXTURE_VARIANT_ADD(test_codegen, drop_by_udp_port_tc) {
+ .replace_blob = (const struct bpfilter_ipt_replace *)user_defined_chain_blob,
+ .replace_blob_size = ARRAY_SIZE(user_defined_chain_blob),
+ .packet = udp_packet_3,
+ .packet_size = ARRAY_SIZE(udp_packet_3),
+ .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+ .hook = BPFILTER_INET_HOOK_LOCAL_IN,
+ .expected_retval = TC_ACT_SHOT,
+};
+
+FIXTURE_VARIANT_ADD(test_codegen, accept_tc) {
+ .replace_blob = (const struct bpfilter_ipt_replace *)user_defined_chain_blob,
+ .replace_blob_size = ARRAY_SIZE(user_defined_chain_blob),
+ .packet = udp_packet_4,
+ .packet_size = ARRAY_SIZE(udp_packet_4),
+ .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+ .hook = BPFILTER_INET_HOOK_LOCAL_IN,
+ .expected_retval = TC_ACT_UNSPEC,
+};
+
+FIXTURE_SETUP(test_codegen)
+{
+ logger_set_file(stderr);
+ ASSERT_EQ(create_context(&self->ctx), 0);
+
+ create_shared_codegen(&self->shared_codegen);
+ ASSERT_EQ(0, create_codegen(&self->codegen, variant->prog_type));
+
+ self->codegen.ctx = &self->ctx;
+ self->codegen.shared_codegen = &self->shared_codegen;
+ self->codegen.iptables_hook = variant->hook;
+
+ self->table = filter_table_ops.create(&self->ctx, variant->replace_blob);
+ ASSERT_FALSE(IS_ERR_OR_NULL(self->table));
+
+ ASSERT_EQ(0, try_codegen(&self->codegen, self->table));
+
+ self->prog_fd = load_img(&self->codegen);
+ ASSERT_GT(self->prog_fd, -1)
+ TH_LOG("load_img(): '%s': %s", STRERR(self->prog_fd),
+ self->codegen.log_buf);
+};
+
+FIXTURE_TEARDOWN(test_codegen)
+{
+ filter_table_ops.free(self->table);
+ unload_img(&self->codegen);
+ free_codegen(&self->codegen);
+ free_context(&self->ctx);
+ if (self->prog_fd > -1)
+ close(self->prog_fd);
+};
+
+TEST_F(test_codegen, test_run)
+{
+ EXPECT_EQ(0, bpf_prog_test_run(self->prog_fd, variant->packet,
+ variant->packet_size, &self->retval))
+ TH_LOG("cannot bpf_prog_test_run(): '%s'", STRERR(errno));
+ EXPECT_EQ(self->retval, variant->expected_retval)
+ TH_LOG("expected: %d, actual: %d\n", variant->expected_retval,
+ self->retval);
+}
+
+TEST_HARNESS_MAIN
--
2.38.1