bpf,fou: Add bpf_skb_{set,get}_fou_encap kfuncs
authorChristian Ehrig <cehrig@cloudflare.com>
Fri, 7 Apr 2023 13:38:54 +0000 (15:38 +0200)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 12 Apr 2023 23:40:39 +0000 (16:40 -0700)
Add two new kfuncs that allow a BPF tc-hook, installed on an ipip
device in collect-metadata mode, to control FOU encap parameters on a
per-packet level. The set of kfuncs is registered with the fou module.

The bpf_skb_set_fou_encap kfunc is supposed to be used in tandem and after
a successful call to the bpf_skb_set_tunnel_key bpf-helper. UDP source and
destination ports can be controlled by passing a struct bpf_fou_encap. A
source port of zero will auto-assign a source port. enum bpf_fou_encap_type
is used to specify if the egress path should FOU or GUE encap the packet.

On the ingress path bpf_skb_get_fou_encap can be used to read UDP source
and destination ports from the receiver's point of view and allows for
packet multiplexing across different destination ports within a single
BPF program and ipip device.

Signed-off-by: Christian Ehrig <cehrig@cloudflare.com>
Link: https://lore.kernel.org/r/e17c94a646b63e78ce0dbf3f04b2c33dc948a32d.1680874078.git.cehrig@cloudflare.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/net/fou.h
net/ipv4/Makefile
net/ipv4/fou_bpf.c [new file with mode: 0644]
net/ipv4/fou_core.c

index 80f56e275b0871f0ebd9f9c9b2ff3c742a3f6590..824eb4b231fd8c03abd031108e86fe78355f6204 100644 (file)
@@ -17,4 +17,6 @@ int __fou_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
 int __gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
                       u8 *protocol, __be16 *sport, int type);
 
+int register_fou_bpf(void);
+
 #endif
index 880277c9fd07bf8fb12323c43ef1df4faea70417..b18ba8ef93ad2b6c292c2bdf0c47ac22bc74127a 100644 (file)
@@ -26,7 +26,7 @@ obj-$(CONFIG_IP_MROUTE) += ipmr.o
 obj-$(CONFIG_IP_MROUTE_COMMON) += ipmr_base.o
 obj-$(CONFIG_NET_IPIP) += ipip.o
 gre-y := gre_demux.o
-fou-y := fou_core.o fou_nl.o
+fou-y := fou_core.o fou_nl.o fou_bpf.o
 obj-$(CONFIG_NET_FOU) += fou.o
 obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o
 obj-$(CONFIG_NET_IPGRE) += ip_gre.o
