Skip to content

Commit

Permalink
xdp-forward: Add the capability to load xdp_fwd_flowtable sample from…
Browse files Browse the repository at this point in the history
… userspace

Introduce the capability to load xdp-fw-flowtable sample to offload in
xdp the processing of sw netfilter flowtable.

Signed-off-by: Lorenzo Bianconi <[email protected]>
  • Loading branch information
LorenzoBianconi authored and tohojo committed Oct 11, 2024
1 parent 9db1ee6 commit 7881bee
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 18 deletions.
2 changes: 1 addition & 1 deletion xdp-forward/Makefile
Original file line number Diff line number Diff line change
@@ -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 :=
Expand Down
33 changes: 31 additions & 2 deletions xdp-forward/README.org
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 <<EOF
table inet filter {
flowtable ft {
hook ingress priority filter
devices = { n0, n1 }
}
chain forward {
type filter hook forward priority filter
meta l4proto { tcp, udp } flow add @ft
}
}
EOF

#xdp-forward load -f flowtable n0 n1
#+end_src

* SEE ALSO
=libxdp(3)= for details on the XDP loading semantics and kernel compatibility
requirements.
Expand Down
39 changes: 36 additions & 3 deletions xdp-forward/xdp-forward.8
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH "xdp-forward" "8" "JULY 30, 2024" "V1.4.2" "XDP program loader"
.TH "xdp-forward" "8" "OCTOBER 10, 2024" "V1.4.3" "XDP program loader"

.SH "NAME"
xdp-forward \- the XDP forwarding plane
Expand All @@ -8,8 +8,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.

.PP
Any packets that xdp-forward does not know how to forward will be passed up to
Expand Down Expand Up @@ -141,6 +141,39 @@ The \fIfib\-direct\fP mode functions like \fIfib\-full\fP, 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).

.SS "flowtable"
.PP
The \fIflowtable\fP operating mode offloads netfilter sw flowtable logic in
the XDP layer if the hardware flowtable is not available.
At the moment \fIxdp\-forward\fP is able to offload just TCP or UDP netfilter
flowtable entries to XDP. The user is supposed to configure the flowtable
separately.

.SH "Examples"
.PP
In order to enable flowtable offloading for tcp and udp traffic between NICs
n0 and n1, issue the following commands:

.RS
.nf
\fC#nft -f /dev/stdin <<EOF
table inet filter {
flowtable ft {
hook ingress priority filter
devices = { n0, n1 }
}
chain forward {
type filter hook forward priority filter
meta l4proto { tcp, udp } flow add @ft
}
}
EOF

#xdp-forward load -f flowtable n0 n1
\fP
.fi
.RE

.SH "SEE ALSO"
.PP
\fIlibxdp(3)\fP for details on the XDP loading semantics and kernel compatibility
Expand Down
71 changes: 59 additions & 12 deletions xdp-forward/xdp-forward.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "compat.h"

#include "xdp_forward.skel.h"
#include "xdp_flowtable.skel.h"
#include "xdp_flowtable_sample.skel.h"

#define MAX_IFACE_NUM 32
#define PROG_NAME "xdp-forward"
Expand All @@ -36,11 +38,13 @@ struct enum_val xdp_modes[] = { { "native", XDP_MODE_NATIVE },

enum fwd_mode {
FWD_FIB_DIRECT,
FWD_FIB_FULL
FWD_FIB_FULL,
FWD_FLOWTABLE,
};

struct enum_val fwd_modes[] = { { "fib-direct", FWD_FIB_DIRECT },
{ "fib-full", FWD_FIB_FULL },
{ "flowtable", FWD_FLOWTABLE },
{ NULL, 0 } };

static int find_prog(struct iface *iface, bool detach)
Expand All @@ -62,7 +66,8 @@ static int find_prog(struct iface *iface, bool detach)
while ((prog = xdp_multiprog__next_prog(prog, mp))) {
check:
if (!strcmp(xdp_program__name(prog), "xdp_fwd_fib_full") ||
!strcmp(xdp_program__name(prog), "xdp_fwd_fib_direct")) {
!strcmp(xdp_program__name(prog), "xdp_fwd_fib_direct") ||
!strcmp(xdp_program__name(prog), "xdp_fwd_flowtable")) {
mode = xdp_multiprog__attach_mode(mp);
ret = 0;
if (detach) {
Expand Down Expand Up @@ -108,15 +113,29 @@ struct prog_option load_options[] = {
END_OPTIONS
};

static bool sample_probe_bpf_xdp_flow_lookup(void)
{
struct xdp_flowtable_sample *skel;
bool res;

skel = xdp_flowtable_sample__open_and_load();
res = !!skel;
xdp_flowtable_sample__destroy(skel);

return res;
}

static int do_load(const void *cfg, __unused const char *pin_root_path)
{
DECLARE_LIBBPF_OPTS(xdp_program_opts, opts);
struct xdp_program *xdp_prog = NULL;
const struct load_opts *opt = cfg;
struct bpf_program *prog = NULL;
struct xdp_forward *skel;
struct bpf_map *map = NULL;
struct bpf_object *obj;
int ret = EXIT_FAILURE;
struct iface *iface;
void *skel;

switch (opt->fwd_mode) {
case FWD_FIB_FULL:
Expand All @@ -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;
Expand Down Expand Up @@ -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));
Expand All @@ -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;

Expand Down
37 changes: 37 additions & 0 deletions xdp-forward/xdp_flowtable_sample.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: GPL-2.0
/* Original xdp_fwd sample Copyright (c) 2017-18 David Ahern <[email protected]>
*/

#include <bpf/vmlinux.h>
#include <linux/bpf.h>
#include <linux/netfilter.h>
#include <bpf/bpf_core_read.h>

#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";

0 comments on commit 7881bee

Please sign in to comment.