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;
enum bpf_prog_type type;
bool verbose;
struct bpf_elf_st stat;
+ struct bpf_hash_entry *ht[256];
};
struct bpf_elf_sec_data {
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:
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);
}
}
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) {
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));
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;
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)
{
}
bpf_save_finfo(ctx);
+ bpf_hash_init(ctx, CONFDIR "/bpf_pinning");
+
return 0;
out_elf:
elf_end(ctx->elf_fd);
if (failure)
bpf_maps_teardown(ctx);
+ bpf_hash_destroy(ctx);
free(ctx->sec_done);
elf_end(ctx->elf_fd);
close(ctx->obj_fd);