All of lore.kernel.org
 help / color / mirror / Atom feed
From: Florian Westphal <fw@strlen.de>
To: <netdev@vger.kernel.org>
Cc: daniel@iogearbox.net, ast@kernel.org, pablo@netfilter.org,
	Florian Westphal <fw@strlen.de>
Subject: [RFC,POC 3/3] bpfilter: switch bpfilter to iptables->IMR translation
Date: Sun,  4 Mar 2018 20:40:44 +0100	[thread overview]
Message-ID: <20180304194044.26751-4-fw@strlen.de> (raw)
In-Reply-To: <20180304194044.26751-1-fw@strlen.de>

Translate basic iptables rule blob to the IMR, then ask
IMR to translate to ebpf.

IMR is shared between nft and bpfilter translators.
iptables_gen_append() is the only relevant function here,
as it demonstrates simple 'source/destination matches x' test.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 net/bpfilter/Makefile       |  2 +-
 net/bpfilter/bpfilter_gen.h | 15 +++++++++
 net/bpfilter/bpfilter_mod.h | 16 +---------
 net/bpfilter/iptables.c     | 76 +++++++++++++++++++++++++++++++++++++++++++++
 net/bpfilter/iptables.h     |  4 +++
 net/bpfilter/sockopt.c      | 73 +++++++++++++++++++++++++++++++++----------
 6 files changed, 154 insertions(+), 32 deletions(-)
 create mode 100644 net/bpfilter/bpfilter_gen.h
 create mode 100644 net/bpfilter/iptables.c
 create mode 100644 net/bpfilter/iptables.h

diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile
index a4064986dc2f..21a8afb60b7c 100644
--- a/net/bpfilter/Makefile
+++ b/net/bpfilter/Makefile
@@ -5,7 +5,7 @@
 
 hostprogs-y := nftjit.ko bpfilter.ko
 always := $(hostprogs-y)
-bpfilter.ko-objs := bpfilter.o tgts.o targets.o tables.o init.o ctor.o sockopt.o gen.o
+bpfilter.ko-objs := bpfilter.o tgts.o targets.o tables.o init.o ctor.o sockopt.o gen.o iptables.o imr.o
 
 NFT_LIBS = -lnftnl
 nftjit.ko-objs := tgts.o targets.o tables.o init.o ctor.o gen.o nftables.o imr.o
diff --git a/net/bpfilter/bpfilter_gen.h b/net/bpfilter/bpfilter_gen.h
new file mode 100644
index 000000000000..71c6e8a73e24
--- /dev/null
+++ b/net/bpfilter/bpfilter_gen.h
@@ -0,0 +1,15 @@
+struct bpfilter_gen_ctx {
+	struct bpf_insn		*img;
+	u32			len_cur;
+	u32			len_max;
+	u32			default_verdict;
+	int			fd;
+	int			ifindex;
+	bool			offloaded;
+};
+
+int bpfilter_gen_init(struct bpfilter_gen_ctx *ctx);
+int bpfilter_gen_prologue(struct bpfilter_gen_ctx *ctx);
+int bpfilter_gen_epilogue(struct bpfilter_gen_ctx *ctx);
+int bpfilter_gen_commit(struct bpfilter_gen_ctx *ctx);
+void bpfilter_gen_destroy(struct bpfilter_gen_ctx *ctx);
diff --git a/net/bpfilter/bpfilter_mod.h b/net/bpfilter/bpfilter_mod.h
index b4209985efff..dc3a90df1788 100644
--- a/net/bpfilter/bpfilter_mod.h
+++ b/net/bpfilter/bpfilter_mod.h
@@ -4,6 +4,7 @@
 
 #include "include/uapi/linux/bpfilter.h"
 #include <linux/list.h>
