mirror of
https://github.com/xdp-project/bpf-examples.git
synced 2024-05-06 15:54:53 +00:00
pping: Use libxdp to load and attach XDP program
Since we now have libxdp as a submodule, we can switch pping over to using libxdp for loading its XDP program. This requires switching the order of attachment, because libxdp needs to be fed the BPF object in an unloaded state (and will load it as part of attaching). Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
This commit is contained in:
143
pping/pping.c
143
pping/pping.c
@@ -19,6 +19,7 @@ static const char *__doc__ =
|
|||||||
#include <sys/resource.h> // For setting rlmit
|
#include <sys/resource.h> // For setting rlmit
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <xdp/libxdp.h>
|
||||||
|
|
||||||
#include "json_writer.h"
|
#include "json_writer.h"
|
||||||
#include "pping.h" //common structs for user-space and BPF parts
|
#include "pping.h" //common structs for user-space and BPF parts
|
||||||
@@ -74,8 +75,8 @@ struct pping_config {
|
|||||||
char *packet_map;
|
char *packet_map;
|
||||||
char *flow_map;
|
char *flow_map;
|
||||||
char *event_map;
|
char *event_map;
|
||||||
int xdp_flags;
|
|
||||||
int ifindex;
|
int ifindex;
|
||||||
|
struct xdp_program *xdp_prog;
|
||||||
int ingress_prog_id;
|
int ingress_prog_id;
|
||||||
int egress_prog_id;
|
int egress_prog_id;
|
||||||
char ifname[IF_NAMESIZE];
|
char ifname[IF_NAMESIZE];
|
||||||
@@ -258,7 +259,6 @@ static int parse_arguments(int argc, char *argv[], struct pping_config *config)
|
|||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
config->force = true;
|
config->force = true;
|
||||||
config->xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST;
|
|
||||||
break;
|
break;
|
||||||
case 'T':
|
case 'T':
|
||||||
config->bpf_config.track_tcp = true;
|
config->bpf_config.track_tcp = true;
|
||||||
@@ -339,51 +339,35 @@ static int init_rodata(struct bpf_object *obj, void *src, size_t size)
|
|||||||
* On failure, will return a negative error code.
|
* On failure, will return a negative error code.
|
||||||
*/
|
*/
|
||||||
static int xdp_attach(struct bpf_object *obj, const char *prog_name,
|
static int xdp_attach(struct bpf_object *obj, const char *prog_name,
|
||||||
int ifindex, __u32 xdp_flags)
|
int ifindex, struct xdp_program **xdp_prog)
|
||||||
{
|
{
|
||||||
struct bpf_program *prog;
|
struct xdp_program *prog;
|
||||||
int prog_fd, err;
|
int err;
|
||||||
__u32 prog_id;
|
DECLARE_LIBXDP_OPTS(xdp_program_opts, opts,
|
||||||
|
.prog_name = prog_name,
|
||||||
|
.obj = obj);
|
||||||
|
|
||||||
if (prog_name)
|
prog = xdp_program__create(&opts);
|
||||||
prog = bpf_object__find_program_by_name(obj, prog_name);
|
if (!prog)
|
||||||
else
|
return -errno;
|
||||||
prog = bpf_object__next_program(obj, NULL);
|
|
||||||
|
|
||||||
prog_fd = bpf_program__fd(prog);
|
err = xdp_program__attach(prog, ifindex, XDP_MODE_UNSPEC, 0);
|
||||||
if (prog_fd < 0)
|
|
||||||
return prog_fd;
|
|
||||||
|
|
||||||
err = bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
err = bpf_get_link_xdp_id(ifindex, &prog_id, xdp_flags);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
bpf_set_link_xdp_fd(ifindex, -1, xdp_flags);
|
xdp_program__close(prog);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return prog_id;
|
*xdp_prog = prog;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xdp_detach(int ifindex, __u32 xdp_flags, __u32 expected_prog_id)
|
static int xdp_detach(struct xdp_program *prog, int ifindex)
|
||||||
{
|
{
|
||||||
__u32 curr_prog_id;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = bpf_get_link_xdp_id(ifindex, &curr_prog_id, xdp_flags);
|
err = xdp_program__detach(prog, ifindex, XDP_MODE_UNSPEC, 0);
|
||||||
if (err)
|
xdp_program__close(prog);
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (!curr_prog_id) {
|
|
||||||
return 0; // No current prog on interface
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expected_prog_id && curr_prog_id != expected_prog_id)
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
return bpf_set_link_xdp_fd(ifindex, -1, xdp_flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -871,26 +855,6 @@ static int set_programs_to_load(struct bpf_object *obj,
|
|||||||
return bpf_program__set_autoload(prog, false);
|
return bpf_program__set_autoload(prog, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Print out some hints for what might have caused an error while attempting
|
|
||||||
* to attach an XDP program. Based on xdp_link_attach() in
|
|
||||||
* xdp-tutorial/common/common_user_bpf_xdp.c
|
|
||||||
*/
|
|
||||||
static void print_xdp_error_hints(FILE *stream, int err)
|
|
||||||
{
|
|
||||||
err = err > 0 ? err : -err;
|
|
||||||
switch (err) {
|
|
||||||
case EBUSY:
|
|
||||||
case EEXIST:
|
|
||||||
fprintf(stream, "Hint: XDP already loaded on device"
|
|
||||||
" use --force to swap/replace\n");
|
|
||||||
break;
|
|
||||||
case EOPNOTSUPP:
|
|
||||||
fprintf(stream, "Hint: Native-XDP not supported\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int load_attach_bpfprogs(struct bpf_object **obj,
|
static int load_attach_bpfprogs(struct bpf_object **obj,
|
||||||
struct pping_config *config)
|
struct pping_config *config)
|
||||||
{
|
{
|
||||||
@@ -914,10 +878,28 @@ static int load_attach_bpfprogs(struct bpf_object **obj,
|
|||||||
}
|
}
|
||||||
|
|
||||||
set_programs_to_load(*obj, config);
|
set_programs_to_load(*obj, config);
|
||||||
err = bpf_object__load(*obj);
|
|
||||||
if (err) {
|
// Attach ingress prog
|
||||||
fprintf(stderr, "Failed loading bpf programs in %s: %s\n",
|
if (strcmp(config->ingress_prog, "pping_xdp_ingress") == 0) {
|
||||||
config->object_path, get_libbpf_strerror(err));
|
/* xdp_attach() loads 'obj' through libxdp */
|
||||||
|
err = xdp_attach(*obj, config->ingress_prog, config->ifindex,
|
||||||
|
&config->xdp_prog);
|
||||||
|
} else {
|
||||||
|
err = bpf_object__load(*obj);
|
||||||
|
if (err) {
|
||||||
|
fprintf(stderr, "Failed loading bpf programs in %s: %s\n",
|
||||||
|
config->object_path, get_libbpf_strerror(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
err = tc_attach(*obj, config->ifindex, BPF_TC_INGRESS,
|
||||||
|
config->ingress_prog,
|
||||||
|
&config->tc_ingress_opts, NULL);
|
||||||
|
config->ingress_prog_id = err;
|
||||||
|
}
|
||||||
|
if (err < 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Failed attaching ingress BPF program on interface %s: %s\n",
|
||||||
|
config->ifname, get_libbpf_strerror(err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -931,37 +913,24 @@ static int load_attach_bpfprogs(struct bpf_object **obj,
|
|||||||
"Failed attaching egress BPF program on interface %s: %s\n",
|
"Failed attaching egress BPF program on interface %s: %s\n",
|
||||||
config->ifname,
|
config->ifname,
|
||||||
get_libbpf_strerror(config->egress_prog_id));
|
get_libbpf_strerror(config->egress_prog_id));
|
||||||
return config->egress_prog_id;
|
err = config->egress_prog_id;
|
||||||
|
goto egress_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach ingress prog
|
|
||||||
if (strcmp(config->ingress_prog, "pping_xdp_ingress") == 0)
|
|
||||||
config->ingress_prog_id =
|
|
||||||
xdp_attach(*obj, config->ingress_prog, config->ifindex,
|
|
||||||
config->xdp_flags);
|
|
||||||
else
|
|
||||||
config->ingress_prog_id =
|
|
||||||
tc_attach(*obj, config->ifindex, BPF_TC_INGRESS,
|
|
||||||
config->ingress_prog,
|
|
||||||
&config->tc_ingress_opts, NULL);
|
|
||||||
if (config->ingress_prog_id < 0) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"Failed attaching ingress BPF program on interface %s: %s\n",
|
|
||||||
config->ifname, get_libbpf_strerror(err));
|
|
||||||
err = config->ingress_prog_id;
|
|
||||||
if (strcmp(config->ingress_prog, "pping_xdp_ingress") == 0)
|
|
||||||
print_xdp_error_hints(stderr, err);
|
|
||||||
goto ingress_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ingress_err:
|
egress_err:
|
||||||
detach_err =
|
if (config->xdp_prog) {
|
||||||
tc_detach(config->ifindex, BPF_TC_EGRESS,
|
detach_err = xdp_detach(config->xdp_prog, config->ifindex);
|
||||||
&config->tc_egress_opts, config->created_tc_hook);
|
config->xdp_prog = NULL;
|
||||||
|
} else {
|
||||||
|
detach_err =
|
||||||
|
tc_detach(config->ifindex, BPF_TC_INGRESS,
|
||||||
|
&config->tc_ingress_opts, config->created_tc_hook);
|
||||||
|
}
|
||||||
if (detach_err)
|
if (detach_err)
|
||||||
fprintf(stderr, "Failed detaching tc program from %s: %s\n",
|
fprintf(stderr, "Failed detaching ingress program from %s: %s\n",
|
||||||
config->ifname, get_libbpf_strerror(detach_err));
|
config->ifname, get_libbpf_strerror(detach_err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -1042,7 +1011,6 @@ int main(int argc, char *argv[])
|
|||||||
.packet_map = "packet_ts",
|
.packet_map = "packet_ts",
|
||||||
.flow_map = "flow_state",
|
.flow_map = "flow_state",
|
||||||
.event_map = "events",
|
.event_map = "events",
|
||||||
.xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST,
|
|
||||||
.tc_ingress_opts = tc_ingress_opts,
|
.tc_ingress_opts = tc_ingress_opts,
|
||||||
.tc_egress_opts = tc_egress_opts,
|
.tc_egress_opts = tc_egress_opts,
|
||||||
.output_format = PPING_OUTPUT_STANDARD,
|
.output_format = PPING_OUTPUT_STANDARD,
|
||||||
@@ -1154,9 +1122,8 @@ cleanup_perf_buffer:
|
|||||||
perf_buffer__free(pb);
|
perf_buffer__free(pb);
|
||||||
|
|
||||||
cleanup_attached_progs:
|
cleanup_attached_progs:
|
||||||
if (strcmp(config.ingress_prog, "pping_xdp_ingress") == 0)
|
if (config.xdp_prog)
|
||||||
detach_err = xdp_detach(config.ifindex, config.xdp_flags,
|
detach_err = xdp_detach(config.xdp_prog, config.ifindex);
|
||||||
config.ingress_prog_id);
|
|
||||||
else
|
else
|
||||||
detach_err = tc_detach(config.ifindex, BPF_TC_INGRESS,
|
detach_err = tc_detach(config.ifindex, BPF_TC_INGRESS,
|
||||||
&config.tc_ingress_opts, false);
|
&config.tc_ingress_opts, false);
|
||||||
|
Reference in New Issue
Block a user