Add maps for flow tables in bpf. TC flower has hash tables for each flow mask ordered by priority. To do the same thing, prepare hashmap-in-arraymap. As bpf does not provide ordered list, we emulate it by an array. Each array entry has one-byte next index field to implement a list. Also prepare a one-element array to point to the head index of the list. Because of the limitation of bpf maps, the outer array is implemented using two array maps. "flow_masks" is the array to emulate the list and its entries have the priority and mask of each flow table. For each priority/mask, the same index entry of another map "flow_tables", which is the hashmap-in-arraymap, points to the actual flow table. The flow insertion logic in UMH and lookup logic in BPF will be implemented in the following commits. NOTE: This list emulation by array may be able to be realized by adding ordered-list type map. In that case we also need map iteration API for bpf progs. Signed-off-by: Toshiaki Makita <toshiaki.makita1@xxxxxxxxx> --- net/xdp_flow/umh_bpf.h | 18 +++++++++++ net/xdp_flow/xdp_flow_kern_bpf.c | 22 +++++++++++++ net/xdp_flow/xdp_flow_umh.c | 70 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 net/xdp_flow/umh_bpf.h diff --git a/net/xdp_flow/umh_bpf.h b/net/xdp_flow/umh_bpf.h new file mode 100644 index 0000000..b4fe0c6 --- /dev/null +++ b/net/xdp_flow/umh_bpf.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _NET_XDP_FLOW_UMH_BPF_H +#define _NET_XDP_FLOW_UMH_BPF_H + +#include "msgfmt.h" + +#define MAX_FLOWS 1024 +#define MAX_FLOW_MASKS 255 +#define FLOW_MASKS_TAIL 255 + +struct xdp_flow_mask_entry { + struct xdp_flow_key mask; + __u16 priority; + short count; + int next; +}; + +#endif diff --git a/net/xdp_flow/xdp_flow_kern_bpf.c b/net/xdp_flow/xdp_flow_kern_bpf.c index 74cdb1d..c101156 100644 --- a/net/xdp_flow/xdp_flow_kern_bpf.c +++ b/net/xdp_flow/xdp_flow_kern_bpf.c @@ -2,6 +2,28 @@ #define KBUILD_MODNAME "foo" #include <uapi/linux/bpf.h> #include <bpf_helpers.h> +#include "umh_bpf.h" + +struct bpf_map_def SEC("maps") flow_masks_head = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(u32), + .value_size = sizeof(int), + .max_entries = 1, +}; + +struct bpf_map_def SEC("maps") flow_masks = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(u32), + .value_size = sizeof(struct xdp_flow_mask_entry), + .max_entries = MAX_FLOW_MASKS, +}; + +struct bpf_map_def SEC("maps") flow_tables = { + .type = BPF_MAP_TYPE_ARRAY_OF_MAPS, + .key_size = sizeof(u32), + .value_size = sizeof(u32), + .max_entries = MAX_FLOW_MASKS, +}; SEC("xdp_flow") int xdp_flow_prog(struct xdp_md *ctx) diff --git a/net/xdp_flow/xdp_flow_umh.c b/net/xdp_flow/xdp_flow_umh.c index 734db00..e35666a 100644 --- a/net/xdp_flow/xdp_flow_umh.c +++ b/net/xdp_flow/xdp_flow_umh.c @@ -13,7 +13,7 @@ #include <sys/resource.h> #include <linux/hashtable.h> #include <linux/err.h> -#include "msgfmt.h" +#include "umh_bpf.h" extern char xdp_flow_bpf_start; extern char xdp_flow_bpf_end; @@ -95,11 +95,13 @@ static int setup(void) static int load_bpf(int ifindex, struct bpf_object **objp) { + int prog_fd, flow_tables_fd, flow_meta_fd, flow_masks_head_fd, err; + struct bpf_map *flow_tables, *flow_masks_head; + int zero = 0, flow_masks_tail = FLOW_MASKS_TAIL; struct bpf_object_open_attr attr = {}; char path[256], errbuf[ERRBUF_SIZE]; struct bpf_program *prog; struct bpf_object *obj; - int prog_fd, err; ssize_t len; len = snprintf(path, 256, "/proc/self/fd/%d", progfile_fd); @@ -127,6 +129,48 @@ static int load_bpf(int ifindex, struct bpf_object **objp) bpf_object__for_each_program(prog, obj) bpf_program__set_type(prog, attr.prog_type); + flow_meta_fd = bpf_create_map(BPF_MAP_TYPE_HASH, + sizeof(struct xdp_flow_key), + sizeof(struct xdp_flow_actions), + MAX_FLOWS, 0); + if (flow_meta_fd < 0) { + err = -errno; + pr_err("map creation for flow_tables meta failed: %s\n", + strerror(errno)); + goto err; + } + + flow_tables_fd = bpf_create_map_in_map(BPF_MAP_TYPE_ARRAY_OF_MAPS, + "flow_tables", sizeof(__u32), + flow_meta_fd, MAX_FLOW_MASKS, 0); + if (flow_tables_fd < 0) { + err = -errno; + pr_err("map creation for flow_tables failed: %s\n", + strerror(errno)); + close(flow_meta_fd); + goto err; + } + + close(flow_meta_fd); + + flow_tables = bpf_object__find_map_by_name(obj, "flow_tables"); + if (!flow_tables) { + pr_err("Cannot find flow_tables\n"); + err = -ENOENT; + close(flow_tables_fd); + goto err; + } + + err = bpf_map__reuse_fd(flow_tables, flow_tables_fd); + if (err) { + err = libbpf_err(err, errbuf); + pr_err("Failed to reuse flow_tables fd: %s\n", errbuf); + close(flow_tables_fd); + goto err; + } + + close(flow_tables_fd); + err = bpf_object__load(obj); if (err) { err = libbpf_err(err, errbuf); @@ -134,6 +178,28 @@ static int load_bpf(int ifindex, struct bpf_object **objp) goto err; } + flow_masks_head = bpf_object__find_map_by_name(obj, "flow_masks_head"); + if (!flow_masks_head) { + pr_err("Cannot find flow_masks_head map\n"); + err = -ENOENT; + goto err; + } + + flow_masks_head_fd = bpf_map__fd(flow_masks_head); + if (flow_masks_head_fd < 0) { + err = libbpf_err(flow_masks_head_fd, errbuf); + pr_err("Invalid flow_masks_head fd: %s\n", errbuf); + goto err; + } + + if (bpf_map_update_elem(flow_masks_head_fd, &zero, &flow_masks_tail, + 0)) { + err = -errno; + pr_err("Failed to initialize flow_masks_head: %s\n", + strerror(errno)); + goto err; + } + prog = bpf_object__find_program_by_title(obj, "xdp_flow"); if (!prog) { pr_err("Cannot find xdp_flow program\n"); -- 1.8.3.1