+#include "bpfilter_gen.h"
 
 struct bpfilter_table {
 	struct hlist_node	hash;
@@ -71,26 +72,11 @@ struct bpfilter_target {
 	u8			rev;
 };
 
-struct bpfilter_gen_ctx {
-	struct bpf_insn		*img;
-	u32			len_cur;
-	u32			len_max;
-	u32			default_verdict;
-	int			fd;
-	int			ifindex;
-	bool			offloaded;
-};
-
 union bpf_attr;
 int sys_bpf(int cmd, union bpf_attr *attr, unsigned int size);
 
-int bpfilter_gen_init(struct bpfilter_gen_ctx *ctx);
-int bpfilter_gen_prologue(struct bpfilter_gen_ctx *ctx);
-int bpfilter_gen_epilogue(struct bpfilter_gen_ctx *ctx);
 int bpfilter_gen_append(struct bpfilter_gen_ctx *ctx,
 			struct bpfilter_ipt_ip *ent, int verdict);
-int bpfilter_gen_commit(struct bpfilter_gen_ctx *ctx);
-void bpfilter_gen_destroy(struct bpfilter_gen_ctx *ctx);
 
 struct bpfilter_target *bpfilter_target_get_by_name(const char *name);
 void bpfilter_target_put(struct bpfilter_target *tgt);
diff --git a/net/bpfilter/iptables.c b/net/bpfilter/iptables.c
new file mode 100644
index 000000000000..055cfa8fbf21
--- /dev/null
+++ b/net/bpfilter/iptables.c
@@ -0,0 +1,76 @@
+#include <string.h>
+#include <stdint.h>
+
+typedef uint16_t __sum16; /* hack */
+#include <linux/ip.h>
+
+#include "bpfilter_mod.h"
+#include "iptables.h"
+#include "imr.h"
+
+static int check_entry(const struct bpfilter_ipt_ip *ent)
+{
+#define M_FF	"\xff\xff\xff\xff"
+	static const __u8 mask1[IFNAMSIZ] = M_FF M_FF M_FF M_FF;
+	static const __u8 mask0[IFNAMSIZ] = { };
+	int ones = strlen(ent->in_iface); ones += ones > 0;
+#undef M_FF
+	if (strlen(ent->out_iface) > 0)
+		return -ENOTSUPP;
+	if (memcmp(ent->in_iface_mask, mask1, ones) ||
+	    memcmp(&ent->in_iface_mask[ones], mask0, sizeof(mask0) - ones))
+		return -ENOTSUPP;
+	if ((ent->src_mask != 0 && ent->src_mask != 0xffffffff) ||
+	    (ent->dst_mask != 0 && ent->dst_mask != 0xffffffff))
+		return -ENOTSUPP;
+
+	return 0;
+}
+
+int iptables_gen_append(struct imr_state *state,
+			struct bpfilter_ipt_ip *ent, int verdict)
+{
+	struct imr_object *left, *right, *relop;
+	int ret;
+
+	ret = check_entry(ent);
+	if (ret < 0)
+		return ret;
+	if (ent->src_mask == 0 && ent->dst_mask == 0)
+		return 0;
+
+	imr_state_rule_begin(state);
+
+	if (ent->src_mask) {
+		left = imr_object_alloc_payload(IMR_PAYLOAD_BASE_NH,
+					        offsetof(struct iphdr, saddr),
+					        sizeof(uint32_t));
+		right = imr_object_alloc_imm32(ent->src);
+
+		relop = imr_object_alloc_relational(IMR_RELOP_EQ, left, right);
+		imr_state_add_obj(state, relop);
+	}
+
+	if (ent->dst_mask) {
+		left = imr_object_alloc_payload(IMR_PAYLOAD_BASE_NH,
+					        offsetof(struct iphdr, daddr),
+					        sizeof(uint32_t));
+		right = imr_object_alloc_imm32(ent->dst);
+
+		relop = imr_object_alloc_relational(IMR_RELOP_EQ, left, right);
+		imr_state_add_obj(state, relop);
+	}
+
+	switch (verdict) {
+	case -1:
+		verdict = IMR_VERDICT_DROP;
+		break;
+	default:
+		verdict = IMR_VERDICT_PASS;
+		break;
+	}
+
+	imr_state_add_obj(state, imr_object_alloc_verdict(verdict));
+
+	return imr_state_rule_end(state);
+}
diff --git a/net/bpfilter/iptables.h b/net/bpfilter/iptables.h
new file mode 100644
index 000000000000..8d1299f10e55
--- /dev/null
+++ b/net/bpfilter/iptables.h
@@ -0,0 +1,4 @@
+#include "imr.h"
+
+int iptables_gen_append(struct imr_state *state,
+			struct bpfilter_ipt_ip *ent, int verdict);
diff --git a/net/bpfilter/sockopt.c b/net/bpfilter/sockopt.c
index 26ad12a11736..c601fa0839a1 100644
--- a/net/bpfilter/sockopt.c
+++ b/net/bpfilter/sockopt.c
@@ -5,8 +5,13 @@
 #include <stdlib.h>
 
 #include <sys/socket.h>
+#include <net/if.h>
+
+#include <linux/if_ether.h>
+#include <arpa/inet.h>
 
 #include "bpfilter_mod.h"
+#include "iptables.h"
 
 /* TODO: Get all of this in here properly done in encoding/decoding layer. */
 static int fetch_name(void *addr, int len, char *name, int name_len)
@@ -144,22 +149,53 @@ int bpfilter_get_entries(void *cmd, int len)
 	return err;
 }
 
