diff --git a/doc/ip-cref.tex b/doc/ip-cref.tex index 242cc266..179baa2f 100644 --- a/doc/ip-cref.tex +++ b/doc/ip-cref.tex @@ -2524,6 +2524,13 @@ It must be an address on another interface of this host. It is enabled by default. Note that a fixed ttl is incompatible with this option: tunnelling with a fixed ttl always makes pmtu discovery. +\item \verb|ignore-df| + +--- (only GRE tunnels) enable IPv4 DF flag suppression on this tunnel. + If is disabled by default. Enabling this option will cause IPv4 + payloads to be handled like any other GRE payload, + regardless of the DF flag. + \item \verb|key K|, \verb|ikey K|, \verb|okey K| --- (only GRE tunnels) use keyed GRE with key \verb|K|. \verb|K| is diff --git a/ip/ipnetns.c b/ip/ipnetns.c index 0b0378ab..42549944 100644 --- a/ip/ipnetns.c +++ b/ip/ipnetns.c @@ -766,6 +766,11 @@ static int netns_monitor(int argc, char **argv) return 0; } +static int invalid_name(const char *name) +{ + return strchr(name, '/') || !strcmp(name, ".") || !strcmp(name, ".."); +} + int do_netns(int argc, char **argv) { netns_nsid_socket_init(); @@ -775,6 +780,11 @@ int do_netns(int argc, char **argv) return netns_list(0, NULL); } + if (argc > 1 && invalid_name(argv[1])) { + fprintf(stderr, "Invalid netns name \"%s\"\n", argv[1]); + exit(-1); + } + if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) || (matches(*argv, "lst") == 0)) { netns_map_init(); diff --git a/ip/iproute.c b/ip/iproute.c index a735d281..cb695ad4 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -137,7 +137,7 @@ static int flush_update(void) { if (rtnl_send_check(&rth, filter.flushb, filter.flushp) < 0) { perror("Failed to send flush request"); - return -1; + return -2; } filter.flushp = 0; return 0; @@ -319,6 +319,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) struct rtattr *tb[RTA_MAX+1]; int host_len, family; __u32 table; + int ret; SPRINT_BUF(b1); static int hz; @@ -348,8 +349,8 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) struct nlmsghdr *fn; if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { - if (flush_update()) - return -1; + if ((ret = flush_update()) < 0) + return ret; } fn = (struct nlmsghdr *)(filter.flushb + NLMSG_ALIGN(filter.flushp)); memcpy(fn, n, n->nlmsg_len); @@ -764,7 +765,7 @@ static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r, NEXT_ARG(); if ((rtnh->rtnh_ifindex = ll_name_to_index(*argv)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", *argv); - exit(1); + return -1; } } else if (strcmp(*argv, "weight") == 0) { unsigned int w; @@ -1396,6 +1397,7 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action) char *od = NULL; unsigned int mark = 0; rtnl_filter_t filter_fn; + int ret; if (action == IPROUTE_SAVE) { if (save_route_prep()) @@ -1604,12 +1606,12 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action) for (;;) { if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) { perror("Cannot send dump request"); - exit(1); + return -2; } filter.flushed = 0; if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) { fprintf(stderr, "Flush terminated\n"); - exit(1); + return -2; } if (filter.flushed == 0) { if (show_stats) { @@ -1622,13 +1624,13 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action) return 0; } round++; - if (flush_update() < 0) - exit(1); + if ((ret = flush_update()) < 0) + return ret; if (time(0) - start > 30) { printf("\n*** Flush not completed after %ld seconds, %d entries remain ***\n", (long)(time(0) - start), filter.flushed); - exit(1); + return -1; } if (show_stats) { @@ -1641,21 +1643,21 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action) if (!filter.cloned) { if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) { perror("Cannot send dump request"); - exit(1); + return -2; } } else { if (rtnl_rtcache_request(&rth, do_ipv6) < 0) { perror("Cannot send dump request"); - exit(1); + return -2; } } if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); - exit(1); + return -2; } - exit(0); + return 0; } @@ -1761,7 +1763,7 @@ static int iproute_get(int argc, char **argv) if (req.r.rtm_dst_len == 0) { fprintf(stderr, "need at least a destination address\n"); - exit(1); + return -1; } if (idev || odev) { @@ -1918,12 +1920,12 @@ static int iproute_restore(void) int pos, prio; if (route_dump_check_magic()) - exit(-1); + return -1; pos = ftell(stdin); if (pos == -1) { perror("Failed to restore: ftell"); - exit(-1); + return -1; } for (prio = 0; prio < 3; prio++) { @@ -1931,15 +1933,15 @@ static int iproute_restore(void) err = rtnl_from_file(stdin, &restore_handler, &prio); if (err) - exit(err); + return -2; if (fseek(stdin, pos, SEEK_SET) == -1) { perror("Failed to restore: fseek"); - exit(-1); + return -1; } } - exit(0); + return 0; } static int show_handler(const struct sockaddr_nl *nl, @@ -1953,9 +1955,12 @@ static int show_handler(const struct sockaddr_nl *nl, static int iproute_showdump(void) { if (route_dump_check_magic()) - exit(-1); + return -1; - exit(rtnl_from_file(stdin, &show_handler, NULL)); + if (rtnl_from_file(stdin, &show_handler, NULL)) + return -2; + + return 0; } void iproute_reset_filter(int ifindex) diff --git a/ip/link_gre.c b/ip/link_gre.c index 82df9006..c2ec5f26 100644 --- a/ip/link_gre.c +++ b/ip/link_gre.c @@ -34,6 +34,7 @@ static void print_usage(FILE *f) " [ ttl TTL ]\n" " [ tos TOS ]\n" " [ [no]pmtudisc ]\n" + " [ [no]ignore-df ]\n" " [ dev PHYS_DEV ]\n" " [ noencap ]\n" " [ encap { fou | gue | none } ]\n" @@ -93,6 +94,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, __u16 encapsport = 0; __u16 encapdport = 0; __u8 metadata = 0; + __u8 ignore_df = 0; __u32 fwmark = 0; if (!(n->nlmsg_flags & NLM_F_CREATE)) { @@ -164,6 +166,10 @@ get_failed: if (greinfo[IFLA_GRE_COLLECT_METADATA]) metadata = 1; + if (greinfo[IFLA_GRE_IGNORE_DF]) + ignore_df = + !!rta_getattr_u8(greinfo[IFLA_GRE_IGNORE_DF]); + if (greinfo[IFLA_GRE_FWMARK]) fwmark = rta_getattr_u32(greinfo[IFLA_GRE_FWMARK]); } @@ -311,6 +317,13 @@ get_failed: encapflags |= ~TUNNEL_ENCAP_FLAG_REMCSUM; } else if (strcmp(*argv, "external") == 0) { metadata = 1; + } else if (strcmp(*argv, "ignore-df") == 0) { + ignore_df = 1; + } else if (strcmp(*argv, "noignore-df") == 0) { + /* + *only the lsb is significant, use 2 for presence + */ + ignore_df = 2; } else if (strcmp(*argv, "fwmark") == 0) { NEXT_ARG(); if (get_u32(&fwmark, *argv, 0)) @@ -355,6 +368,9 @@ get_failed: addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport)); addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport)); + if (ignore_df) + addattr8(n, 1024, IFLA_GRE_IGNORE_DF, ignore_df & 1); + return 0; } @@ -454,6 +470,9 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) else fputs("external ", f); + if (tb[IFLA_GRE_IGNORE_DF] && rta_getattr_u8(tb[IFLA_GRE_IGNORE_DF])) + fputs("ignore-df ", f); + if (tb[IFLA_GRE_ENCAP_TYPE] && rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) { __u16 type = rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]); diff --git a/lib/bpf.c b/lib/bpf.c index 7eb5cd96..e7a4d12f 100644 --- a/lib/bpf.c +++ b/lib/bpf.c @@ -344,15 +344,24 @@ static void bpf_map_pin_report(const struct bpf_elf_map *pin, fprintf(stderr, "\n"); } -static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map, - int length, enum bpf_prog_type type) +struct bpf_prog_data { + unsigned int type; + unsigned int jited; +}; + +struct bpf_map_ext { + struct bpf_prog_data owner; +}; + +static int bpf_derive_elf_map_from_fdinfo(int fd, struct bpf_elf_map *map, + struct bpf_map_ext *ext) { + unsigned int val, owner_type = 0, owner_jited = 0; char file[PATH_MAX], buff[4096]; - struct bpf_elf_map tmp = {}, zero = {}; - unsigned int val, owner_type = 0; FILE *fp; snprintf(file, sizeof(file), "/proc/%d/fdinfo/%d", getpid(), fd); + memset(map, 0, sizeof(*map)); fp = fopen(file, "r"); if (!fp) { @@ -362,27 +371,48 @@ static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map, while (fgets(buff, sizeof(buff), fp)) { if (sscanf(buff, "map_type:\t%u", &val) == 1) - tmp.type = val; + map->type = val; else if (sscanf(buff, "key_size:\t%u", &val) == 1) - tmp.size_key = val; + map->size_key = val; else if (sscanf(buff, "value_size:\t%u", &val) == 1) - tmp.size_value = val; + map->size_value = val; else if (sscanf(buff, "max_entries:\t%u", &val) == 1) - tmp.max_elem = val; + map->max_elem = val; else if (sscanf(buff, "map_flags:\t%i", &val) == 1) - tmp.flags = val; + map->flags = val; else if (sscanf(buff, "owner_prog_type:\t%i", &val) == 1) owner_type = val; + else if (sscanf(buff, "owner_jited:\t%i", &val) == 1) + owner_jited = val; } fclose(fp); + if (ext) { + memset(ext, 0, sizeof(*ext)); + ext->owner.type = owner_type; + ext->owner.jited = owner_jited; + } + + return 0; +} + +static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map, + struct bpf_map_ext *ext, int length, + enum bpf_prog_type type) +{ + struct bpf_elf_map tmp, zero = {}; + int ret; + + ret = bpf_derive_elf_map_from_fdinfo(fd, &tmp, ext); + if (ret < 0) + return ret; /* The decision to reject this is on kernel side eventually, but * at least give the user a chance to know what's wrong. */ - if (owner_type && owner_type != type) + if (ext->owner.type && ext->owner.type != type) fprintf(stderr, "Program array map owner types differ: %u (obj) != %u (pin)\n", - type, owner_type); + type, ext->owner.type); if (!memcmp(&tmp, map, length)) { return 0; @@ -429,6 +459,24 @@ static int bpf_mnt_fs(const char *target) return 0; } +static int bpf_mnt_check_target(const char *target) +{ + struct stat sb = {}; + int ret; + + ret = stat(target, &sb); + if (ret) { + ret = mkdir(target, S_IRWXU); + if (ret) { + fprintf(stderr, "mkdir %s failed: %s\n", target, + strerror(errno)); + return ret; + } + } + + return 0; +} + static int bpf_valid_mntpt(const char *mnt, unsigned long magic) { struct statfs st_fs; @@ -441,6 +489,21 @@ static int bpf_valid_mntpt(const char *mnt, unsigned long magic) return 0; } +static const char *bpf_find_mntpt_single(unsigned long magic, char *mnt, + int len, const char *mntpt) +{ + int ret; + + ret = bpf_valid_mntpt(mntpt, magic); + if (!ret) { + strncpy(mnt, mntpt, len - 1); + mnt[len - 1] = 0; + return mnt; + } + + return NULL; +} + static const char *bpf_find_mntpt(const char *fstype, unsigned long magic, char *mnt, int len, const char * const *known_mnts) @@ -452,11 +515,8 @@ static const char *bpf_find_mntpt(const char *fstype, unsigned long magic, if (known_mnts) { ptr = known_mnts; while (*ptr) { - if (bpf_valid_mntpt(*ptr, magic) == 0) { - strncpy(mnt, *ptr, len - 1); - mnt[len - 1] = 0; + if (bpf_find_mntpt_single(magic, mnt, len, *ptr)) return mnt; - } ptr++; } } @@ -634,6 +694,7 @@ static const char *bpf_get_work_dir(enum bpf_prog_type type) static char bpf_wrk_dir[PATH_MAX]; static const char *mnt; static bool bpf_mnt_cached; + const char *mnt_env = getenv(BPF_ENV_MNT); static const char * const bpf_known_mnts[] = { BPF_DIR_MNT, "/bpf", @@ -652,13 +713,17 @@ static const char *bpf_get_work_dir(enum bpf_prog_type type) return out; } - mnt = bpf_find_mntpt("bpf", BPF_FS_MAGIC, bpf_tmp, sizeof(bpf_tmp), - bpf_known_mnts); + if (mnt_env) + mnt = bpf_find_mntpt_single(BPF_FS_MAGIC, bpf_tmp, + sizeof(bpf_tmp), mnt_env); + else + mnt = bpf_find_mntpt("bpf", BPF_FS_MAGIC, bpf_tmp, + sizeof(bpf_tmp), bpf_known_mnts); if (!mnt) { - mnt = getenv(BPF_ENV_MNT); - if (!mnt) - mnt = BPF_DIR_MNT; - ret = bpf_mnt_fs(mnt); + mnt = mnt_env ? : BPF_DIR_MNT; + ret = bpf_mnt_check_target(mnt); + if (!ret) + ret = bpf_mnt_fs(mnt); if (ret) { mnt = NULL; goto out; @@ -882,6 +947,7 @@ int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv) .argc = argc, .argv = argv, }; + struct bpf_map_ext ext = {}; int ret, prog_fd, map_fd; enum bpf_mode mode; uint32_t map_key; @@ -908,7 +974,7 @@ int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv) goto out_prog; } - ret = bpf_map_selfcheck_pinned(map_fd, &test, + ret = bpf_map_selfcheck_pinned(map_fd, &test, &ext, offsetof(struct bpf_elf_map, max_elem), type); if (ret < 0) { @@ -981,7 +1047,12 @@ struct bpf_hash_entry { struct bpf_hash_entry *next; }; +struct bpf_config { + unsigned int jit_enabled; +}; + struct bpf_elf_ctx { + struct bpf_config cfg; Elf *elf_fd; GElf_Ehdr elf_hdr; Elf_Data *sym_tab; @@ -989,6 +1060,7 @@ struct bpf_elf_ctx { int obj_fd; int map_fds[ELF_MAX_MAPS]; struct bpf_elf_map maps[ELF_MAX_MAPS]; + struct bpf_map_ext maps_ext[ELF_MAX_MAPS]; int sym_num; int map_num; int map_len; @@ -1425,39 +1497,6 @@ static int bpf_find_map_id(const struct bpf_elf_ctx *ctx, uint32_t id) return -ENOENT; } -static int bpf_derive_elf_map_from_fdinfo(int fd, struct bpf_elf_map *map) -{ - char file[PATH_MAX], buff[4096]; - unsigned int val; - FILE *fp; - - snprintf(file, sizeof(file), "/proc/%d/fdinfo/%d", getpid(), fd); - - memset(map, 0, sizeof(*map)); - - fp = fopen(file, "r"); - if (!fp) { - fprintf(stderr, "No procfs support?!\n"); - return -EIO; - } - - while (fgets(buff, sizeof(buff), fp)) { - if (sscanf(buff, "map_type:\t%u", &val) == 1) - map->type = val; - else if (sscanf(buff, "key_size:\t%u", &val) == 1) - map->size_key = val; - else if (sscanf(buff, "value_size:\t%u", &val) == 1) - map->size_value = val; - else if (sscanf(buff, "max_entries:\t%u", &val) == 1) - map->max_elem = val; - else if (sscanf(buff, "map_flags:\t%i", &val) == 1) - map->flags = val; - } - - fclose(fp); - return 0; -} - static void bpf_report_map_in_map(int outer_fd, int inner_fd, uint32_t idx) { struct bpf_elf_map outer_map; @@ -1465,7 +1504,7 @@ static void bpf_report_map_in_map(int outer_fd, int inner_fd, uint32_t idx) fprintf(stderr, "Cannot insert map into map! "); - ret = bpf_derive_elf_map_from_fdinfo(outer_fd, &outer_map); + ret = bpf_derive_elf_map_from_fdinfo(outer_fd, &outer_map, NULL); if (!ret) { if (idx >= outer_map.max_elem && outer_map.type == BPF_MAP_TYPE_ARRAY_OF_MAPS) { @@ -1484,14 +1523,15 @@ static bool bpf_is_map_in_map_type(const struct bpf_elf_map *map) map->type == BPF_MAP_TYPE_HASH_OF_MAPS; } -static int bpf_map_attach(const char *name, const struct bpf_elf_map *map, - struct bpf_elf_ctx *ctx, int *have_map_in_map) +static int bpf_map_attach(const char *name, struct bpf_elf_ctx *ctx, + const struct bpf_elf_map *map, struct bpf_map_ext *ext, + int *have_map_in_map) { int fd, ret, map_inner_fd = 0; fd = bpf_probe_pinned(name, ctx, map->pinning); if (fd > 0) { - ret = bpf_map_selfcheck_pinned(fd, map, + ret = bpf_map_selfcheck_pinned(fd, map, ext, offsetof(struct bpf_elf_map, id), ctx->type); if (ret < 0) { @@ -1581,8 +1621,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, - &have_map_in_map); + fd = bpf_map_attach(map_name, ctx, &ctx->maps[i], + &ctx->maps_ext[i], &have_map_in_map); if (fd < 0) return fd; @@ -1597,8 +1637,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, - NULL); + fd = bpf_map_attach(map_name, ctx, &ctx->maps[i], + &ctx->maps_ext[i], NULL); if (fd < 0) return fd; @@ -1901,9 +1941,15 @@ static int bpf_fetch_prog(struct bpf_elf_ctx *ctx, const char *section, return fd; } +struct bpf_tail_call_props { + unsigned int total; + unsigned int jited; +}; + static int bpf_apply_relo_data(struct bpf_elf_ctx *ctx, struct bpf_elf_sec_data *data_relo, - struct bpf_elf_sec_data *data_insn) + struct bpf_elf_sec_data *data_insn, + struct bpf_tail_call_props *props) { Elf_Data *idata = data_insn->sec_data; GElf_Shdr *rhdr = &data_relo->sec_hdr; @@ -1943,6 +1989,13 @@ static int bpf_apply_relo_data(struct bpf_elf_ctx *ctx, return -EINVAL; if (!ctx->map_fds[rmap]) return -EINVAL; + if (ctx->maps[rmap].type == BPF_MAP_TYPE_PROG_ARRAY) { + props->total++; + if (ctx->maps_ext[rmap].owner.jited || + (ctx->maps_ext[rmap].owner.type == 0 && + ctx->cfg.jit_enabled)) + props->jited++; + } if (ctx->verbose) fprintf(stderr, "Map \'%s\' (%d) injected into prog section \'%s\' at offset %u!\n", @@ -1964,6 +2017,8 @@ static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section, int ret, idx, i, fd = -1; for (i = 1; i < ctx->elf_hdr.e_shnum; i++) { + struct bpf_tail_call_props props = {}; + ret = bpf_fill_section_data(ctx, i, &data_relo); if (ret < 0 || data_relo.sec_hdr.sh_type != SHT_REL) continue; @@ -1979,7 +2034,7 @@ static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section, *sseen = true; - ret = bpf_apply_relo_data(ctx, &data_relo, &data_insn); + ret = bpf_apply_relo_data(ctx, &data_relo, &data_insn, &props); if (ret < 0) { *lderr = true; return ret; @@ -1994,6 +2049,16 @@ static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section, fd = bpf_prog_attach(section, &prog, ctx); if (fd < 0) { *lderr = true; + if (props.total) { + if (ctx->cfg.jit_enabled && + props.total != props.jited) + fprintf(stderr, "JIT enabled, but only %u/%u tail call maps in the program have JITed owner!\n", + props.jited, props.total); + if (!ctx->cfg.jit_enabled && + props.jited) + fprintf(stderr, "JIT disabled, but %u/%u tail call maps in the program have JITed owner!\n", + props.jited, props.total); + } return fd; } @@ -2031,6 +2096,51 @@ static int bpf_find_map_by_id(struct bpf_elf_ctx *ctx, uint32_t id) return -1; } +struct bpf_jited_aux { + int prog_fd; + int map_fd; + struct bpf_prog_data prog; + struct bpf_map_ext map; +}; + +static int bpf_derive_prog_from_fdinfo(int fd, struct bpf_prog_data *prog) +{ + char file[PATH_MAX], buff[4096]; + unsigned int val; + FILE *fp; + + snprintf(file, sizeof(file), "/proc/%d/fdinfo/%d", getpid(), fd); + memset(prog, 0, sizeof(*prog)); + + fp = fopen(file, "r"); + if (!fp) { + fprintf(stderr, "No procfs support?!\n"); + return -EIO; + } + + while (fgets(buff, sizeof(buff), fp)) { + if (sscanf(buff, "prog_type:\t%u", &val) == 1) + prog->type = val; + else if (sscanf(buff, "prog_jited:\t%u", &val) == 1) + prog->jited = val; + } + + fclose(fp); + return 0; +} + +static int bpf_tail_call_get_aux(struct bpf_jited_aux *aux) +{ + struct bpf_elf_map tmp; + int ret; + + ret = bpf_derive_elf_map_from_fdinfo(aux->map_fd, &tmp, &aux->map); + if (!ret) + ret = bpf_derive_prog_from_fdinfo(aux->prog_fd, &aux->prog); + + return ret; +} + static int bpf_fill_prog_arrays(struct bpf_elf_ctx *ctx) { struct bpf_elf_sec_data data; @@ -2060,10 +2170,31 @@ static int bpf_fill_prog_arrays(struct bpf_elf_ctx *ctx) ret = bpf_map_update(ctx->map_fds[idx], &key_id, &fd, BPF_ANY); if (ret < 0) { - if (errno == E2BIG) + struct bpf_jited_aux aux = {}; + + ret = -errno; + if (errno == E2BIG) { fprintf(stderr, "Tail call key %u for map %u out of bounds?\n", key_id, map_id); - return -errno; + return ret; + } + + aux.map_fd = ctx->map_fds[idx]; + aux.prog_fd = fd; + + if (bpf_tail_call_get_aux(&aux)) + return ret; + if (!aux.map.owner.type) + return ret; + + if (aux.prog.type != aux.map.owner.type) + fprintf(stderr, "Tail call map owned by prog type %u, but prog type is %u!\n", + aux.map.owner.type, aux.prog.type); + if (aux.prog.jited != aux.map.owner.jited) + fprintf(stderr, "Tail call map %s jited, but prog %s!\n", + aux.map.owner.jited ? "is" : "not", + aux.prog.jited ? "is" : "not"); + return ret; } ctx->sec_done[i] = true; @@ -2221,6 +2352,21 @@ static int bpf_elf_check_ehdr(const struct bpf_elf_ctx *ctx) return 0; } +static void bpf_get_cfg(struct bpf_elf_ctx *ctx) +{ + static const char *path_jit = "/proc/sys/net/core/bpf_jit_enable"; + int fd; + + fd = open(path_jit, O_RDONLY); + if (fd > 0) { + char tmp[16] = {}; + + if (read(fd, tmp, sizeof(tmp)) > 0) + ctx->cfg.jit_enabled = atoi(tmp); + close(fd); + } +} + static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname, enum bpf_prog_type type, bool verbose) { @@ -2231,6 +2377,7 @@ static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname, return ret; memset(ctx, 0, sizeof(*ctx)); + bpf_get_cfg(ctx); ctx->verbose = verbose; ctx->type = type; diff --git a/man/man8/ip-tunnel.8 b/man/man8/ip-tunnel.8 index 4938c740..7ddbffb2 100644 --- a/man/man8/ip-tunnel.8 +++ b/man/man8/ip-tunnel.8 @@ -49,6 +49,7 @@ ip-tunnel - tunnel configuration .BR 6rd-reset " ]" .br .RB "[ [" no "]" pmtudisc " ]" +.RB "[ [" no "]" ignore-df " ]" .RB "[ " dev .IR PHYS_DEV " ]" @@ -175,6 +176,14 @@ It is enabled by default. Note that a fixed ttl is incompatible with this option: tunneling with a fixed ttl always makes pmtu discovery. +.TP +.B ignore-df +enable IPv4 DF suppression on this tunnel. +Normally datagrams that exceed the MTU will be fragmented; the presence +of the DF flag inhibits this, resulting instead in an ICMP Unreachable +(Fragmentation Required) message. Enabling this attribute casues the +DF flag to be ignored. + .TP .BI key " K" .TP