Commit f6793eec authored by Daniel Borkmann's avatar Daniel Borkmann Committed by Stephen Hemminger

{f, m}_bpf: allow for user-defined object pinnings

The recently introduced object pinning can be further extended in order
to allow sharing maps beyond tc namespace. F.e. maps that are being pinned
from tracing side, can be accessed through this facility as well.
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 9e607f2e
#
# subpath mappings from mount point for pinning
#
#3 tracing
#4 foo/bar
#5 tc/cls1
......@@ -33,7 +33,7 @@ struct bpf_elf_map {
__u32 size_value;
__u32 max_elem;
__u32 id;
__u8 pinning;
__u32 pinning;
};
#endif /* __BPF_ELF__ */
......@@ -40,6 +40,10 @@ extern bool do_all;
#define IPSEC_PROTO_ANY 255
#endif
#ifndef CONFDIR
#define CONFDIR "/etc/iproute2"
#endif
#define SPRINT_BSIZE 64
#define SPRINT_BUF(x) char x[SPRINT_BSIZE]
......
......@@ -23,10 +23,7 @@
#include <linux/rtnetlink.h>
#include "rt_names.h"
#ifndef CONFDIR
#define CONFDIR "/etc/iproute2"
#endif
#include "utils.h"
#define NAME_MAX_LEN 512
......
......@@ -458,6 +458,12 @@ struct bpf_elf_prog {
const char *license;
};
struct bpf_hash_entry {
unsigned int pinning;
const char *subpath;
struct bpf_hash_entry *next;
};
struct bpf_elf_ctx {
Elf *elf_fd;
GElf_Ehdr elf_hdr;
......@@ -474,6 +480,7 @@ struct bpf_elf_ctx {
enum bpf_prog_type type;
bool verbose;
struct bpf_elf_st stat;
struct bpf_hash_entry *ht[256];
};
struct bpf_elf_sec_data {
......@@ -771,20 +778,34 @@ static int bpf_init_env(const char *pathname)
return 0;
}
static bool bpf_no_pinning(int pinning)
static const char *bpf_custom_pinning(const struct bpf_elf_ctx *ctx,
uint32_t pinning)
{
struct bpf_hash_entry *entry;
entry = ctx->ht[pinning & (ARRAY_SIZE(ctx->ht) - 1)];
while (entry && entry->pinning != pinning)
entry = entry->next;
return entry ? entry->subpath : NULL;
}
static bool bpf_no_pinning(const struct bpf_elf_ctx *ctx,
uint32_t pinning)
{
switch (pinning) {
case PIN_OBJECT_NS:
case PIN_GLOBAL_NS:
return false;
case PIN_NONE:
default:
return true;
default:
return !bpf_custom_pinning(ctx, pinning);
}
}
static void bpf_make_pathname(char *pathname, size_t len, const char *name,
int pinning)
const struct bpf_elf_ctx *ctx, uint32_t pinning)
{
switch (pinning) {
case PIN_OBJECT_NS:
......@@ -795,41 +816,89 @@ static void bpf_make_pathname(char *pathname, size_t len, const char *name,
snprintf(pathname, len, "%s/%s/%s", bpf_get_tc_dir(),
BPF_DIR_GLOBALS, name);
break;
default:
snprintf(pathname, len, "%s/../%s/%s", bpf_get_tc_dir(),
bpf_custom_pinning(ctx, pinning), name);
break;
}
}
static int bpf_probe_pinned(const char *name, int pinning)
static int bpf_probe_pinned(const char *name, const struct bpf_elf_ctx *ctx,
uint32_t pinning)
{
char pathname[PATH_MAX];
if (bpf_no_pinning(pinning) || !bpf_get_tc_dir())
if (bpf_no_pinning(ctx, pinning) || !bpf_get_tc_dir())
return 0;
bpf_make_pathname(pathname, sizeof(pathname), name, pinning);
bpf_make_pathname(pathname, sizeof(pathname), name, ctx, pinning);
return bpf_obj_get(pathname);
}
static int bpf_place_pinned(int fd, const char *name, int pinning)
static int bpf_make_obj_path(void)
{
char pathname[PATH_MAX];
char tmp[PATH_MAX];
int ret;
if (bpf_no_pinning(pinning) || !bpf_get_tc_dir())
return 0;
snprintf(tmp, sizeof(tmp), "%s/%s", bpf_get_tc_dir(),
bpf_get_obj_uid(NULL));
ret = mkdir(tmp, S_IRWXU);
if (ret && errno != EEXIST) {
fprintf(stderr, "mkdir %s failed: %s\n", tmp, strerror(errno));
return ret;
}
return 0;
}
static int bpf_make_custom_path(const char *todo)
{
char tmp[PATH_MAX], rem[PATH_MAX], *sub;
int ret;
snprintf(tmp, sizeof(tmp), "%s/../", bpf_get_tc_dir());
snprintf(rem, sizeof(rem), "%s/", todo);
sub = strtok(rem, "/");
if (pinning == PIN_OBJECT_NS) {
snprintf(pathname, sizeof(pathname), "%s/%s",
bpf_get_tc_dir(), bpf_get_obj_uid(NULL));
while (sub) {
if (strlen(tmp) + strlen(sub) + 2 > PATH_MAX)
return -EINVAL;
strcat(tmp, sub);
strcat(tmp, "/");
ret = mkdir(pathname, S_IRWXU);
ret = mkdir(tmp, S_IRWXU);
if (ret && errno != EEXIST) {
fprintf(stderr, "mkdir %s failed: %s\n", pathname,
fprintf(stderr, "mkdir %s failed: %s\n", tmp,
strerror(errno));
return ret;
}
sub = strtok(NULL, "/");
}
bpf_make_pathname(pathname, sizeof(pathname), name, pinning);
return 0;
}
static int bpf_place_pinned(int fd, const char *name,
const struct bpf_elf_ctx *ctx, uint32_t pinning)
{
char pathname[PATH_MAX];
const char *tmp;
int ret = 0;
if (bpf_no_pinning(ctx, pinning) || !bpf_get_tc_dir())
return 0;
if (pinning == PIN_OBJECT_NS)
ret = bpf_make_obj_path();
else if ((tmp = bpf_custom_pinning(ctx, pinning)))
ret = bpf_make_custom_path(tmp);
if (ret < 0)
return ret;
bpf_make_pathname(pathname, sizeof(pathname), name, ctx, pinning);
return bpf_obj_pin(fd, pathname);
}
......@@ -856,11 +925,11 @@ static int bpf_prog_attach(const char *section,
}
static int bpf_map_attach(const char *name, const struct bpf_elf_map *map,
bool verbose)
const struct bpf_elf_ctx *ctx, bool verbose)
{
int fd, ret;
fd = bpf_probe_pinned(name, map->pinning);
fd = bpf_probe_pinned(name, ctx, map->pinning);
if (fd > 0) {
ret = bpf_map_selfcheck_pinned(fd, map);
if (ret < 0) {
......@@ -889,7 +958,7 @@ static int bpf_map_attach(const char *name, const struct bpf_elf_map *map,
return fd;
}
ret = bpf_place_pinned(fd, name, map->pinning);
ret = bpf_place_pinned(fd, name, ctx, map->pinning);
if (ret < 0 && errno != EEXIST) {
fprintf(stderr, "Could not pin %s map: %s\n", name,
strerror(errno));
......@@ -940,7 +1009,8 @@ static int bpf_maps_attach_all(struct bpf_elf_ctx *ctx)
if (!map_name)
return -EIO;
fd = bpf_map_attach(map_name, &ctx->maps[i], ctx->verbose);
fd = bpf_map_attach(map_name, &ctx->maps[i], ctx,
ctx->verbose);
if (fd < 0)
return fd;
......@@ -1258,6 +1328,105 @@ static void bpf_save_finfo(struct bpf_elf_ctx *ctx)
ctx->stat.st_ino = st.st_ino;
}
static int bpf_read_pin_mapping(FILE *fp, uint32_t *id, char *path)
{
char buff[PATH_MAX];
while (fgets(buff, sizeof(buff), fp)) {
char *ptr = buff;
while (*ptr == ' ' || *ptr == '\t')
ptr++;
if (*ptr == '#' || *ptr == '\n' || *ptr == 0)
continue;
if (sscanf(ptr, "%i %s\n", id, path) != 2 &&
sscanf(ptr, "%i %s #", id, path) != 2) {
strcpy(path, ptr);
return -1;
}
return 1;
}
return 0;
}
static bool bpf_pinning_reserved(uint32_t pinning)
{
switch (pinning) {
case PIN_NONE:
case PIN_OBJECT_NS:
case PIN_GLOBAL_NS:
return true;
default:
return false;
}
}
static void bpf_hash_init(struct bpf_elf_ctx *ctx, const char *db_file)
{
struct bpf_hash_entry *entry;
char subpath[PATH_MAX];
uint32_t pinning;
FILE *fp;
int ret;
fp = fopen(db_file, "r");
if (!fp)
return;
memset(subpath, 0, sizeof(subpath));
while ((ret = bpf_read_pin_mapping(fp, &pinning, subpath))) {
if (ret == -1) {
fprintf(stderr, "Database %s is corrupted at: %s\n",
db_file, subpath);
fclose(fp);
return;
}
if (bpf_pinning_reserved(pinning)) {
fprintf(stderr, "Database %s, id %u is reserved - "
"ignoring!\n", db_file, pinning);
continue;
}
entry = malloc(sizeof(*entry));
if (!entry) {
fprintf(stderr, "No memory left for db entry!\n");
continue;
}
entry->pinning = pinning;
entry->subpath = strdup(subpath);
if (!entry->subpath) {
fprintf(stderr, "No memory left for db entry!\n");
free(entry);
continue;
}
entry->next = ctx->ht[pinning & (ARRAY_SIZE(ctx->ht) - 1)];
ctx->ht[pinning & (ARRAY_SIZE(ctx->ht) - 1)] = entry;
}
fclose(fp);
}
static void bpf_hash_destroy(struct bpf_elf_ctx *ctx)
{
struct bpf_hash_entry *entry;
int i;
for (i = 0; i < ARRAY_SIZE(ctx->ht); i++) {
while ((entry = ctx->ht[i]) != NULL) {
ctx->ht[i] = entry->next;
free((char *)entry->subpath);
free(entry);
}
}
}
static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname,
enum bpf_prog_type type, bool verbose)
{
......@@ -1295,6 +1464,8 @@ static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname,
}
bpf_save_finfo(ctx);
bpf_hash_init(ctx, CONFDIR "/bpf_pinning");
return 0;
out_elf:
elf_end(ctx->elf_fd);
......@@ -1331,6 +1502,7 @@ static void bpf_elf_ctx_destroy(struct bpf_elf_ctx *ctx, bool failure)
if (failure)
bpf_maps_teardown(ctx);
bpf_hash_destroy(ctx);
free(ctx->sec_done);
elf_end(ctx->elf_fd);
close(ctx->obj_fd);
......
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