diff --git a/net/ipv4/fou_bpf.c b/net/ipv4/fou_bpf.c
new file mode 100644 (file)
index 0000000..3760a14
--- /dev/null
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Unstable Fou Helpers for TC-BPF hook
+ *
+ * These are called from SCHED_CLS BPF programs. Note that it is
+ * allowed to break compatibility for these functions since the interface they
+ * are exposed through to BPF programs is explicitly unstable.
+ */
+
+#include <linux/bpf.h>
+#include <linux/btf_ids.h>
+
+#include <net/dst_metadata.h>
+#include <net/fou.h>
+
+struct bpf_fou_encap {
+       __be16 sport;
+       __be16 dport;
+};
+
+enum bpf_fou_encap_type {
+       FOU_BPF_ENCAP_FOU,
+       FOU_BPF_ENCAP_GUE,
+};
+
+__diag_push();
+__diag_ignore_all("-Wmissing-prototypes",
+                 "Global functions as their definitions will be in BTF");
+
+/* bpf_skb_set_fou_encap - Set FOU encap parameters
+ *
+ * This function allows for using GUE or FOU encapsulation together with an
+ * ipip device in collect-metadata mode.
+ *
+ * It is meant to be used in BPF tc-hooks and after a call to the
+ * bpf_skb_set_tunnel_key helper, responsible for setting IP addresses.
+ *
+ * Parameters:
+ * @skb_ctx    Pointer to ctx (__sk_buff) in TC program. Cannot be NULL
+ * @encap      Pointer to a `struct bpf_fou_encap` storing UDP src and
+ *             dst ports. If sport is set to 0 the kernel will auto-assign a
+ *             port. This is similar to using `encap-sport auto`.
+ *             Cannot be NULL
+ * @type       Encapsulation type for the packet. Their definitions are
+ *             specified in `enum bpf_fou_encap_type`
+ */
+__bpf_kfunc int bpf_skb_set_fou_encap(struct __sk_buff *skb_ctx,
+                                     struct bpf_fou_encap *encap, int type)
+{
+       struct sk_buff *skb = (struct sk_buff *)skb_ctx;
+       struct ip_tunnel_info *info = skb_tunnel_info(skb);
+
+       if (unlikely(!encap))
+               return -EINVAL;
+
+       if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX)))
+               return -EINVAL;
+
+       switch (type) {
+       case FOU_BPF_ENCAP_FOU:
+               info->encap.type = TUNNEL_ENCAP_FOU;
+               break;
+       case FOU_BPF_ENCAP_GUE:
+               info->encap.type = TUNNEL_ENCAP_GUE;
+               break;
+       default:
+               info->encap.type = TUNNEL_ENCAP_NONE;
+       }
+
+       if (info->key.tun_flags & TUNNEL_CSUM)
+               info->encap.flags |= TUNNEL_ENCAP_FLAG_CSUM;
+
+       info->encap.sport = encap->sport;
+       info->encap.dport = encap->dport;
+
+       return 0;
+}
+
+/* bpf_skb_get_fou_encap - Get FOU encap parameters
+ *
+ * This function allows for reading encap metadata from a packet received
+ * on an ipip device in collect-metadata mode.
+ *
+ * Parameters:
+ * @skb_ctx    Pointer to ctx (__sk_buff) in TC program. Cannot be NULL
+ * @encap      Pointer to a struct bpf_fou_encap storing UDP source and
+ *             destination port. Cannot be NULL
+ */
+__bpf_kfunc int bpf_skb_get_fou_encap(struct __sk_buff *skb_ctx,
+                                     struct bpf_fou_encap *encap)
+{
+       struct sk_buff *skb = (struct sk_buff *)skb_ctx;
+       struct ip_tunnel_info *info = skb_tunnel_info(skb);
+
+       if (unlikely(!info))
+               return -EINVAL;
+
+       encap->sport = info->encap.sport;
+       encap->dport = info->encap.dport;
+
+       return 0;
+}
+
+__diag_pop()
+
+BTF_SET8_START(fou_kfunc_set)
+BTF_ID_FLAGS(func, bpf_skb_set_fou_encap)
+BTF_ID_FLAGS(func, bpf_skb_get_fou_encap)
+BTF_SET8_END(fou_kfunc_set)
+
+static const struct btf_kfunc_id_set fou_bpf_kfunc_set = {
+       .owner = THIS_MODULE,
+       .set   = &fou_kfunc_set,
+};
+
+int register_fou_bpf(void)
+{
+       return register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS,
+                                        &fou_bpf_kfunc_set);
+}
index cafec9b4eee01622a09a48197628ea6ef41239e9..0c41076e31edadd16f8e55ebc50f84db262a2f0d 100644 (file)
@@ -1236,10 +1236,15 @@ static int __init fou_init(void)
        if (ret < 0)
                goto unregister;
 
+       ret = register_fou_bpf();
+       if (ret < 0)
+               goto kfunc_failed;
+
        ret = ip_tunnel_encap_add_fou_ops();
        if (ret == 0)
                return 0;
 
+kfunc_failed:
        genl_unregister_family(&fou_nl_family);
 unregister:
        unregister_pernet_device(&fou_net_ops);