diff options
Diffstat (limited to 'src/xdp/common')
-rw-r--r-- | src/xdp/common/Makefile | 23 | ||||
-rw-r--r-- | src/xdp/common/README.org | 8 | ||||
-rw-r--r-- | src/xdp/common/common.mk | 103 | ||||
-rw-r--r-- | src/xdp/common/common_defines.h | 38 | ||||
-rw-r--r-- | src/xdp/common/common_libbpf.c | 161 | ||||
-rw-r--r-- | src/xdp/common/common_libbpf.h | 24 | ||||
-rw-r--r-- | src/xdp/common/common_params.c | 197 | ||||
-rw-r--r-- | src/xdp/common/common_params.h | 22 | ||||
-rw-r--r-- | src/xdp/common/common_user_bpf_xdp.c | 389 | ||||
-rw-r--r-- | src/xdp/common/common_user_bpf_xdp.h | 20 | ||||
-rw-r--r-- | src/xdp/common/parsing_helpers.h | 244 | ||||
-rw-r--r-- | src/xdp/common/rewrite_helpers.h | 144 | ||||
-rw-r--r-- | src/xdp/common/xdp_stats_kern.h | 44 | ||||
-rw-r--r-- | src/xdp/common/xdp_stats_kern_user.h | 19 |
14 files changed, 0 insertions, 1436 deletions
diff --git a/src/xdp/common/Makefile b/src/xdp/common/Makefile deleted file mode 100644 index 2502027e9..000000000 --- a/src/xdp/common/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0) -CC := gcc - -all: common_params.o common_user_bpf_xdp.o common_libbpf.o - -CFLAGS := -g -Wall - -CFLAGS += -I../include/ -# TODO: Do we need to make libbpf from this make file too? - -common_params.o: common_params.c common_params.h - $(CC) $(CFLAGS) -c -o $@ $< - -common_user_bpf_xdp.o: common_user_bpf_xdp.c common_user_bpf_xdp.h - $(CC) $(CFLAGS) -c -o $@ $< - -common_libbpf.o: common_libbpf.c common_libbpf.h - $(CC) $(CFLAGS) -c -o $@ $< - -.PHONY: clean - -clean: - rm -f *.o diff --git a/src/xdp/common/README.org b/src/xdp/common/README.org deleted file mode 100644 index 561fdbced..000000000 --- a/src/xdp/common/README.org +++ /dev/null @@ -1,8 +0,0 @@ -# -*- fill-column: 76; -*- -#+TITLE: Common files -#+OPTIONS: ^:nil - -This directory contains code that is common between the different -assignments. This reduce code duplication in each tutorial assignment, and -allow us to hideaway code that is irrelevant or have been seen/introduced in -earlier assignments. diff --git a/src/xdp/common/common.mk b/src/xdp/common/common.mk deleted file mode 100644 index ffb86a65c..000000000 --- a/src/xdp/common/common.mk +++ /dev/null @@ -1,103 +0,0 @@ -# Common Makefile parts for BPF-building with libbpf -# -------------------------------------------------- -# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) -# -# This file should be included from your Makefile like: -# COMMON_DIR = ../common/ -# include $(COMMON_DIR)/common.mk -# -# It is expected that you define the variables: -# XDP_TARGETS and USER_TARGETS -# as a space-separated list -# -LLC ?= llc -CLANG ?= clang -CC ?= gcc - -XDP_C = ${XDP_TARGETS:=.c} -XDP_OBJ = ${XDP_C:.c=.o} -USER_C := ${USER_TARGETS:=.c} -USER_OBJ := ${USER_C:.c=.o} - -# Expect this is defined by including Makefile, but define if not -COMMON_DIR ?= ../common/ - -COPY_LOADER ?= -LOADER_DIR ?= $(COMMON_DIR)/../utils - -# Extend if including Makefile already added some -COMMON_OBJS += $(COMMON_DIR)/common_params.o $(COMMON_DIR)/common_user_bpf_xdp.o - -# Create expansions for dependencies -COMMON_H := ${COMMON_OBJS:.o=.h} - -EXTRA_DEPS += - -# BPF-prog kern and userspace shares struct via header file: -KERN_USER_H ?= $(wildcard common_kern_user.h) - -CFLAGS ?= -g -I../include/ -BPF_CFLAGS ?= -I../include/ - -LIBS = -lbpf -lelf $(USER_LIBS) - -all: llvm-check $(USER_TARGETS) $(XDP_OBJ) $(COPY_LOADER) $(COPY_STATS) - -.PHONY: clean $(CLANG) $(LLC) - -clean: - $(MAKE) -C $(COMMON_DIR) clean - rm -f $(USER_TARGETS) $(XDP_OBJ) $(USER_OBJ) $(COPY_LOADER) $(COPY_STATS) - rm -f *.ll - rm -f *~ - -ifdef COPY_LOADER -$(COPY_LOADER): $(LOADER_DIR)/${COPY_LOADER:=.c} $(COMMON_H) - make -C $(LOADER_DIR) $(COPY_LOADER) - cp $(LOADER_DIR)/$(COPY_LOADER) $(COPY_LOADER) -endif - -ifdef COPY_STATS -$(COPY_STATS): $(LOADER_DIR)/${COPY_STATS:=.c} $(COMMON_H) - make -C $(LOADER_DIR) $(COPY_STATS) - cp $(LOADER_DIR)/$(COPY_STATS) $(COPY_STATS) -# Needing xdp_stats imply depending on header files: -EXTRA_DEPS += $(COMMON_DIR)/xdp_stats_kern.h $(COMMON_DIR)/xdp_stats_kern_user.h -endif - -# For build dependency on this file, if it gets updated -COMMON_MK = $(COMMON_DIR)/common.mk - -llvm-check: $(CLANG) $(LLC) - @for TOOL in $^ ; do \ - if [ ! $$(command -v $${TOOL} 2>/dev/null) ]; then \ - echo "*** ERROR: Cannot find tool $${TOOL}" ;\ - exit 1; \ - else true; fi; \ - done - -# Create dependency: detect if C-file change and touch H-file, to trigger -# target $(COMMON_OBJS) -$(COMMON_H): %.h: %.c - touch $@ - -# Detect if any of common obj changed and create dependency on .h-files -$(COMMON_OBJS): %.o: %.h - make -C $(COMMON_DIR) - -$(USER_TARGETS): %: %.c Makefile $(COMMON_MK) $(COMMON_OBJS) $(KERN_USER_H) $(EXTRA_DEPS) - $(CC) -Wall $(CFLAGS) $(LDFLAGS) -o $@ $(COMMON_OBJS) \ - $< $(LIBS) - -$(XDP_OBJ): %.o: %.c Makefile $(COMMON_MK) $(KERN_USER_H) $(EXTRA_DEPS) - $(CLANG) -S \ - -target bpf \ - -D __BPF_TRACING__ \ - $(BPF_CFLAGS) \ - -Wall \ - -Wno-unused-value \ - -Wno-pointer-sign \ - -Wno-compare-distinct-pointer-types \ - -Werror \ - -O2 -emit-llvm -c -g -o ${@:.o=.ll} $< - $(LLC) -march=bpf -filetype=obj -o $@ ${@:.o=.ll} diff --git a/src/xdp/common/common_defines.h b/src/xdp/common/common_defines.h deleted file mode 100644 index 2986d2d67..000000000 --- a/src/xdp/common/common_defines.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef __COMMON_DEFINES_H -#define __COMMON_DEFINES_H - -#include <net/if.h> -#include <linux/types.h> -#include <stdbool.h> - -struct config { - __u32 xdp_flags; - int ifindex; - char *ifname; - char ifname_buf[IF_NAMESIZE]; - int redirect_ifindex; - char *redirect_ifname; - char redirect_ifname_buf[IF_NAMESIZE]; - bool do_unload; - bool reuse_maps; - char pin_dir[512]; - char filename[512]; - char progsec[32]; - char src_mac[18]; - char dest_mac[18]; - __u16 xsk_bind_flags; - int xsk_if_queue; - bool xsk_poll_mode; -}; - -/* Defined in common_params.o */ -extern int verbose; - -/* Exit return codes */ -#define EXIT_OK 0 /* == EXIT_SUCCESS (stdlib.h) man exit(3) */ -#define EXIT_FAIL 1 /* == EXIT_FAILURE (stdlib.h) man exit(3) */ -#define EXIT_FAIL_OPTION 2 -#define EXIT_FAIL_XDP 30 -#define EXIT_FAIL_BPF 40 - -#endif /* __COMMON_DEFINES_H */ diff --git a/src/xdp/common/common_libbpf.c b/src/xdp/common/common_libbpf.c deleted file mode 100644 index 443ca4c66..000000000 --- a/src/xdp/common/common_libbpf.c +++ /dev/null @@ -1,161 +0,0 @@ -/* Common function that with time should be moved to libbpf */ - -#include <errno.h> -#include <string.h> - -#include <bpf/bpf.h> -#include <bpf/libbpf.h> - -#include "common_libbpf.h" - -/* From: include/linux/err.h */ -#define MAX_ERRNO 4095 -#define IS_ERR_VALUE(x) ((x) >= (unsigned long)-MAX_ERRNO) -static inline bool IS_ERR_OR_NULL(const void *ptr) -{ - return (!ptr) || IS_ERR_VALUE((unsigned long)ptr); -} - -#define pr_warning printf - -/* As close as possible to libbpf bpf_prog_load_xattr(), with the - * difference of handling pinned maps. - */ -int bpf_prog_load_xattr_maps(const struct bpf_prog_load_attr_maps *attr, - struct bpf_object **pobj, int *prog_fd) -{ - struct bpf_program *prog, *first_prog = NULL; - enum bpf_attach_type expected_attach_type; - enum bpf_prog_type prog_type; - struct bpf_object *obj; - struct bpf_map *map; - int err; - int i; - - if (!attr) - return -EINVAL; - if (!attr->file) - return -EINVAL; - - obj = bpf_object__open_file(attr->file, NULL); - - if (libbpf_get_error(obj)) - return -EINVAL; - - prog = bpf_object__next_program(obj, NULL); - bpf_program__set_type(prog, attr->prog_type); - - bpf_object__for_each_program(prog, obj) { - /* - * If type is not specified, try to guess it based on - * section name. - */ - prog_type = attr->prog_type; - // Was: prog->prog_ifindex = attr->ifindex; - bpf_program__set_ifindex(prog, attr->ifindex); - - expected_attach_type = attr->expected_attach_type; -#if 0 /* Use internal libbpf variables */ - if (prog_type == BPF_PROG_TYPE_UNSPEC) { - err = bpf_program__identify_section(prog, &prog_type, - &expected_attach_type); - if (err < 0) { - bpf_object__close(obj); - return -EINVAL; - } - } -#endif - - bpf_program__set_type(prog, prog_type); - bpf_program__set_expected_attach_type(prog, - expected_attach_type); - - if (!first_prog) - first_prog = prog; - } - - /* Reset attr->pinned_maps.map_fd to identify successful file load */ - for (i = 0; i < attr->nr_pinned_maps; i++) - attr->pinned_maps[i].map_fd = -1; - - bpf_map__for_each(map, obj) { - const char* mapname = bpf_map__name(map); - - if (bpf_map__type(map) != BPF_MAP_TYPE_PERF_EVENT_ARRAY) - bpf_map__set_ifindex(map, attr->ifindex); - /* Was: map->map_ifindex = attr->ifindex; */ - - for (i = 0; i < attr->nr_pinned_maps; i++) { - struct bpf_pinned_map *pin_map = &attr->pinned_maps[i]; - int fd; - - if (strcmp(mapname, pin_map->name) != 0) - continue; - - /* Matched, try opening pinned file */ - fd = bpf_obj_get(pin_map->filename); - if (fd > 0) { - /* Use FD from pinned map as replacement */ - bpf_map__reuse_fd(map, fd); - /* TODO: Might want to set internal map "name" - * if opened pinned map didn't, to allow - * bpf_object__find_map_fd_by_name() to work. - */ - pin_map->map_fd = fd; - continue; - } - /* Could not open pinned filename map, then this prog - * should then pin the map, BUT this can only happen - * after bpf_object__load(). - */ - } - } - - if (!first_prog) { - pr_warning("object file doesn't contain bpf program\n"); - bpf_object__close(obj); - return -ENOENT; - } - - err = bpf_object__load(obj); - if (err) { - bpf_object__close(obj); - return -EINVAL; - } - - /* Pin the maps that were not loaded via pinned filename */ - bpf_map__for_each(map, obj) { - const char* mapname = bpf_map__name(map); - - for (i = 0; i < attr->nr_pinned_maps; i++) { - struct bpf_pinned_map *pin_map = &attr->pinned_maps[i]; - int err; - - if (strcmp(mapname, pin_map->name) != 0) - continue; - - /* Matched, check if map is already loaded */ - if (pin_map->map_fd != -1) - continue; - - /* Needs to be pinned */ - err = bpf_map__pin(map, pin_map->filename); - if (err) - continue; - pin_map->map_fd = bpf_map__fd(map); - } - } - - /* Help user if requested map name that doesn't exist */ - for (i = 0; i < attr->nr_pinned_maps; i++) { - struct bpf_pinned_map *pin_map = &attr->pinned_maps[i]; - - if (pin_map->map_fd < 0) - pr_warning("%s() requested mapname:%s not seen\n", - __func__, pin_map->name); - } - - *pobj = obj; - *prog_fd = bpf_program__fd(first_prog); - return 0; -} diff --git a/src/xdp/common/common_libbpf.h b/src/xdp/common/common_libbpf.h deleted file mode 100644 index 4754bd8ca..000000000 --- a/src/xdp/common/common_libbpf.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Common function that with time should be moved to libbpf */ -#ifndef __COMMON_LIBBPF_H -#define __COMMON_LIBBPF_H - -struct bpf_pinned_map { - const char *name; - const char *filename; - int map_fd; -}; - -/* bpf_prog_load_attr extended */ -struct bpf_prog_load_attr_maps { - const char *file; - enum bpf_prog_type prog_type; - enum bpf_attach_type expected_attach_type; - int ifindex; - int nr_pinned_maps; - struct bpf_pinned_map *pinned_maps; -}; - -int bpf_prog_load_xattr_maps(const struct bpf_prog_load_attr_maps *attr, - struct bpf_object **pobj, int *prog_fd); - -#endif /* __COMMON_LIBBPF_H */ diff --git a/src/xdp/common/common_params.c b/src/xdp/common/common_params.c deleted file mode 100644 index 642d56d92..000000000 --- a/src/xdp/common/common_params.c +++ /dev/null @@ -1,197 +0,0 @@ -#include <stddef.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <stdbool.h> -#include <getopt.h> -#include <errno.h> - -#include <net/if.h> -#include <linux/if_link.h> /* XDP_FLAGS_* depend on kernel-headers installed */ -#include <linux/if_xdp.h> - -#include "common_params.h" - -int verbose = 1; - -#define BUFSIZE 30 - -void _print_options(const struct option_wrapper *long_options, bool required) -{ - int i, pos; - char buf[BUFSIZE]; - - for (i = 0; long_options[i].option.name != 0; i++) { - if (long_options[i].required != required) - continue; - - if (long_options[i].option.val > 64) /* ord('A') = 65 */ - printf(" -%c,", long_options[i].option.val); - else - printf(" "); - pos = snprintf(buf, BUFSIZE, " --%s", long_options[i].option.name); - if (long_options[i].metavar) - snprintf(&buf[pos], BUFSIZE-pos, " %s", long_options[i].metavar); - printf("%-22s", buf); - printf(" %s", long_options[i].help); - printf("\n"); - } -} - -void usage(const char *prog_name, const char *doc, - const struct option_wrapper *long_options, bool full) -{ - printf("Usage: %s [options]\n", prog_name); - - if (!full) { - printf("Use --help (or -h) to see full option list.\n"); - return; - } - - printf("\nDOCUMENTATION:\n %s\n", doc); - printf("Required options:\n"); - _print_options(long_options, true); - printf("\n"); - printf("Other options:\n"); - _print_options(long_options, false); - printf("\n"); -} - -int option_wrappers_to_options(const struct option_wrapper *wrapper, - struct option **options) -{ - int i, num; - struct option *new_options; - for (i = 0; wrapper[i].option.name != 0; i++) {} - num = i; - - new_options = malloc(sizeof(struct option) * num); - if (!new_options) - return -1; - for (i = 0; i < num; i++) { - memcpy(&new_options[i], &wrapper[i], sizeof(struct option)); - } - - *options = new_options; - return 0; -} - -void parse_cmdline_args(int argc, char **argv, - const struct option_wrapper *options_wrapper, - struct config *cfg, const char *doc) -{ - struct option *long_options; - bool full_help = false; - int longindex = 0; - char *dest; - int opt; - - if (option_wrappers_to_options(options_wrapper, &long_options)) { - fprintf(stderr, "Unable to malloc()\n"); - exit(EXIT_FAIL_OPTION); - } - - /* Parse commands line args */ - while ((opt = getopt_long(argc, argv, "hd:r:L:R:ASNFUMQ:czpq", - long_options, &longindex)) != -1) { - switch (opt) { - case 'd': - if (strlen(optarg) >= IF_NAMESIZE) { - fprintf(stderr, "ERR: --dev name too long\n"); - goto error; - } - cfg->ifname = (char *)&cfg->ifname_buf; - strncpy(cfg->ifname, optarg, IF_NAMESIZE); - cfg->ifindex = if_nametoindex(cfg->ifname); - if (cfg->ifindex == 0) { - fprintf(stderr, - "ERR: --dev name unknown err(%d):%s\n", - errno, strerror(errno)); - goto error; - } - break; - case 'r': - if (strlen(optarg) >= IF_NAMESIZE) { - fprintf(stderr, "ERR: --redirect-dev name too long\n"); - goto error; - } - cfg->redirect_ifname = (char *)&cfg->redirect_ifname_buf; - strncpy(cfg->redirect_ifname, optarg, IF_NAMESIZE); - cfg->redirect_ifindex = if_nametoindex(cfg->redirect_ifname); - if (cfg->redirect_ifindex == 0) { - fprintf(stderr, - "ERR: --redirect-dev name unknown err(%d):%s\n", - errno, strerror(errno)); - goto error; - } - break; - case 'A': - cfg->xdp_flags &= ~XDP_FLAGS_MODES; /* Clear flags */ - break; - case 'S': - cfg->xdp_flags &= ~XDP_FLAGS_MODES; /* Clear flags */ - cfg->xdp_flags |= XDP_FLAGS_SKB_MODE; /* Set flag */ - cfg->xsk_bind_flags &= XDP_ZEROCOPY; - cfg->xsk_bind_flags |= XDP_COPY; - break; - case 'N': - cfg->xdp_flags &= ~XDP_FLAGS_MODES; /* Clear flags */ - cfg->xdp_flags |= XDP_FLAGS_DRV_MODE; /* Set flag */ - break; - case 3: /* --offload-mode */ - cfg->xdp_flags &= ~XDP_FLAGS_MODES; /* Clear flags */ - cfg->xdp_flags |= XDP_FLAGS_HW_MODE; /* Set flag */ - break; - case 'F': - cfg->xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST; - break; - case 'M': - cfg->reuse_maps = true; - break; - case 'U': - cfg->do_unload = true; - break; - case 'p': - cfg->xsk_poll_mode = true; - break; - case 'q': - verbose = false; - break; - case 'Q': - cfg->xsk_if_queue = atoi(optarg); - break; - case 1: /* --filename */ - dest = (char *)&cfg->filename; - strncpy(dest, optarg, sizeof(cfg->filename)); - break; - case 2: /* --progsec */ - dest = (char *)&cfg->progsec; - strncpy(dest, optarg, sizeof(cfg->progsec)); - break; - case 'L': /* --src-mac */ - dest = (char *)&cfg->src_mac; - strncpy(dest, optarg, sizeof(cfg->src_mac)); - break; - case 'R': /* --dest-mac */ - dest = (char *)&cfg->dest_mac; - strncpy(dest, optarg, sizeof(cfg->dest_mac)); - case 'c': - cfg->xsk_bind_flags &= XDP_ZEROCOPY; - cfg->xsk_bind_flags |= XDP_COPY; - break; - case 'z': - cfg->xsk_bind_flags &= XDP_COPY; - cfg->xsk_bind_flags |= XDP_ZEROCOPY; - break; - case 'h': - full_help = true; - /* fall-through */ - error: - default: - usage(argv[0], doc, options_wrapper, full_help); - free(long_options); - exit(EXIT_FAIL_OPTION); - } - } - free(long_options); -} diff --git a/src/xdp/common/common_params.h b/src/xdp/common/common_params.h deleted file mode 100644 index 6f64c82e3..000000000 --- a/src/xdp/common/common_params.h +++ /dev/null @@ -1,22 +0,0 @@ -/* This common_user.h is used by userspace programs */ -#ifndef __COMMON_PARAMS_H -#define __COMMON_PARAMS_H - -#include <getopt.h> -#include "common_defines.h" - -struct option_wrapper { - struct option option; - char *help; - char *metavar; - bool required; -}; - -void usage(const char *prog_name, const char *doc, - const struct option_wrapper *long_options, bool full); - -void parse_cmdline_args(int argc, char **argv, - const struct option_wrapper *long_options, - struct config *cfg, const char *doc); - -#endif /* __COMMON_PARAMS_H */ diff --git a/src/xdp/common/common_user_bpf_xdp.c b/src/xdp/common/common_user_bpf_xdp.c deleted file mode 100644 index 524f08c9d..000000000 --- a/src/xdp/common/common_user_bpf_xdp.c +++ /dev/null @@ -1,389 +0,0 @@ -#include <bpf/libbpf.h> /* bpf_get_link_xdp_id + bpf_set_link_xdp_id */ -#include <string.h> /* strerror */ -#include <net/if.h> /* IF_NAMESIZE */ -#include <stdlib.h> /* exit(3) */ -#include <errno.h> - -#include <bpf/bpf.h> -#include <bpf/libbpf.h> - -#include <linux/if_link.h> /* Need XDP flags */ -#include <linux/err.h> - -#include "common_defines.h" - -#ifndef PATH_MAX -#define PATH_MAX 4096 -#endif - -int xdp_link_attach(int ifindex, __u32 xdp_flags, int prog_fd) -{ - int err; - - /* libbpf provide the XDP net_device link-level hook attach helper */ - err = bpf_xdp_attach(ifindex, prog_fd, xdp_flags, NULL); - if (err == -EEXIST && !(xdp_flags & XDP_FLAGS_UPDATE_IF_NOEXIST)) { - /* Force mode didn't work, probably because a program of the - * opposite type is loaded. Let's unload that and try loading - * again. - */ - - __u32 old_flags = xdp_flags; - - xdp_flags &= ~XDP_FLAGS_MODES; - xdp_flags |= (old_flags & XDP_FLAGS_SKB_MODE) ? XDP_FLAGS_DRV_MODE : XDP_FLAGS_SKB_MODE; - err = bpf_xdp_detach(ifindex, xdp_flags, NULL); - if (!err) - err = bpf_xdp_attach(ifindex, prog_fd, old_flags, NULL); - } - if (err < 0) { - fprintf(stderr, "ERR: " - "ifindex(%d) link set xdp fd failed (%d): %s\n", - ifindex, -err, strerror(-err)); - - switch (-err) { - case EBUSY: - case EEXIST: - fprintf(stderr, "Hint: XDP already loaded on device" - " use --force to swap/replace\n"); - break; - case EOPNOTSUPP: - fprintf(stderr, "Hint: Native-XDP not supported" - " use --skb-mode or --auto-mode\n"); - break; - default: - break; - } - return EXIT_FAIL_XDP; - } - - return EXIT_OK; -} - -int xdp_link_detach(int ifindex, __u32 xdp_flags, __u32 expected_prog_id) -{ - __u32 curr_prog_id; - int err; - - err = bpf_xdp_query_id(ifindex, xdp_flags, &curr_prog_id); - if (err) { - fprintf(stderr, "ERR: get link xdp id failed (err=%d): %s\n", - -err, strerror(-err)); - return EXIT_FAIL_XDP; - } - - if (!curr_prog_id) { - if (verbose) - printf("INFO: %s() no curr XDP prog on ifindex:%d\n", - __func__, ifindex); - return EXIT_OK; - } - - if (expected_prog_id && curr_prog_id != expected_prog_id) { - fprintf(stderr, "ERR: %s() " - "expected prog ID(%d) no match(%d), not removing\n", - __func__, expected_prog_id, curr_prog_id); - return EXIT_FAIL; - } - - if ((err = bpf_xdp_detach(ifindex, xdp_flags, NULL)) < 0) { - fprintf(stderr, "ERR: %s() link set xdp failed (err=%d): %s\n", - __func__, err, strerror(-err)); - return EXIT_FAIL_XDP; - } - - if (verbose) - printf("INFO: %s() removed XDP prog ID:%d on ifindex:%d\n", - __func__, curr_prog_id, ifindex); - - return EXIT_OK; -} - -struct bpf_object *load_bpf_object_file(const char *filename, int ifindex) -{ - int first_prog_fd = -1; - struct bpf_object *obj; - int err; - - /* This struct allow us to set ifindex, this features is used for - * hardware offloading XDP programs (note this sets libbpf - * bpf_program->prog_ifindex and foreach bpf_map->map_ifindex). - */ - struct bpf_program *prog; - obj = bpf_object__open_file(filename, NULL); - - if (libbpf_get_error(obj)) - return NULL; - - prog = bpf_object__next_program(obj, NULL); - bpf_program__set_type(prog, BPF_PROG_TYPE_XDP); - bpf_program__set_ifindex(prog, ifindex); - - /* Use libbpf for extracting BPF byte-code from BPF-ELF object, and - * loading this into the kernel via bpf-syscall - */ - err = bpf_object__load(obj); - if (err) { - fprintf(stderr, "ERR: loading BPF-OBJ file(%s) (%d): %s\n", - filename, err, strerror(-err)); - return NULL; - } - - first_prog_fd = bpf_program__fd(prog); - - /* Notice how a pointer to a libbpf bpf_object is returned */ - return obj; -} - -static struct bpf_object *open_bpf_object(const char *file, int ifindex) -{ - int err; - struct bpf_object *obj; - struct bpf_map *map; - struct bpf_program *prog, *first_prog = NULL; - - obj = bpf_object__open_file(file, NULL); - - if (libbpf_get_error(obj)) - return NULL; - - prog = bpf_object__next_program(obj, NULL); - bpf_program__set_type(prog, BPF_PROG_TYPE_XDP); - - err = bpf_object__load(obj); - if (IS_ERR_OR_NULL(obj)) { - err = -PTR_ERR(obj); - fprintf(stderr, "ERR: opening BPF-OBJ file(%s) (%d): %s\n", - file, err, strerror(-err)); - return NULL; - } - - bpf_object__for_each_program(prog, obj) { - bpf_program__set_type(prog, BPF_PROG_TYPE_XDP); - bpf_program__set_ifindex(prog, ifindex); - if (!first_prog) - first_prog = prog; - } - - bpf_object__for_each_map(map, obj) { - if (bpf_map__type(map) != BPF_MAP_TYPE_PERF_EVENT_ARRAY) - bpf_map__set_ifindex(map, ifindex); - } - - if (!first_prog) { - fprintf(stderr, "ERR: file %s contains no programs\n", file); - return NULL; - } - - return obj; -} - -static int reuse_maps(struct bpf_object *obj, const char *path) -{ - struct bpf_map *map; - - if (!obj) - return -ENOENT; - - if (!path) - return -EINVAL; - - bpf_object__for_each_map(map, obj) { - int len, err; - int pinned_map_fd; - char buf[PATH_MAX]; - - len = snprintf(buf, PATH_MAX, "%s/%s", path, bpf_map__name(map)); - if (len < 0) { - return -EINVAL; - } else if (len >= PATH_MAX) { - return -ENAMETOOLONG; - } - - pinned_map_fd = bpf_obj_get(buf); - if (pinned_map_fd < 0) - return pinned_map_fd; - - err = bpf_map__reuse_fd(map, pinned_map_fd); - if (err) - return err; - } - - return 0; -} - -struct bpf_object *load_bpf_object_file_reuse_maps(const char *file, - int ifindex, - const char *pin_dir) -{ - int err; - struct bpf_object *obj; - - obj = open_bpf_object(file, ifindex); - if (!obj) { - fprintf(stderr, "ERR: failed to open object %s\n", file); - return NULL; - } - - err = reuse_maps(obj, pin_dir); - if (err) { - fprintf(stderr, "ERR: failed to reuse maps for object %s, pin_dir=%s\n", - file, pin_dir); - return NULL; - } - - err = bpf_object__load(obj); - if (err) { - fprintf(stderr, "ERR: loading BPF-OBJ file(%s) (%d): %s\n", - file, err, strerror(-err)); - return NULL; - } - - return obj; -} - -struct bpf_object *load_bpf_and_xdp_attach(struct config *cfg) -{ - struct bpf_program *bpf_prog; - struct bpf_object *bpf_obj; - int offload_ifindex = 0; - int prog_fd = -1; - int err; - - /* If flags indicate hardware offload, supply ifindex */ - if (cfg->xdp_flags & XDP_FLAGS_HW_MODE) - offload_ifindex = cfg->ifindex; - - /* Load the BPF-ELF object file and get back libbpf bpf_object */ - if (cfg->reuse_maps) - bpf_obj = load_bpf_object_file_reuse_maps(cfg->filename, - offload_ifindex, - cfg->pin_dir); - else - bpf_obj = load_bpf_object_file(cfg->filename, offload_ifindex); - if (!bpf_obj) { - fprintf(stderr, "ERR: loading file: %s\n", cfg->filename); - exit(EXIT_FAIL_BPF); - } - /* At this point: All XDP/BPF programs from the cfg->filename have been - * loaded into the kernel, and evaluated by the verifier. Only one of - * these gets attached to XDP hook, the others will get freed once this - * process exit. - */ - - if (cfg->progsec[0]) - /* Find a matching BPF prog section name */ - bpf_prog = bpf_object__find_program_by_name(bpf_obj, cfg->progsec); - else - /* Find the first program */ - bpf_prog = bpf_object__next_program(bpf_obj, NULL); - - if (!bpf_prog) { - fprintf(stderr, "ERR: couldn't find a program in ELF section '%s'\n", cfg->progsec); - exit(EXIT_FAIL_BPF); - } - - strncpy(cfg->progsec, bpf_program__section_name(bpf_prog), sizeof(cfg->progsec)); - - prog_fd = bpf_program__fd(bpf_prog); - if (prog_fd <= 0) { - fprintf(stderr, "ERR: bpf_program__fd failed\n"); - exit(EXIT_FAIL_BPF); - } - - /* At this point: BPF-progs are (only) loaded by the kernel, and prog_fd - * is our select file-descriptor handle. Next step is attaching this FD - * to a kernel hook point, in this case XDP net_device link-level hook. - */ - err = xdp_link_attach(cfg->ifindex, cfg->xdp_flags, prog_fd); - if (err) - exit(err); - - return bpf_obj; -} - -#define XDP_UNKNOWN XDP_REDIRECT + 1 -#ifndef XDP_ACTION_MAX -#define XDP_ACTION_MAX (XDP_UNKNOWN + 1) -#endif - -static const char *xdp_action_names[XDP_ACTION_MAX] = { - [XDP_ABORTED] = "XDP_ABORTED", - [XDP_DROP] = "XDP_DROP", - [XDP_PASS] = "XDP_PASS", - [XDP_TX] = "XDP_TX", - [XDP_REDIRECT] = "XDP_REDIRECT", - [XDP_UNKNOWN] = "XDP_UNKNOWN", -}; - -const char *action2str(__u32 action) -{ - if (action < XDP_ACTION_MAX) - return xdp_action_names[action]; - return NULL; -} - -int check_map_fd_info(const struct bpf_map_info *info, - const struct bpf_map_info *exp) -{ - if (exp->key_size && exp->key_size != info->key_size) { - fprintf(stderr, "ERR: %s() " - "Map key size(%d) mismatch expected size(%d)\n", - __func__, info->key_size, exp->key_size); - return EXIT_FAIL; - } - if (exp->value_size && exp->value_size != info->value_size) { - fprintf(stderr, "ERR: %s() " - "Map value size(%d) mismatch expected size(%d)\n", - __func__, info->value_size, exp->value_size); - return EXIT_FAIL; - } - if (exp->max_entries && exp->max_entries != info->max_entries) { - fprintf(stderr, "ERR: %s() " - "Map max_entries(%d) mismatch expected size(%d)\n", - __func__, info->max_entries, exp->max_entries); - return EXIT_FAIL; - } - if (exp->type && exp->type != info->type) { - fprintf(stderr, "ERR: %s() " - "Map type(%d) mismatch expected type(%d)\n", - __func__, info->type, exp->type); - return EXIT_FAIL; - } - - return 0; -} - -int open_bpf_map_file(const char *pin_dir, - const char *mapname, - struct bpf_map_info *info) -{ - char filename[PATH_MAX]; - int err, len, fd; - __u32 info_len = sizeof(*info); - - len = snprintf(filename, PATH_MAX, "%s/%s", pin_dir, mapname); - if (len < 0) { - fprintf(stderr, "ERR: constructing full mapname path\n"); - return -1; - } - - fd = bpf_obj_get(filename); - if (fd < 0) { - fprintf(stderr, - "WARN: Failed to open bpf map file:%s err(%d):%s\n", - filename, errno, strerror(errno)); - return fd; - } - - if (info) { - err = bpf_obj_get_info_by_fd(fd, info, &info_len); - if (err) { - fprintf(stderr, "ERR: %s() can't get info - %s\n", - __func__, strerror(errno)); - return EXIT_FAIL_BPF; - } - } - - return fd; -} diff --git a/src/xdp/common/common_user_bpf_xdp.h b/src/xdp/common/common_user_bpf_xdp.h deleted file mode 100644 index 4f8aa51d4..000000000 --- a/src/xdp/common/common_user_bpf_xdp.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Common BPF/XDP functions used by userspace side programs */ -#ifndef __COMMON_USER_BPF_XDP_H -#define __COMMON_USER_BPF_XDP_H - -int xdp_link_attach(int ifindex, __u32 xdp_flags, int prog_fd); -int xdp_link_detach(int ifindex, __u32 xdp_flags, __u32 expected_prog_id); - -struct bpf_object *load_bpf_object_file(const char *filename, int ifindex); -struct bpf_object *load_bpf_and_xdp_attach(struct config *cfg); - -const char *action2str(__u32 action); - -int check_map_fd_info(const struct bpf_map_info *info, - const struct bpf_map_info *exp); - -int open_bpf_map_file(const char *pin_dir, - const char *mapname, - struct bpf_map_info *info); - -#endif /* __COMMON_USER_BPF_XDP_H */ diff --git a/src/xdp/common/parsing_helpers.h b/src/xdp/common/parsing_helpers.h deleted file mode 100644 index c0837e88f..000000000 --- a/src/xdp/common/parsing_helpers.h +++ /dev/null @@ -1,244 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-clause) */ -/* - * This file contains parsing functions that are used in the packetXX XDP - * programs. The functions are marked as __always_inline, and fully defined in - * this header file to be included in the BPF program. - * - * Each helper parses a packet header, including doing bounds checking, and - * returns the type of its contents if successful, and -1 otherwise. - * - * For Ethernet and IP headers, the content type is the type of the payload - * (h_proto for Ethernet, nexthdr for IPv6), for ICMP it is the ICMP type field. - * All return values are in host byte order. - * - * The versions of the functions included here are slightly expanded versions of - * the functions in the packet01 lesson. For instance, the Ethernet header - * parsing has support for parsing VLAN tags. - */ - -#ifndef __PARSING_HELPERS_H -#define __PARSING_HELPERS_H - -#include <stddef.h> -#include <linux/if_ether.h> -#include <linux/if_packet.h> -#include <linux/ip.h> -#include <linux/ipv6.h> -#include <linux/icmp.h> -#include <linux/icmpv6.h> -#include <linux/udp.h> -#include <linux/tcp.h> - -/* Header cursor to keep track of current parsing position */ -struct hdr_cursor { - void *pos; -}; - -/* - * struct vlan_hdr - vlan header - * @h_vlan_TCI: priority and VLAN ID - * @h_vlan_encapsulated_proto: packet type ID or len - */ -struct vlan_hdr { - __be16 h_vlan_TCI; - __be16 h_vlan_encapsulated_proto; -}; - -/* - * Struct icmphdr_common represents the common part of the icmphdr and icmp6hdr - * structures. - */ -struct icmphdr_common { - __u8 type; - __u8 code; - __sum16 cksum; -}; - -/* Allow users of header file to redefine VLAN max depth */ -#ifndef VLAN_MAX_DEPTH -#define VLAN_MAX_DEPTH 4 -#endif - -static __always_inline int proto_is_vlan(__u16 h_proto) -{ - return !!(h_proto == bpf_htons(ETH_P_8021Q) || - h_proto == bpf_htons(ETH_P_8021AD)); -} - -/* Notice, parse_ethhdr() will skip VLAN tags, by advancing nh->pos and returns - * next header EtherType, BUT the ethhdr pointer supplied still points to the - * Ethernet header. Thus, caller can look at eth->h_proto to see if this was a - * VLAN tagged packet. - */ -static __always_inline int parse_ethhdr(struct hdr_cursor *nh, void *data_end, - struct ethhdr **ethhdr) -{ - struct ethhdr *eth = nh->pos; - int hdrsize = sizeof(*eth); - struct vlan_hdr *vlh; - __u16 h_proto; - int i; - - /* Byte-count bounds check; check if current pointer + size of header - * is after data_end. - */ - if (nh->pos + hdrsize > data_end) - return -1; - - nh->pos += hdrsize; - *ethhdr = eth; - vlh = nh->pos; - h_proto = eth->h_proto; - - /* Use loop unrolling to avoid the verifier restriction on loops; - * support up to VLAN_MAX_DEPTH layers of VLAN encapsulation. - */ - #pragma unroll - for (i = 0; i < VLAN_MAX_DEPTH; i++) { - if (!proto_is_vlan(h_proto)) - break; - - if (vlh + 1 > data_end) - break; - - h_proto = vlh->h_vlan_encapsulated_proto; - vlh++; - } - - nh->pos = vlh; - return h_proto; /* network-byte-order */ -} - -static __always_inline int parse_ip6hdr(struct hdr_cursor *nh, - void *data_end, - struct ipv6hdr **ip6hdr) -{ - struct ipv6hdr *ip6h = nh->pos; - - /* Pointer-arithmetic bounds check; pointer +1 points to after end of - * thing being pointed to. We will be using this style in the remainder - * of the tutorial. - */ - if (ip6h + 1 > data_end) - return -1; - - nh->pos = ip6h + 1; - *ip6hdr = ip6h; - - return ip6h->nexthdr; -} - -static __always_inline int parse_iphdr(struct hdr_cursor *nh, - void *data_end, - struct iphdr **iphdr) -{ - struct iphdr *iph = nh->pos; - int hdrsize; - - if (iph + 1 > data_end) - return -1; - - hdrsize = iph->ihl * 4; - - /* Variable-length IPv4 header, need to use byte-based arithmetic */ - if (nh->pos + hdrsize > data_end) - return -1; - - nh->pos += hdrsize; - *iphdr = iph; - - return iph->protocol; -} - -static __always_inline int parse_icmp6hdr(struct hdr_cursor *nh, - void *data_end, - struct icmp6hdr **icmp6hdr) -{ - struct icmp6hdr *icmp6h = nh->pos; - - if (icmp6h + 1 > data_end) - return -1; - - nh->pos = icmp6h + 1; - *icmp6hdr = icmp6h; - - return icmp6h->icmp6_type; -} - -static __always_inline int parse_icmphdr(struct hdr_cursor *nh, - void *data_end, - struct icmphdr **icmphdr) -{ - struct icmphdr *icmph = nh->pos; - - if (icmph + 1 > data_end) - return -1; - - nh->pos = icmph + 1; - *icmphdr = icmph; - - return icmph->type; -} - -static __always_inline int parse_icmphdr_common(struct hdr_cursor *nh, - void *data_end, - struct icmphdr_common **icmphdr) -{ - struct icmphdr_common *h = nh->pos; - - if (h + 1 > data_end) - return -1; - - nh->pos = h + 1; - *icmphdr = h; - - return h->type; -} - -/* - * parse_udphdr: parse the udp header and return the length of the udp payload - */ -static __always_inline int parse_udphdr(struct hdr_cursor *nh, - void *data_end, - struct udphdr **udphdr) -{ - int len; - struct udphdr *h = nh->pos; - - if (h + 1 > data_end) - return -1; - - nh->pos = h + 1; - *udphdr = h; - - len = bpf_ntohs(h->len) - sizeof(struct udphdr); - if (len < 0) - return -1; - - return len; -} - -/* - * parse_tcphdr: parse and return the length of the tcp header - */ -static __always_inline int parse_tcphdr(struct hdr_cursor *nh, - void *data_end, - struct tcphdr **tcphdr) -{ - int len; - struct tcphdr *h = nh->pos; - - if (h + 1 > data_end) - return -1; - - len = h->doff * 4; - if ((void *) h + len > data_end) - return -1; - - nh->pos = h + 1; - *tcphdr = h; - - return len; -} - -#endif /* __PARSING_HELPERS_H */ diff --git a/src/xdp/common/rewrite_helpers.h b/src/xdp/common/rewrite_helpers.h deleted file mode 100644 index a5d3e671d..000000000 --- a/src/xdp/common/rewrite_helpers.h +++ /dev/null @@ -1,144 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-clause) */ -/* - * This file contains functions that are used in the packetXX XDP programs to - * manipulate on packets data. The functions are marked as __always_inline, and - * fully defined in this header file to be included in the BPF program. - */ - -#ifndef __REWRITE_HELPERS_H -#define __REWRITE_HELPERS_H - -#include <linux/bpf.h> -#include <linux/ip.h> -#include <linux/ipv6.h> -#include <linux/if_ether.h> - -#include <bpf/bpf_helpers.h> -#include <bpf/bpf_endian.h> - -/* Pops the outermost VLAN tag off the packet. Returns the popped VLAN ID on - * success or negative errno on failure. - */ -static __always_inline int vlan_tag_pop(struct xdp_md *ctx, struct ethhdr *eth) -{ - void *data_end = (void *)(long)ctx->data_end; - struct ethhdr eth_cpy; - struct vlan_hdr *vlh; - __be16 h_proto; - int vlid; - - if (!proto_is_vlan(eth->h_proto)) - return -1; - - /* Careful with the parenthesis here */ - vlh = (void *)(eth + 1); - - /* Still need to do bounds checking */ - if (vlh + 1 > data_end) - return -1; - - /* Save vlan ID for returning, h_proto for updating Ethernet header */ - vlid = bpf_ntohs(vlh->h_vlan_TCI); - h_proto = vlh->h_vlan_encapsulated_proto; - - /* Make a copy of the outer Ethernet header before we cut it off */ - __builtin_memcpy(ð_cpy, eth, sizeof(eth_cpy)); - - /* Actually adjust the head pointer */ - if (bpf_xdp_adjust_head(ctx, (int)sizeof(*vlh))) - return -1; - - /* Need to re-evaluate data *and* data_end and do new bounds checking - * after adjusting head - */ - eth = (void *)(long)ctx->data; - data_end = (void *)(long)ctx->data_end; - if (eth + 1 > data_end) - return -1; - - /* Copy back the old Ethernet header and update the proto type */ - __builtin_memcpy(eth, ð_cpy, sizeof(*eth)); - eth->h_proto = h_proto; - - return vlid; -} - -/* Pushes a new VLAN tag after the Ethernet header. Returns 0 on success, - * -1 on failure. - */ -static __always_inline int vlan_tag_push(struct xdp_md *ctx, - struct ethhdr *eth, int vlid) -{ - void *data_end = (void *)(long)ctx->data_end; - struct ethhdr eth_cpy; - struct vlan_hdr *vlh; - - /* First copy the original Ethernet header */ - __builtin_memcpy(ð_cpy, eth, sizeof(eth_cpy)); - - /* Then add space in front of the packet */ - if (bpf_xdp_adjust_head(ctx, 0 - (int)sizeof(*vlh))) - return -1; - - /* Need to re-evaluate data_end and data after head adjustment, and - * bounds check, even though we know there is enough space (as we - * increased it). - */ - data_end = (void *)(long)ctx->data_end; - eth = (void *)(long)ctx->data; - - if (eth + 1 > data_end) - return -1; - - /* Copy back Ethernet header in the right place, populate VLAN tag with - * ID and proto, and set outer Ethernet header to VLAN type. - */ - __builtin_memcpy(eth, ð_cpy, sizeof(*eth)); - - vlh = (void *)(eth + 1); - - if (vlh + 1 > data_end) - return -1; - - vlh->h_vlan_TCI = bpf_htons(vlid); - vlh->h_vlan_encapsulated_proto = eth->h_proto; - - eth->h_proto = bpf_htons(ETH_P_8021Q); - return 0; -} - -/* - * Swaps destination and source MAC addresses inside an Ethernet header - */ -static __always_inline void swap_src_dst_mac(struct ethhdr *eth) -{ - __u8 h_tmp[ETH_ALEN]; - - __builtin_memcpy(h_tmp, eth->h_source, ETH_ALEN); - __builtin_memcpy(eth->h_source, eth->h_dest, ETH_ALEN); - __builtin_memcpy(eth->h_dest, h_tmp, ETH_ALEN); -} - -/* - * Swaps destination and source IPv6 addresses inside an IPv6 header - */ -static __always_inline void swap_src_dst_ipv6(struct ipv6hdr *ipv6) -{ - struct in6_addr tmp = ipv6->saddr; - - ipv6->saddr = ipv6->daddr; - ipv6->daddr = tmp; -} - -/* - * Swaps destination and source IPv4 addresses inside an IPv4 header - */ -static __always_inline void swap_src_dst_ipv4(struct iphdr *iphdr) -{ - __be32 tmp = iphdr->saddr; - - iphdr->saddr = iphdr->daddr; - iphdr->daddr = tmp; -} - -#endif /* __REWRITE_HELPERS_H */ diff --git a/src/xdp/common/xdp_stats_kern.h b/src/xdp/common/xdp_stats_kern.h deleted file mode 100644 index c061a149d..000000000 --- a/src/xdp/common/xdp_stats_kern.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -/* Used *ONLY* by BPF-prog running kernel side. */ -#ifndef __XDP_STATS_KERN_H -#define __XDP_STATS_KERN_H - -/* Data record type 'struct datarec' is defined in common/xdp_stats_kern_user.h, - * programs using this header must first include that file. - */ -#ifndef __XDP_STATS_KERN_USER_H -#warning "You forgot to #include <../common/xdp_stats_kern_user.h>" -#include <../common/xdp_stats_kern_user.h> -#endif - -/* Keeps stats per (enum) xdp_action */ -struct { - __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); - __type(key, __u32); - __type(value, struct datarec); - __uint(max_entries, XDP_ACTION_MAX); -} xdp_stats_map SEC(".maps"); - -static __always_inline -__u32 xdp_stats_record_action(struct xdp_md *ctx, __u32 action) -{ - if (action >= XDP_ACTION_MAX) - return XDP_ABORTED; - - /* Lookup in kernel BPF-side return pointer to actual data record */ - struct datarec *rec = bpf_map_lookup_elem(&xdp_stats_map, &action); - if (!rec) - return XDP_ABORTED; - - /* BPF_MAP_TYPE_PERCPU_ARRAY returns a data record specific to current - * CPU and XDP hooks runs under Softirq, which makes it safe to update - * without atomic operations. - */ - rec->rx_packets++; - rec->rx_bytes += (ctx->data_end - ctx->data); - - return action; -} - -#endif /* __XDP_STATS_KERN_H */ diff --git a/src/xdp/common/xdp_stats_kern_user.h b/src/xdp/common/xdp_stats_kern_user.h deleted file mode 100644 index d7b8d05e6..000000000 --- a/src/xdp/common/xdp_stats_kern_user.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -/* Used by BPF-prog kernel side BPF-progs and userspace programs, - * for sharing xdp_stats common struct and DEFINEs. - */ -#ifndef __XDP_STATS_KERN_USER_H -#define __XDP_STATS_KERN_USER_H - -/* This is the data record stored in the map */ -struct datarec { - __u64 rx_packets; - __u64 rx_bytes; -}; - -#ifndef XDP_ACTION_MAX -#define XDP_ACTION_MAX (XDP_REDIRECT + 1) -#endif - -#endif /* __XDP_STATS_KERN_USER_H */ |