Commit bbaf6029 authored by Maciej Fijalkowski's avatar Maciej Fijalkowski Committed by Daniel Borkmann

samples/bpf: Convert XDP samples to libbpf usage

Some of XDP samples that are attaching the bpf program to the interface
via libbpf's bpf_set_link_xdp_fd are still using the bpf_load.c for
loading and manipulating the ebpf program and maps. Convert them to do
this through libbpf usage and remove bpf_load from the picture.

While at it remove what looks like debug leftover in
xdp_redirect_map_user.c

In xdp_redirect_cpu, change the way that the program to be loaded onto
interface is chosen - user now needs to pass the program's section name
instead of the relative number. In case of typo print out the section
names to choose from.
Signed-off-by: default avatarMaciej Fijalkowski <maciej.fijalkowski@intel.com>
Reviewed-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Acked-by: default avatarJesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
parent 7313798b
...@@ -87,18 +87,18 @@ test_cgrp2_sock2-objs := bpf_load.o test_cgrp2_sock2.o ...@@ -87,18 +87,18 @@ test_cgrp2_sock2-objs := bpf_load.o test_cgrp2_sock2.o
xdp1-objs := xdp1_user.o xdp1-objs := xdp1_user.o
# reuse xdp1 source intentionally # reuse xdp1 source intentionally
xdp2-objs := xdp1_user.o xdp2-objs := xdp1_user.o
xdp_router_ipv4-objs := bpf_load.o xdp_router_ipv4_user.o xdp_router_ipv4-objs := xdp_router_ipv4_user.o
test_current_task_under_cgroup-objs := bpf_load.o $(CGROUP_HELPERS) \ test_current_task_under_cgroup-objs := bpf_load.o $(CGROUP_HELPERS) \
test_current_task_under_cgroup_user.o test_current_task_under_cgroup_user.o
trace_event-objs := bpf_load.o trace_event_user.o $(TRACE_HELPERS) trace_event-objs := bpf_load.o trace_event_user.o $(TRACE_HELPERS)
sampleip-objs := bpf_load.o sampleip_user.o $(TRACE_HELPERS) sampleip-objs := bpf_load.o sampleip_user.o $(TRACE_HELPERS)
tc_l2_redirect-objs := bpf_load.o tc_l2_redirect_user.o tc_l2_redirect-objs := bpf_load.o tc_l2_redirect_user.o
lwt_len_hist-objs := bpf_load.o lwt_len_hist_user.o lwt_len_hist-objs := bpf_load.o lwt_len_hist_user.o
xdp_tx_iptunnel-objs := bpf_load.o xdp_tx_iptunnel_user.o xdp_tx_iptunnel-objs := xdp_tx_iptunnel_user.o
test_map_in_map-objs := bpf_load.o test_map_in_map_user.o test_map_in_map-objs := bpf_load.o test_map_in_map_user.o
per_socket_stats_example-objs := cookie_uid_helper_example.o per_socket_stats_example-objs := cookie_uid_helper_example.o
xdp_redirect-objs := bpf_load.o xdp_redirect_user.o xdp_redirect-objs := xdp_redirect_user.o
xdp_redirect_map-objs := bpf_load.o xdp_redirect_map_user.o xdp_redirect_map-objs := xdp_redirect_map_user.o
xdp_redirect_cpu-objs := bpf_load.o xdp_redirect_cpu_user.o xdp_redirect_cpu-objs := bpf_load.o xdp_redirect_cpu_user.o
xdp_monitor-objs := bpf_load.o xdp_monitor_user.o xdp_monitor-objs := bpf_load.o xdp_monitor_user.o
xdp_rxq_info-objs := xdp_rxq_info_user.o xdp_rxq_info-objs := xdp_rxq_info_user.o
......
...@@ -24,12 +24,8 @@ static const char *__doc__ = ...@@ -24,12 +24,8 @@ static const char *__doc__ =
/* How many xdp_progs are defined in _kern.c */ /* How many xdp_progs are defined in _kern.c */
#define MAX_PROG 6 #define MAX_PROG 6
/* Wanted to get rid of bpf_load.h and fake-"libbpf.h" (and instead
* use bpf/libbpf.h), but cannot as (currently) needed for XDP
* attaching to a device via bpf_set_link_xdp_fd()
*/
#include <bpf/bpf.h> #include <bpf/bpf.h>
#include "bpf_load.h" #include "bpf/libbpf.h"
#include "bpf_util.h" #include "bpf_util.h"
...@@ -38,6 +34,15 @@ static char ifname_buf[IF_NAMESIZE]; ...@@ -38,6 +34,15 @@ static char ifname_buf[IF_NAMESIZE];
static char *ifname; static char *ifname;
static __u32 xdp_flags; static __u32 xdp_flags;
static int cpu_map_fd;
static int rx_cnt_map_fd;
static int redirect_err_cnt_map_fd;
static int cpumap_enqueue_cnt_map_fd;
static int cpumap_kthread_cnt_map_fd;
static int cpus_available_map_fd;
static int cpus_count_map_fd;
static int cpus_iterator_map_fd;
static int exception_cnt_map_fd;
/* Exit return codes */ /* Exit return codes */
#define EXIT_OK 0 #define EXIT_OK 0
...@@ -52,7 +57,7 @@ static const struct option long_options[] = { ...@@ -52,7 +57,7 @@ static const struct option long_options[] = {
{"dev", required_argument, NULL, 'd' }, {"dev", required_argument, NULL, 'd' },
{"skb-mode", no_argument, NULL, 'S' }, {"skb-mode", no_argument, NULL, 'S' },
{"sec", required_argument, NULL, 's' }, {"sec", required_argument, NULL, 's' },
{"prognum", required_argument, NULL, 'p' }, {"progname", required_argument, NULL, 'p' },
{"qsize", required_argument, NULL, 'q' }, {"qsize", required_argument, NULL, 'q' },
{"cpu", required_argument, NULL, 'c' }, {"cpu", required_argument, NULL, 'c' },
{"stress-mode", no_argument, NULL, 'x' }, {"stress-mode", no_argument, NULL, 'x' },
...@@ -70,7 +75,17 @@ static void int_exit(int sig) ...@@ -70,7 +75,17 @@ static void int_exit(int sig)
exit(EXIT_OK); exit(EXIT_OK);
} }
static void usage(char *argv[]) static void print_avail_progs(struct bpf_object *obj)
{
struct bpf_program *pos;
bpf_object__for_each_program(pos, obj) {
if (bpf_program__is_xdp(pos))
printf(" %s\n", bpf_program__title(pos, false));
}
}
static void usage(char *argv[], struct bpf_object *obj)
{ {
int i; int i;
...@@ -88,6 +103,8 @@ static void usage(char *argv[]) ...@@ -88,6 +103,8 @@ static void usage(char *argv[])
long_options[i].val); long_options[i].val);
printf("\n"); printf("\n");
} }
printf("\n Programs to be used for --progname:\n");
print_avail_progs(obj);
printf("\n"); printf("\n");
} }
...@@ -262,7 +279,7 @@ static __u64 calc_errs_pps(struct datarec *r, ...@@ -262,7 +279,7 @@ static __u64 calc_errs_pps(struct datarec *r,
static void stats_print(struct stats_record *stats_rec, static void stats_print(struct stats_record *stats_rec,
struct stats_record *stats_prev, struct stats_record *stats_prev,
int prog_num) char *prog_name)
{ {
unsigned int nr_cpus = bpf_num_possible_cpus(); unsigned int nr_cpus = bpf_num_possible_cpus();
double pps = 0, drop = 0, err = 0; double pps = 0, drop = 0, err = 0;
...@@ -272,7 +289,7 @@ static void stats_print(struct stats_record *stats_rec, ...@@ -272,7 +289,7 @@ static void stats_print(struct stats_record *stats_rec,
int i; int i;
/* Header */ /* Header */
printf("Running XDP/eBPF prog_num:%d\n", prog_num); printf("Running XDP/eBPF prog_name:%s\n", prog_name);
printf("%-15s %-7s %-14s %-11s %-9s\n", printf("%-15s %-7s %-14s %-11s %-9s\n",
"XDP-cpumap", "CPU:to", "pps", "drop-pps", "extra-info"); "XDP-cpumap", "CPU:to", "pps", "drop-pps", "extra-info");
...@@ -423,20 +440,20 @@ static void stats_collect(struct stats_record *rec) ...@@ -423,20 +440,20 @@ static void stats_collect(struct stats_record *rec)
{ {
int fd, i; int fd, i;
fd = map_fd[1]; /* map: rx_cnt */ fd = rx_cnt_map_fd;
map_collect_percpu(fd, 0, &rec->rx_cnt); map_collect_percpu(fd, 0, &rec->rx_cnt);
fd = map_fd[2]; /* map: redirect_err_cnt */ fd = redirect_err_cnt_map_fd;
map_collect_percpu(fd, 1, &rec->redir_err); map_collect_percpu(fd, 1, &rec->redir_err);
fd = map_fd[3]; /* map: cpumap_enqueue_cnt */ fd = cpumap_enqueue_cnt_map_fd;
for (i = 0; i < MAX_CPUS; i++) for (i = 0; i < MAX_CPUS; i++)
map_collect_percpu(fd, i, &rec->enq[i]); map_collect_percpu(fd, i, &rec->enq[i]);
fd = map_fd[4]; /* map: cpumap_kthread_cnt */ fd = cpumap_kthread_cnt_map_fd;
map_collect_percpu(fd, 0, &rec->kthread); map_collect_percpu(fd, 0, &rec->kthread);
fd = map_fd[8]; /* map: exception_cnt */ fd = exception_cnt_map_fd;
map_collect_percpu(fd, 0, &rec->exception); map_collect_percpu(fd, 0, &rec->exception);
} }
...@@ -461,7 +478,7 @@ static int create_cpu_entry(__u32 cpu, __u32 queue_size, ...@@ -461,7 +478,7 @@ static int create_cpu_entry(__u32 cpu, __u32 queue_size,
/* Add a CPU entry to cpumap, as this allocate a cpu entry in /* Add a CPU entry to cpumap, as this allocate a cpu entry in
* the kernel for the cpu. * the kernel for the cpu.
*/ */
ret = bpf_map_update_elem(map_fd[0], &cpu, &queue_size, 0); ret = bpf_map_update_elem(cpu_map_fd, &cpu, &queue_size, 0);
if (ret) { if (ret) {
fprintf(stderr, "Create CPU entry failed (err:%d)\n", ret); fprintf(stderr, "Create CPU entry failed (err:%d)\n", ret);
exit(EXIT_FAIL_BPF); exit(EXIT_FAIL_BPF);
...@@ -470,23 +487,22 @@ static int create_cpu_entry(__u32 cpu, __u32 queue_size, ...@@ -470,23 +487,22 @@ static int create_cpu_entry(__u32 cpu, __u32 queue_size,
/* Inform bpf_prog's that a new CPU is available to select /* Inform bpf_prog's that a new CPU is available to select
* from via some control maps. * from via some control maps.
*/ */
/* map_fd[5] = cpus_available */ ret = bpf_map_update_elem(cpus_available_map_fd, &avail_idx, &cpu, 0);
ret = bpf_map_update_elem(map_fd[5], &avail_idx, &cpu, 0);
if (ret) { if (ret) {
fprintf(stderr, "Add to avail CPUs failed\n"); fprintf(stderr, "Add to avail CPUs failed\n");
exit(EXIT_FAIL_BPF); exit(EXIT_FAIL_BPF);
} }
/* When not replacing/updating existing entry, bump the count */ /* When not replacing/updating existing entry, bump the count */
/* map_fd[6] = cpus_count */ ret = bpf_map_lookup_elem(cpus_count_map_fd, &key, &curr_cpus_count);
ret = bpf_map_lookup_elem(map_fd[6], &key, &curr_cpus_count);
if (ret) { if (ret) {
fprintf(stderr, "Failed reading curr cpus_count\n"); fprintf(stderr, "Failed reading curr cpus_count\n");
exit(EXIT_FAIL_BPF); exit(EXIT_FAIL_BPF);
} }
if (new) { if (new) {
curr_cpus_count++; curr_cpus_count++;
ret = bpf_map_update_elem(map_fd[6], &key, &curr_cpus_count, 0); ret = bpf_map_update_elem(cpus_count_map_fd, &key,
&curr_cpus_count, 0);
if (ret) { if (ret) {
fprintf(stderr, "Failed write curr cpus_count\n"); fprintf(stderr, "Failed write curr cpus_count\n");
exit(EXIT_FAIL_BPF); exit(EXIT_FAIL_BPF);
...@@ -509,8 +525,8 @@ static void mark_cpus_unavailable(void) ...@@ -509,8 +525,8 @@ static void mark_cpus_unavailable(void)
int ret, i; int ret, i;
for (i = 0; i < MAX_CPUS; i++) { for (i = 0; i < MAX_CPUS; i++) {
/* map_fd[5] = cpus_available */ ret = bpf_map_update_elem(cpus_available_map_fd, &i,
ret = bpf_map_update_elem(map_fd[5], &i, &invalid_cpu, 0); &invalid_cpu, 0);
if (ret) { if (ret) {
fprintf(stderr, "Failed marking CPU unavailable\n"); fprintf(stderr, "Failed marking CPU unavailable\n");
exit(EXIT_FAIL_BPF); exit(EXIT_FAIL_BPF);
...@@ -530,7 +546,7 @@ static void stress_cpumap(void) ...@@ -530,7 +546,7 @@ static void stress_cpumap(void)
create_cpu_entry(1, 16000, 0, false); create_cpu_entry(1, 16000, 0, false);
} }
static void stats_poll(int interval, bool use_separators, int prog_num, static void stats_poll(int interval, bool use_separators, char *prog_name,
bool stress_mode) bool stress_mode)
{ {
struct stats_record *record, *prev; struct stats_record *record, *prev;
...@@ -546,7 +562,7 @@ static void stats_poll(int interval, bool use_separators, int prog_num, ...@@ -546,7 +562,7 @@ static void stats_poll(int interval, bool use_separators, int prog_num,
while (1) { while (1) {
swap(&prev, &record); swap(&prev, &record);
stats_collect(record); stats_collect(record);
stats_print(record, prev, prog_num); stats_print(record, prev, prog_name);
sleep(interval); sleep(interval);
if (stress_mode) if (stress_mode)
stress_cpumap(); stress_cpumap();
...@@ -556,17 +572,51 @@ static void stats_poll(int interval, bool use_separators, int prog_num, ...@@ -556,17 +572,51 @@ static void stats_poll(int interval, bool use_separators, int prog_num,
free_stats_record(prev); free_stats_record(prev);
} }
static int init_map_fds(struct bpf_object *obj)
{
cpu_map_fd = bpf_object__find_map_fd_by_name(obj, "cpu_map");
rx_cnt_map_fd = bpf_object__find_map_fd_by_name(obj, "rx_cnt");
redirect_err_cnt_map_fd =
bpf_object__find_map_fd_by_name(obj, "redirect_err_cnt");
cpumap_enqueue_cnt_map_fd =
bpf_object__find_map_fd_by_name(obj, "cpumap_enqueue_cnt");
cpumap_kthread_cnt_map_fd =
bpf_object__find_map_fd_by_name(obj, "cpumap_kthread_cnt");
cpus_available_map_fd =
bpf_object__find_map_fd_by_name(obj, "cpus_available");
cpus_count_map_fd = bpf_object__find_map_fd_by_name(obj, "cpus_count");
cpus_iterator_map_fd =
bpf_object__find_map_fd_by_name(obj, "cpus_iterator");
exception_cnt_map_fd =
bpf_object__find_map_fd_by_name(obj, "exception_cnt");
if (cpu_map_fd < 0 || rx_cnt_map_fd < 0 ||
redirect_err_cnt_map_fd < 0 || cpumap_enqueue_cnt_map_fd < 0 ||
cpumap_kthread_cnt_map_fd < 0 || cpus_available_map_fd < 0 ||
cpus_count_map_fd < 0 || cpus_iterator_map_fd < 0 ||
exception_cnt_map_fd < 0)
return -ENOENT;
return 0;
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY}; struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY};
char *prog_name = "xdp_cpu_map5_lb_hash_ip_pairs";
struct bpf_prog_load_attr prog_load_attr = {
.prog_type = BPF_PROG_TYPE_UNSPEC,
};
bool use_separators = true; bool use_separators = true;
bool stress_mode = false; bool stress_mode = false;
struct bpf_program *prog;
struct bpf_object *obj;
char filename[256]; char filename[256];
int added_cpus = 0; int added_cpus = 0;
int longindex = 0; int longindex = 0;
int interval = 2; int interval = 2;
int prog_num = 5;
int add_cpu = -1; int add_cpu = -1;
int prog_fd;
__u32 qsize; __u32 qsize;
int opt; int opt;
...@@ -579,22 +629,25 @@ int main(int argc, char **argv) ...@@ -579,22 +629,25 @@ int main(int argc, char **argv)
qsize = 128+64; qsize = 128+64;
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
prog_load_attr.file = filename;
if (setrlimit(RLIMIT_MEMLOCK, &r)) { if (setrlimit(RLIMIT_MEMLOCK, &r)) {
perror("setrlimit(RLIMIT_MEMLOCK)"); perror("setrlimit(RLIMIT_MEMLOCK)");
return 1; return 1;
} }
if (load_bpf_file(filename)) { if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
fprintf(stderr, "ERR in load_bpf_file(): %s", bpf_log_buf);
return EXIT_FAIL; return EXIT_FAIL;
}
if (!prog_fd[0]) { if (prog_fd < 0) {
fprintf(stderr, "ERR: load_bpf_file: %s\n", strerror(errno)); fprintf(stderr, "ERR: bpf_prog_load_xattr: %s\n",
strerror(errno));
return EXIT_FAIL;
}
if (init_map_fds(obj) < 0) {
fprintf(stderr, "bpf_object__find_map_fd_by_name failed\n");
return EXIT_FAIL; return EXIT_FAIL;
} }
mark_cpus_unavailable(); mark_cpus_unavailable();
/* Parse commands line args */ /* Parse commands line args */
...@@ -630,13 +683,7 @@ int main(int argc, char **argv) ...@@ -630,13 +683,7 @@ int main(int argc, char **argv)
break; break;
case 'p': case 'p':
/* Selecting eBPF prog to load */ /* Selecting eBPF prog to load */
prog_num = atoi(optarg); prog_name = optarg;
if (prog_num < 0 || prog_num >= MAX_PROG) {
fprintf(stderr,
"--prognum too large err(%d):%s\n",
errno, strerror(errno));
goto error;
}
break; break;
case 'c': case 'c':
/* Add multiple CPUs */ /* Add multiple CPUs */
...@@ -656,21 +703,21 @@ int main(int argc, char **argv) ...@@ -656,21 +703,21 @@ int main(int argc, char **argv)
case 'h': case 'h':
error: error:
default: default:
usage(argv); usage(argv, obj);
return EXIT_FAIL_OPTION; return EXIT_FAIL_OPTION;
} }
} }
/* Required option */ /* Required option */
if (ifindex == -1) { if (ifindex == -1) {
fprintf(stderr, "ERR: required option --dev missing\n"); fprintf(stderr, "ERR: required option --dev missing\n");
usage(argv); usage(argv, obj);
return EXIT_FAIL_OPTION; return EXIT_FAIL_OPTION;
} }
/* Required option */ /* Required option */
if (add_cpu == -1) { if (add_cpu == -1) {
fprintf(stderr, "ERR: required option --cpu missing\n"); fprintf(stderr, "ERR: required option --cpu missing\n");
fprintf(stderr, " Specify multiple --cpu option to add more\n"); fprintf(stderr, " Specify multiple --cpu option to add more\n");
usage(argv); usage(argv, obj);
return EXIT_FAIL_OPTION; return EXIT_FAIL_OPTION;
} }
...@@ -678,11 +725,23 @@ int main(int argc, char **argv) ...@@ -678,11 +725,23 @@ int main(int argc, char **argv)
signal(SIGINT, int_exit); signal(SIGINT, int_exit);
signal(SIGTERM, int_exit); signal(SIGTERM, int_exit);
if (bpf_set_link_xdp_fd(ifindex, prog_fd[prog_num], xdp_flags) < 0) { prog = bpf_object__find_program_by_title(obj, prog_name);
if (!prog) {
fprintf(stderr, "bpf_object__find_program_by_title failed\n");
return EXIT_FAIL;
}
prog_fd = bpf_program__fd(prog);
if (prog_fd < 0) {
fprintf(stderr, "bpf_program__fd failed\n");
return EXIT_FAIL;
}
if (bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags) < 0) {
fprintf(stderr, "link set xdp fd failed\n"); fprintf(stderr, "link set xdp fd failed\n");
return EXIT_FAIL_XDP; return EXIT_FAIL_XDP;
} }
stats_poll(interval, use_separators, prog_num, stress_mode); stats_poll(interval, use_separators, prog_name, stress_mode);
return EXIT_OK; return EXIT_OK;
} }
...@@ -22,15 +22,16 @@ ...@@ -22,15 +22,16 @@
#include <libgen.h> #include <libgen.h>
#include <sys/resource.h> #include <sys/resource.h>
#include "bpf_load.h"
#include "bpf_util.h" #include "bpf_util.h"
#include <bpf/bpf.h> #include <bpf/bpf.h>
#include "bpf/libbpf.h"
static int ifindex_in; static int ifindex_in;
static int ifindex_out; static int ifindex_out;
static bool ifindex_out_xdp_dummy_attached = true; static bool ifindex_out_xdp_dummy_attached = true;
static __u32 xdp_flags; static __u32 xdp_flags;
static int rxcnt_map_fd;
static void int_exit(int sig) static void int_exit(int sig)
{ {
...@@ -53,7 +54,7 @@ static void poll_stats(int interval, int ifindex) ...@@ -53,7 +54,7 @@ static void poll_stats(int interval, int ifindex)
int i; int i;
sleep(interval); sleep(interval);
assert(bpf_map_lookup_elem(map_fd[1], &key, values) == 0); assert(bpf_map_lookup_elem(rxcnt_map_fd, &key, values) == 0);
for (i = 0; i < nr_cpus; i++) for (i = 0; i < nr_cpus; i++)
sum += (values[i] - prev[i]); sum += (values[i] - prev[i]);
if (sum) if (sum)
...@@ -76,9 +77,16 @@ static void usage(const char *prog) ...@@ -76,9 +77,16 @@ static void usage(const char *prog)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
struct bpf_prog_load_attr prog_load_attr = {
.prog_type = BPF_PROG_TYPE_XDP,
};
struct bpf_program *prog, *dummy_prog;
int prog_fd, dummy_prog_fd;
const char *optstr = "SN"; const char *optstr = "SN";
char filename[256]; struct bpf_object *obj;
int ret, opt, key = 0; int ret, opt, key = 0;
char filename[256];
int tx_port_map_fd;
while ((opt = getopt(argc, argv, optstr)) != -1) { while ((opt = getopt(argc, argv, optstr)) != -1) {
switch (opt) { switch (opt) {
...@@ -109,24 +117,40 @@ int main(int argc, char **argv) ...@@ -109,24 +117,40 @@ int main(int argc, char **argv)
printf("input: %d output: %d\n", ifindex_in, ifindex_out); printf("input: %d output: %d\n", ifindex_in, ifindex_out);
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
prog_load_attr.file = filename;
if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
return 1;
if (load_bpf_file(filename)) { prog = bpf_program__next(NULL, obj);
printf("%s", bpf_log_buf); dummy_prog = bpf_program__next(prog, obj);
if (!prog || !dummy_prog) {
printf("finding a prog in obj file failed\n");
return 1;
}
/* bpf_prog_load_xattr gives us the pointer to first prog's fd,
* so we're missing only the fd for dummy prog
*/
dummy_prog_fd = bpf_program__fd(dummy_prog);
if (prog_fd < 0 || dummy_prog_fd < 0) {
printf("bpf_prog_load_xattr: %s\n", strerror(errno));
return 1; return 1;
} }
if (!prog_fd[0]) { tx_port_map_fd = bpf_object__find_map_fd_by_name(obj, "tx_port");
printf("load_bpf_file: %s\n", strerror(errno)); rxcnt_map_fd = bpf_object__find_map_fd_by_name(obj, "rxcnt");
if (tx_port_map_fd < 0 || rxcnt_map_fd < 0) {
printf("bpf_object__find_map_fd_by_name failed\n");
return 1; return 1;
} }
if (bpf_set_link_xdp_fd(ifindex_in, prog_fd[0], xdp_flags) < 0) { if (bpf_set_link_xdp_fd(ifindex_in, prog_fd, xdp_flags) < 0) {
printf("ERROR: link set xdp fd failed on %d\n", ifindex_in); printf("ERROR: link set xdp fd failed on %d\n", ifindex_in);
return 1; return 1;
} }
/* Loading dummy XDP prog on out-device */ /* Loading dummy XDP prog on out-device */
if (bpf_set_link_xdp_fd(ifindex_out, prog_fd[1], if (bpf_set_link_xdp_fd(ifindex_out, dummy_prog_fd,
(xdp_flags | XDP_FLAGS_UPDATE_IF_NOEXIST)) < 0) { (xdp_flags | XDP_FLAGS_UPDATE_IF_NOEXIST)) < 0) {
printf("WARN: link set xdp fd failed on %d\n", ifindex_out); printf("WARN: link set xdp fd failed on %d\n", ifindex_out);
ifindex_out_xdp_dummy_attached = false; ifindex_out_xdp_dummy_attached = false;
...@@ -135,11 +159,8 @@ int main(int argc, char **argv) ...@@ -135,11 +159,8 @@ int main(int argc, char **argv)
signal(SIGINT, int_exit); signal(SIGINT, int_exit);
signal(SIGTERM, int_exit); signal(SIGTERM, int_exit);
printf("map[0] (vports) = %i, map[1] (map) = %i, map[2] (count) = %i\n",
map_fd[0], map_fd[1], map_fd[2]);
/* populate virtual to physical port map */ /* populate virtual to physical port map */
ret = bpf_map_update_elem(map_fd[0], &key, &ifindex_out, 0); ret = bpf_map_update_elem(tx_port_map_fd, &key, &ifindex_out, 0);
if (ret) { if (ret) {
perror("bpf_update_elem"); perror("bpf_update_elem");
goto out; goto out;
......
...@@ -22,15 +22,16 @@ ...@@ -22,15 +22,16 @@
#include <libgen.h> #include <libgen.h>
#include <sys/resource.h> #include <sys/resource.h>
#include "bpf_load.h"
#include "bpf_util.h" #include "bpf_util.h"
#include <bpf/bpf.h> #include <bpf/bpf.h>
#include "bpf/libbpf.h"
static int ifindex_in; static int ifindex_in;
static int ifindex_out; static int ifindex_out;
static bool ifindex_out_xdp_dummy_attached = true; static bool ifindex_out_xdp_dummy_attached = true;
static __u32 xdp_flags; static __u32 xdp_flags;
static int rxcnt_map_fd;
static void int_exit(int sig) static void int_exit(int sig)
{ {
...@@ -53,7 +54,7 @@ static void poll_stats(int interval, int ifindex) ...@@ -53,7 +54,7 @@ static void poll_stats(int interval, int ifindex)
int i; int i;
sleep(interval); sleep(interval);
assert(bpf_map_lookup_elem(map_fd[1], &key, values) == 0); assert(bpf_map_lookup_elem(rxcnt_map_fd, &key, values) == 0);
for (i = 0; i < nr_cpus; i++) for (i = 0; i < nr_cpus; i++)
sum += (values[i] - prev[i]); sum += (values[i] - prev[i]);
if (sum) if (sum)
...@@ -77,9 +78,16 @@ static void usage(const char *prog) ...@@ -77,9 +78,16 @@ static void usage(const char *prog)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
struct bpf_prog_load_attr prog_load_attr = {
.prog_type = BPF_PROG_TYPE_XDP,
};
struct bpf_program *prog, *dummy_prog;
int prog_fd, tx_port_map_fd, opt;
const char *optstr = "SN"; const char *optstr = "SN";
struct bpf_object *obj;
char filename[256]; char filename[256];
int ret, opt, key = 0; int dummy_prog_fd;
int ret, key = 0;
while ((opt = getopt(argc, argv, optstr)) != -1) { while ((opt = getopt(argc, argv, optstr)) != -1) {
switch (opt) { switch (opt) {
...@@ -110,24 +118,40 @@ int main(int argc, char **argv) ...@@ -110,24 +118,40 @@ int main(int argc, char **argv)
printf("input: %d output: %d\n", ifindex_in, ifindex_out); printf("input: %d output: %d\n", ifindex_in, ifindex_out);
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
prog_load_attr.file = filename;
if (load_bpf_file(filename)) { if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
printf("%s", bpf_log_buf); return 1;
prog = bpf_program__next(NULL, obj);
dummy_prog = bpf_program__next(prog, obj);
if (!prog || !dummy_prog) {
printf("finding a prog in obj file failed\n");
return 1;
}
/* bpf_prog_load_xattr gives us the pointer to first prog's fd,
* so we're missing only the fd for dummy prog
*/
dummy_prog_fd = bpf_program__fd(dummy_prog);
if (prog_fd < 0 || dummy_prog_fd < 0) {
printf("bpf_prog_load_xattr: %s\n", strerror(errno));
return 1; return 1;
} }
if (!prog_fd[0]) { tx_port_map_fd = bpf_object__find_map_fd_by_name(obj, "tx_port");
printf("load_bpf_file: %s\n", strerror(errno)); rxcnt_map_fd = bpf_object__find_map_fd_by_name(obj, "rxcnt");
if (tx_port_map_fd < 0 || rxcnt_map_fd < 0) {
printf("bpf_object__find_map_fd_by_name failed\n");
return 1; return 1;
} }
if (bpf_set_link_xdp_fd(ifindex_in, prog_fd[0], xdp_flags) < 0) { if (bpf_set_link_xdp_fd(ifindex_in, prog_fd, xdp_flags) < 0) {
printf("ERROR: link set xdp fd failed on %d\n", ifindex_in); printf("ERROR: link set xdp fd failed on %d\n", ifindex_in);
return 1; return 1;
} }
/* Loading dummy XDP prog on out-device */ /* Loading dummy XDP prog on out-device */
if (bpf_set_link_xdp_fd(ifindex_out, prog_fd[1], if (bpf_set_link_xdp_fd(ifindex_out, dummy_prog_fd,
(xdp_flags | XDP_FLAGS_UPDATE_IF_NOEXIST)) < 0) { (xdp_flags | XDP_FLAGS_UPDATE_IF_NOEXIST)) < 0) {
printf("WARN: link set xdp fd failed on %d\n", ifindex_out); printf("WARN: link set xdp fd failed on %d\n", ifindex_out);
ifindex_out_xdp_dummy_attached = false; ifindex_out_xdp_dummy_attached = false;
...@@ -137,7 +161,7 @@ int main(int argc, char **argv) ...@@ -137,7 +161,7 @@ int main(int argc, char **argv)
signal(SIGTERM, int_exit); signal(SIGTERM, int_exit);
/* bpf redirect port */ /* bpf redirect port */
ret = bpf_map_update_elem(map_fd[0], &key, &ifindex_out, 0); ret = bpf_map_update_elem(tx_port_map_fd, &key, &ifindex_out, 0);
if (ret) { if (ret) {
perror("bpf_update_elem"); perror("bpf_update_elem");
goto out; goto out;
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <string.h> #include <string.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
#include "bpf_load.h"
#include <bpf/bpf.h> #include <bpf/bpf.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <fcntl.h> #include <fcntl.h>
...@@ -25,11 +24,17 @@ ...@@ -25,11 +24,17 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include "bpf_util.h" #include "bpf_util.h"
#include "bpf/libbpf.h"
int sock, sock_arp, flags = 0; int sock, sock_arp, flags = 0;
static int total_ifindex; static int total_ifindex;
int *ifindex_list; int *ifindex_list;
char buf[8192]; char buf[8192];
static int lpm_map_fd;
static int rxcnt_map_fd;
static int arp_table_map_fd;
static int exact_match_map_fd;
static int tx_port_map_fd;
static int get_route_table(int rtm_family); static int get_route_table(int rtm_family);
static void int_exit(int sig) static void int_exit(int sig)
...@@ -186,7 +191,8 @@ static void read_route(struct nlmsghdr *nh, int nll) ...@@ -186,7 +191,8 @@ static void read_route(struct nlmsghdr *nh, int nll)
bpf_set_link_xdp_fd(ifindex_list[i], -1, flags); bpf_set_link_xdp_fd(ifindex_list[i], -1, flags);
exit(0); exit(0);
} }
assert(bpf_map_update_elem(map_fd[4], &route.iface, &route.iface, 0) == 0); assert(bpf_map_update_elem(tx_port_map_fd,
&route.iface, &route.iface, 0) == 0);
if (rtm_family == AF_INET) { if (rtm_family == AF_INET) {
struct trie_value { struct trie_value {
__u8 prefix[4]; __u8 prefix[4];
...@@ -207,11 +213,16 @@ static void read_route(struct nlmsghdr *nh, int nll) ...@@ -207,11 +213,16 @@ static void read_route(struct nlmsghdr *nh, int nll)
direct_entry.arp.dst = 0; direct_entry.arp.dst = 0;
if (route.dst_len == 32) { if (route.dst_len == 32) {
if (nh->nlmsg_type == RTM_DELROUTE) { if (nh->nlmsg_type == RTM_DELROUTE) {
assert(bpf_map_delete_elem(map_fd[3], &route.dst) == 0); assert(bpf_map_delete_elem(exact_match_map_fd,
&route.dst) == 0);
} else { } else {
if (bpf_map_lookup_elem(map_fd[2], &route.dst, &direct_entry.arp.mac) == 0) if (bpf_map_lookup_elem(arp_table_map_fd,
&route.dst,
&direct_entry.arp.mac) == 0)
direct_entry.arp.dst = route.dst; direct_entry.arp.dst = route.dst;
assert(bpf_map_update_elem(map_fd[3], &route.dst, &direct_entry, 0) == 0); assert(bpf_map_update_elem(exact_match_map_fd,
&route.dst,
&direct_entry, 0) == 0);
} }
} }
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
...@@ -225,7 +236,7 @@ static void read_route(struct nlmsghdr *nh, int nll) ...@@ -225,7 +236,7 @@ static void read_route(struct nlmsghdr *nh, int nll)
route.gw, route.dst_len, route.gw, route.dst_len,
route.metric, route.metric,
route.iface_name); route.iface_name);
if (bpf_map_lookup_elem(map_fd[0], prefix_key, if (bpf_map_lookup_elem(lpm_map_fd, prefix_key,
prefix_value) < 0) { prefix_value) < 0) {
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
prefix_value->prefix[i] = prefix_key->data[i]; prefix_value->prefix[i] = prefix_key->data[i];
...@@ -234,7 +245,7 @@ static void read_route(struct nlmsghdr *nh, int nll) ...@@ -234,7 +245,7 @@ static void read_route(struct nlmsghdr *nh, int nll)
prefix_value->gw = route.gw; prefix_value->gw = route.gw;
prefix_value->metric = route.metric; prefix_value->metric = route.metric;
assert(bpf_map_update_elem(map_fd[0], assert(bpf_map_update_elem(lpm_map_fd,
prefix_key, prefix_key,
prefix_value, 0 prefix_value, 0
) == 0); ) == 0);
...@@ -247,7 +258,7 @@ static void read_route(struct nlmsghdr *nh, int nll) ...@@ -247,7 +258,7 @@ static void read_route(struct nlmsghdr *nh, int nll)
prefix_key->data[2], prefix_key->data[2],
prefix_key->data[3], prefix_key->data[3],
prefix_key->prefixlen); prefix_key->prefixlen);
assert(bpf_map_delete_elem(map_fd[0], assert(bpf_map_delete_elem(lpm_map_fd,
prefix_key prefix_key
) == 0); ) == 0);
/* Rereading the route table to check if /* Rereading the route table to check if
...@@ -275,8 +286,7 @@ static void read_route(struct nlmsghdr *nh, int nll) ...@@ -275,8 +286,7 @@ static void read_route(struct nlmsghdr *nh, int nll)
prefix_value->ifindex = route.iface; prefix_value->ifindex = route.iface;
prefix_value->gw = route.gw; prefix_value->gw = route.gw;
prefix_value->metric = route.metric; prefix_value->metric = route.metric;
assert(bpf_map_update_elem( assert(bpf_map_update_elem(lpm_map_fd,
map_fd[0],
prefix_key, prefix_key,
prefix_value, prefix_value,
0) == 0); 0) == 0);
...@@ -401,7 +411,8 @@ static void read_arp(struct nlmsghdr *nh, int nll) ...@@ -401,7 +411,8 @@ static void read_arp(struct nlmsghdr *nh, int nll)
arp_entry.mac = atol(mac); arp_entry.mac = atol(mac);
printf("%x\t\t%llx\n", arp_entry.dst, arp_entry.mac); printf("%x\t\t%llx\n", arp_entry.dst, arp_entry.mac);
if (ndm_family == AF_INET) { if (ndm_family == AF_INET) {
if (bpf_map_lookup_elem(map_fd[3], &arp_entry.dst, if (bpf_map_lookup_elem(exact_match_map_fd,
&arp_entry.dst,
&direct_entry) == 0) { &direct_entry) == 0) {
if (nh->nlmsg_type == RTM_DELNEIGH) { if (nh->nlmsg_type == RTM_DELNEIGH) {
direct_entry.arp.dst = 0; direct_entry.arp.dst = 0;
...@@ -410,16 +421,17 @@ static void read_arp(struct nlmsghdr *nh, int nll) ...@@ -410,16 +421,17 @@ static void read_arp(struct nlmsghdr *nh, int nll)
direct_entry.arp.dst = arp_entry.dst; direct_entry.arp.dst = arp_entry.dst;
direct_entry.arp.mac = arp_entry.mac; direct_entry.arp.mac = arp_entry.mac;
} }
assert(bpf_map_update_elem(map_fd[3], assert(bpf_map_update_elem(exact_match_map_fd,
&arp_entry.dst, &arp_entry.dst,
&direct_entry, 0 &direct_entry, 0
) == 0); ) == 0);
memset(&direct_entry, 0, sizeof(direct_entry)); memset(&direct_entry, 0, sizeof(direct_entry));
} }
if (nh->nlmsg_type == RTM_DELNEIGH) { if (nh->nlmsg_type == RTM_DELNEIGH) {
assert(bpf_map_delete_elem(map_fd[2], &arp_entry.dst) == 0); assert(bpf_map_delete_elem(arp_table_map_fd,
&arp_entry.dst) == 0);
} else if (nh->nlmsg_type == RTM_NEWNEIGH) { } else if (nh->nlmsg_type == RTM_NEWNEIGH) {
assert(bpf_map_update_elem(map_fd[2], assert(bpf_map_update_elem(arp_table_map_fd,
&arp_entry.dst, &arp_entry.dst,
&arp_entry.mac, 0 &arp_entry.mac, 0
) == 0); ) == 0);
...@@ -553,7 +565,8 @@ static int monitor_route(void) ...@@ -553,7 +565,8 @@ static int monitor_route(void)
for (key = 0; key < nr_keys; key++) { for (key = 0; key < nr_keys; key++) {
__u64 sum = 0; __u64 sum = 0;
assert(bpf_map_lookup_elem(map_fd[1], &key, values) == 0); assert(bpf_map_lookup_elem(rxcnt_map_fd,
&key, values) == 0);
for (i = 0; i < nr_cpus; i++) for (i = 0; i < nr_cpus; i++)
sum += (values[i] - prev[key][i]); sum += (values[i] - prev[key][i]);
if (sum) if (sum)
...@@ -596,11 +609,18 @@ static int monitor_route(void) ...@@ -596,11 +609,18 @@ static int monitor_route(void)
int main(int ac, char **argv) int main(int ac, char **argv)
{ {
struct bpf_prog_load_attr prog_load_attr = {
.prog_type = BPF_PROG_TYPE_XDP,
};
struct bpf_object *obj;
char filename[256]; char filename[256];
char **ifname_list; char **ifname_list;
int prog_fd;
int i = 1; int i = 1;
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
prog_load_attr.file = filename;
if (ac < 2) { if (ac < 2) {
printf("usage: %s [-S] Interface name list\n", argv[0]); printf("usage: %s [-S] Interface name list\n", argv[0]);
return 1; return 1;
...@@ -614,15 +634,28 @@ int main(int ac, char **argv) ...@@ -614,15 +634,28 @@ int main(int ac, char **argv)
total_ifindex = ac - 1; total_ifindex = ac - 1;
ifname_list = (argv + 1); ifname_list = (argv + 1);
} }
if (load_bpf_file(filename)) {
printf("%s", bpf_log_buf); if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
return 1; return 1;
}
printf("\n**************loading bpf file*********************\n\n\n"); printf("\n**************loading bpf file*********************\n\n\n");
if (!prog_fd[0]) { if (!prog_fd) {
printf("load_bpf_file: %s\n", strerror(errno)); printf("bpf_prog_load_xattr: %s\n", strerror(errno));
return 1; return 1;
} }
lpm_map_fd = bpf_object__find_map_fd_by_name(obj, "lpm_map");
rxcnt_map_fd = bpf_object__find_map_fd_by_name(obj, "rxcnt");
arp_table_map_fd = bpf_object__find_map_fd_by_name(obj, "arp_table");
exact_match_map_fd = bpf_object__find_map_fd_by_name(obj,
"exact_match");
tx_port_map_fd = bpf_object__find_map_fd_by_name(obj, "tx_port");
if (lpm_map_fd < 0 || rxcnt_map_fd < 0 || arp_table_map_fd < 0 ||
exact_match_map_fd < 0 || tx_port_map_fd < 0) {
printf("bpf_object__find_map_fd_by_name failed\n");
return 1;
}
ifindex_list = (int *)malloc(total_ifindex * sizeof(int *)); ifindex_list = (int *)malloc(total_ifindex * sizeof(int *));
for (i = 0; i < total_ifindex; i++) { for (i = 0; i < total_ifindex; i++) {
ifindex_list[i] = if_nametoindex(ifname_list[i]); ifindex_list[i] = if_nametoindex(ifname_list[i]);
...@@ -633,7 +666,7 @@ int main(int ac, char **argv) ...@@ -633,7 +666,7 @@ int main(int ac, char **argv)
} }
} }
for (i = 0; i < total_ifindex; i++) { for (i = 0; i < total_ifindex; i++) {
if (bpf_set_link_xdp_fd(ifindex_list[i], prog_fd[0], flags) < 0) { if (bpf_set_link_xdp_fd(ifindex_list[i], prog_fd, flags) < 0) {
printf("link set xdp fd failed\n"); printf("link set xdp fd failed\n");
int recovery_index = i; int recovery_index = i;
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include <netinet/ether.h> #include <netinet/ether.h>
#include <unistd.h> #include <unistd.h>
#include <time.h> #include <time.h>
#include "bpf_load.h" #include "bpf/libbpf.h"
#include <bpf/bpf.h> #include <bpf/bpf.h>
#include "bpf_util.h" #include "bpf_util.h"
#include "xdp_tx_iptunnel_common.h" #include "xdp_tx_iptunnel_common.h"
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
static int ifindex = -1; static int ifindex = -1;
static __u32 xdp_flags = 0; static __u32 xdp_flags = 0;
static int rxcnt_map_fd;
static void int_exit(int sig) static void int_exit(int sig)
{ {
...@@ -53,7 +54,8 @@ static void poll_stats(unsigned int kill_after_s) ...@@ -53,7 +54,8 @@ static void poll_stats(unsigned int kill_after_s)
for (proto = 0; proto < nr_protos; proto++) { for (proto = 0; proto < nr_protos; proto++) {
__u64 sum = 0; __u64 sum = 0;
assert(bpf_map_lookup_elem(map_fd[0], &proto, values) == 0); assert(bpf_map_lookup_elem(rxcnt_map_fd, &proto,
values) == 0);
for (i = 0; i < nr_cpus; i++) for (i = 0; i < nr_cpus; i++)
sum += (values[i] - prev[proto][i]); sum += (values[i] - prev[proto][i]);
...@@ -138,15 +140,19 @@ static int parse_ports(const char *port_str, int *min_port, int *max_port) ...@@ -138,15 +140,19 @@ static int parse_ports(const char *port_str, int *min_port, int *max_port)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct bpf_prog_load_attr prog_load_attr = {
.prog_type = BPF_PROG_TYPE_XDP,
};
struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
int min_port = 0, max_port = 0, vip2tnl_map_fd;
const char *optstr = "i:a:p:s:d:m:T:P:SNh";
unsigned char opt_flags[256] = {}; unsigned char opt_flags[256] = {};
unsigned int kill_after_s = 0; unsigned int kill_after_s = 0;
const char *optstr = "i:a:p:s:d:m:T:P:SNh";
int min_port = 0, max_port = 0;
struct iptnl_info tnl = {}; struct iptnl_info tnl = {};
struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; struct bpf_object *obj;
struct vip vip = {}; struct vip vip = {};
char filename[256]; char filename[256];
int opt; int opt, prog_fd;
int i; int i;
tnl.family = AF_UNSPEC; tnl.family = AF_UNSPEC;
...@@ -232,29 +238,36 @@ int main(int argc, char **argv) ...@@ -232,29 +238,36 @@ int main(int argc, char **argv)
} }
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
prog_load_attr.file = filename;
if (load_bpf_file(filename)) { if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
printf("%s", bpf_log_buf);
return 1; return 1;
}
if (!prog_fd[0]) { if (!prog_fd) {
printf("load_bpf_file: %s\n", strerror(errno)); printf("load_bpf_file: %s\n", strerror(errno));
return 1; return 1;
} }
rxcnt_map_fd = bpf_object__find_map_fd_by_name(obj, "rxcnt");
vip2tnl_map_fd = bpf_object__find_map_fd_by_name(obj, "vip2tnl");
if (vip2tnl_map_fd < 0 || rxcnt_map_fd < 0) {
printf("bpf_object__find_map_fd_by_name failed\n");
return 1;
}
signal(SIGINT, int_exit); signal(SIGINT, int_exit);
signal(SIGTERM, int_exit); signal(SIGTERM, int_exit);
while (min_port <= max_port) { while (min_port <= max_port) {
vip.dport = htons(min_port++); vip.dport = htons(min_port++);
if (bpf_map_update_elem(map_fd[1], &vip, &tnl, BPF_NOEXIST)) { if (bpf_map_update_elem(vip2tnl_map_fd, &vip, &tnl,
BPF_NOEXIST)) {
perror("bpf_map_update_elem(&vip2tnl)"); perror("bpf_map_update_elem(&vip2tnl)");
return 1; return 1;
} }
} }
if (bpf_set_link_xdp_fd(ifindex, prog_fd[0], xdp_flags) < 0) { if (bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags) < 0) {
printf("link set xdp fd failed\n"); printf("link set xdp fd failed\n");
return 1; return 1;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment