mirror of
				https://git.proxmox.com/git/mirror_iproute2
				synced 2025-11-04 02:56:43 +00:00 
			
		
		
		
	Merge branch 'master' into net-next
This commit is contained in:
		
						commit
						08f5fdb201
					
				@ -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
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								ip/ipnetns.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								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();
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										47
									
								
								ip/iproute.c
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								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)
 | 
			
		||||
 | 
			
		||||
@ -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]);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										281
									
								
								lib/bpf.c
									
									
									
									
									
								
							
							
						
						
									
										281
									
								
								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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user