diff --git a/xdp-forward/Makefile b/xdp-forward/Makefile index 17e8374e..17aa4317 100644 --- a/xdp-forward/Makefile +++ b/xdp-forward/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -XDP_TARGETS := xdp_forward.bpf xdp_flowtable.bpf +XDP_TARGETS := xdp_forward.bpf xdp_flowtable.bpf xdp_flowtable_sample.bpf BPF_SKEL_TARGETS := $(XDP_TARGETS) XDP_OBJ_INSTALL := diff --git a/xdp-forward/README.org b/xdp-forward/README.org index d640e18c..bb2dfff8 100644 --- a/xdp-forward/README.org +++ b/xdp-forward/README.org @@ -14,8 +14,8 @@ xdp-forward is an XDP forwarding plane, which will accelerate packet forwarding using XDP. To use it, simply load it on the set of interfaces to accelerate forwarding between. The userspace component of xdp-forward will then configure and load XDP programs on those interfaces, and forward packets between them -using XDP_REDIRECT, using the kernel routing table to determine the destination -if each packet. +using XDP_REDIRECT, using the kernel routing table or netfilter flowtable to +determine the destination for each packet. Any packets that xdp-forward does not know how to forward will be passed up to the networking stack and handled by the kernel like normal. Depending on the @@ -121,6 +121,35 @@ The =fib-direct= mode functions like =fib-full=, except it passes the policy routing rules configured will be skipped during the lookup, which can improve performance (but won't obey the policy of those rules, obviously). +** flowtable +The =flowtable= operating mode offloads netfilter sw flowtable logic in +the XDP layer if the hardware flowtable is not available. +At the moment =xdp-forward= is able to offload just TCP or UDP netfilter +flowtable entries to XDP. The user is supposed to configure the flowtable +separately. + +* Examples + +In order to enable flowtable offloading for tcp and udp traffic between NICs +n0 and n1, issue the following commands: + +#+begin_src sh +#nft -f /dev/stdin <fwd_mode) { case FWD_FIB_FULL: @@ -125,23 +144,48 @@ static int do_load(const void *cfg, __unused const char *pin_root_path) case FWD_FIB_DIRECT: opts.prog_name = "xdp_fwd_fib_direct"; break; + case FWD_FLOWTABLE: + opts.prog_name = "xdp_fwd_flowtable"; + break; default: goto end; } - skel = xdp_forward__open(); - if (!skel) { - pr_warn("Failed to load skeleton: %s\n", strerror(errno)); - goto end; + if (opt->fwd_mode == FWD_FLOWTABLE) { + struct xdp_flowtable *xdp_flowtable_skel; + + if (!sample_probe_bpf_xdp_flow_lookup()) { + pr_warn("The kernel does not support the bpf_xdp_flow_lookup() kfunc\n"); + goto end; + } + + xdp_flowtable_skel = xdp_flowtable__open(); + if (!xdp_flowtable_skel) { + pr_warn("Failed to load skeleton: %s\n", strerror(errno)); + goto end; + } + map = xdp_flowtable_skel->maps.xdp_tx_ports; + obj = xdp_flowtable_skel->obj; + skel = (void *)xdp_flowtable_skel; + } else { + struct xdp_forward *xdp_forward_skel = xdp_forward__open(); + + if (!xdp_forward_skel) { + pr_warn("Failed to load skeleton: %s\n", strerror(errno)); + goto end; + } + map = xdp_forward_skel->maps.xdp_tx_ports; + obj = xdp_forward_skel->obj; + skel = (void *)xdp_forward_skel; } /* Make sure we only load the one XDP program we are interested in */ - while ((prog = bpf_object__next_program(skel->obj, prog)) != NULL) + while ((prog = bpf_object__next_program(obj, prog)) != NULL) if (bpf_program__type(prog) == BPF_PROG_TYPE_XDP && bpf_program__expected_attach_type(prog) == BPF_XDP) bpf_program__set_autoload(prog, false); - opts.obj = skel->obj; + opts.obj = obj; xdp_prog = xdp_program__create(&opts); if (!xdp_prog) { ret = -errno; @@ -177,8 +221,8 @@ static int do_load(const void *cfg, __unused const char *pin_root_path) goto end_detach; } - ret = bpf_map_update_elem(bpf_map__fd(skel->maps.xdp_tx_ports), - &iface->ifindex, &iface->ifindex, 0); + ret = bpf_map_update_elem(bpf_map__fd(map), &iface->ifindex, + &iface->ifindex, 0); if (ret) { pr_warn("Failed to update devmap value: %s\n", strerror(errno)); @@ -188,7 +232,10 @@ static int do_load(const void *cfg, __unused const char *pin_root_path) } end_destroy: - xdp_forward__destroy(skel); + if (opt->fwd_mode == FWD_FLOWTABLE) + xdp_flowtable__destroy(skel); + else + xdp_forward__destroy(skel); end: return ret; diff --git a/xdp-forward/xdp_flowtable_sample.bpf.c b/xdp-forward/xdp_flowtable_sample.bpf.c new file mode 100644 index 00000000..185120a2 --- /dev/null +++ b/xdp-forward/xdp_flowtable_sample.bpf.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Original xdp_fwd sample Copyright (c) 2017-18 David Ahern + */ + +#include +#include +#include +#include + +#define AF_INET 2 + +struct bpf_flowtable_opts { + __s32 error; +}; + +struct flow_offload_tuple_rhash * +bpf_xdp_flow_lookup(struct xdp_md *, struct bpf_fib_lookup *, + struct bpf_flowtable_opts *, __u32) __ksym; + +SEC("xdp") +int xdp_fwd_flowtable_sample(struct xdp_md *ctx) +{ + struct flow_offload_tuple_rhash *tuplehash; + struct bpf_flowtable_opts opts = {}; + struct bpf_fib_lookup tuple = { + .family = AF_INET, + .ifindex = ctx->ingress_ifindex, + }; + + tuplehash = bpf_xdp_flow_lookup(ctx, &tuple, &opts, sizeof(opts)); + if (!tuplehash) + return XDP_DROP; + + return XDP_PASS; +} + +char _license[] SEC("license") = "GPL";