+/* We run via XDP so skip non ip ethernet frames */
+static int iptables_accept_non_ipv4(struct imr_state *state)
+{
+	struct imr_object *eth_p_ip, *lltype, *relop;
+	int ret;
+
+	imr_state_rule_begin(state);
+	lltype = imr_object_alloc_payload(IMR_PAYLOAD_BASE_LL,
+					  offsetof(struct ethhdr, h_proto),
+					  sizeof(uint16_t));
+	if (!lltype)
+		return -ENOMEM;
+
+	eth_p_ip = imr_object_alloc_imm32(htons(ETH_P_IP));
+	if (!eth_p_ip) {
+		imr_object_free(lltype);
+		return -ENOMEM;
+	}
+
+	relop = imr_object_alloc_relational(IMR_RELOP_NE, lltype, eth_p_ip);
+	if (!relop) {
+		imr_object_free(eth_p_ip);
+		imr_object_free(lltype);
+		return -ENOMEM;
+	}
+
+	ret = imr_state_add_obj(state, relop);
+	if (ret == 0) {
+		ret = imr_state_add_obj(state, imr_object_alloc_verdict(IMR_VERDICT_PASS));
+		if (ret == 0)
+			return imr_state_rule_end(state);
+	}
+
+	return ret;
+}
+
 static int do_set_replace(struct bpfilter_ipt_replace *req, void *base,
 			  struct bpfilter_table *tbl)
 {
 	unsigned int total_size = req->size;
 	struct bpfilter_table_info *info;
 	struct bpfilter_ipt_entry *ent;
-	struct bpfilter_gen_ctx ctx;
+	struct imr_state *imr_state;
 	unsigned int off, sents = 0, ents = 0;
+	int last_iface = 0;
 	int ret;
 
-	ret = bpfilter_gen_init(&ctx);
-	if (ret < 0)
-		return ret;
-	ret = bpfilter_gen_prologue(&ctx);
-	if (ret < 0)
-		return ret;
 	info = bpfilter_ipv4_table_alloc(tbl, total_size);
 	if (!info)
 		return -ENOMEM;
@@ -167,15 +203,25 @@ static int do_set_replace(struct bpfilter_ipt_replace *req, void *base,
 		free(info);
 		return -EFAULT;
 	}
+	imr_state = imr_state_alloc();
 	base = &info->entries[0];
+	iptables_accept_non_ipv4(imr_state);
 	for (off = 0; off < total_size; off += ent->next_offset) {
 		struct bpfilter_standard_target *tgt;
+		int ifindex;
 		ent = base + off;
+		ifindex = if_nametoindex(ent->ip.in_iface);
+		if (!ifindex)
+			continue;
+		if (last_iface && last_iface != ifindex)
+			return -ENOTSUPP;
+		else
+			last_iface = ifindex;
 		ents++;
 		sents += ent->next_offset;
 		tgt = (void *) ent + ent->target_offset;
 		target_u2k(tgt);
-		ret = bpfilter_gen_append(&ctx, &ent->ip, tgt->verdict);
+		ret = iptables_gen_append(imr_state, &ent->ip, tgt->verdict);
                 if (ret < 0)
                         goto err;
 	}
@@ -183,16 +229,11 @@ static int do_set_replace(struct bpfilter_ipt_replace *req, void *base,
 	info->size = sents;
 	memcpy(info->hook_entry, req->hook_entry, sizeof(info->hook_entry));
 	memcpy(info->underflow, req->underflow, sizeof(info->hook_entry));
-	ret = bpfilter_gen_epilogue(&ctx);
-	if (ret < 0)
-		goto err;
-	ret = bpfilter_gen_commit(&ctx);
-	if (ret < 0)
-		goto err;
+	ret = imr_do_bpf(imr_state);
+	imr_state_free(imr_state);
 	free(tbl->info);
 	tbl->info = info;
-	bpfilter_gen_destroy(&ctx);
-	dprintf(debug_fd, "offloaded %u\n", ctx.offloaded);
+
 	return ret;
 err:
 	free(info);
-- 
2.16.1

  parent reply	other threads:[~2018-03-04 19:42 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-04 19:40 [RFC,POC] iptables/nftables to epbf/xdp via common intermediate layer Florian Westphal
2018-03-04 19:40 ` [RFC,POC 1/3] bpfilter: add experimental IMR bpf translator Florian Westphal
2018-03-04 19:40 ` [RFC,POC 2/3] bpfilter: add nftables jit proof-of-concept Florian Westphal
2018-03-04 19:40 ` Florian Westphal [this message]
2018-03-06 14:22 ` [RFC,POC] iptables/nftables to epbf/xdp via common intermediate layer Daniel Borkmann
2018-03-06 16:42   ` Florian Westphal
2018-03-06 17:24     ` Edward Cree
2018-03-06 18:03       ` Florian Westphal
2018-03-06 18:18         ` Edward Cree
2018-03-15 16:13           ` Alexei Starovoitov
2018-03-15 17:00             ` Florian Westphal
2018-03-15 20:26               ` Alexei Starovoitov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180304194044.26751-4-fw@strlen.de \
    --to=fw@strlen.de \
    --cc=ast@kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=netdev@vger.kernel.org \
    --cc=pablo@netfilter.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.