diff options
Diffstat (limited to 'tools/lib/bpf/bpf.c')
| -rw-r--r-- | tools/lib/bpf/bpf.c | 114 | 
1 files changed, 108 insertions, 6 deletions
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 03f9bcc4ef50..3caaa3428774 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -173,9 +173,35 @@ int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name,  					  -1);  } +static void * +alloc_zero_tailing_info(const void *orecord, __u32 cnt, +			__u32 actual_rec_size, __u32 expected_rec_size) +{ +	__u64 info_len = actual_rec_size * cnt; +	void *info, *nrecord; +	int i; + +	info = malloc(info_len); +	if (!info) +		return NULL; + +	/* zero out bytes kernel does not understand */ +	nrecord = info; +	for (i = 0; i < cnt; i++) { +		memcpy(nrecord, orecord, expected_rec_size); +		memset(nrecord + expected_rec_size, 0, +		       actual_rec_size - expected_rec_size); +		orecord += actual_rec_size; +		nrecord += actual_rec_size; +	} + +	return info; +} +  int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,  			   char *log_buf, size_t log_buf_sz)  { +	void *finfo = NULL, *linfo = NULL;  	union bpf_attr attr;  	__u32 name_len;  	int fd; @@ -196,19 +222,72 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,  	attr.log_level = 0;  	attr.kern_version = load_attr->kern_version;  	attr.prog_ifindex = load_attr->prog_ifindex; +	attr.prog_btf_fd = load_attr->prog_btf_fd; +	attr.func_info_rec_size = load_attr->func_info_rec_size; +	attr.func_info_cnt = load_attr->func_info_cnt; +	attr.func_info = ptr_to_u64(load_attr->func_info); +	attr.line_info_rec_size = load_attr->line_info_rec_size; +	attr.line_info_cnt = load_attr->line_info_cnt; +	attr.line_info = ptr_to_u64(load_attr->line_info);  	memcpy(attr.prog_name, load_attr->name,  	       min(name_len, BPF_OBJ_NAME_LEN - 1));  	fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); -	if (fd >= 0 || !log_buf || !log_buf_sz) +	if (fd >= 0)  		return fd; +	/* After bpf_prog_load, the kernel may modify certain attributes +	 * to give user space a hint how to deal with loading failure. +	 * Check to see whether we can make some changes and load again. +	 */ +	while (errno == E2BIG && (!finfo || !linfo)) { +		if (!finfo && attr.func_info_cnt && +		    attr.func_info_rec_size < load_attr->func_info_rec_size) { +			/* try with corrected func info records */ +			finfo = alloc_zero_tailing_info(load_attr->func_info, +							load_attr->func_info_cnt, +							load_attr->func_info_rec_size, +							attr.func_info_rec_size); +			if (!finfo) +				goto done; + +			attr.func_info = ptr_to_u64(finfo); +			attr.func_info_rec_size = load_attr->func_info_rec_size; +		} else if (!linfo && attr.line_info_cnt && +			   attr.line_info_rec_size < +			   load_attr->line_info_rec_size) { +			linfo = alloc_zero_tailing_info(load_attr->line_info, +							load_attr->line_info_cnt, +							load_attr->line_info_rec_size, +							attr.line_info_rec_size); +			if (!linfo) +				goto done; + +			attr.line_info = ptr_to_u64(linfo); +			attr.line_info_rec_size = load_attr->line_info_rec_size; +		} else { +			break; +		} + +		fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); + +		if (fd >= 0) +			goto done; +	} + +	if (!log_buf || !log_buf_sz) +		goto done; +  	/* Try again with log */  	attr.log_buf = ptr_to_u64(log_buf);  	attr.log_size = log_buf_sz;  	attr.log_level = 1;  	log_buf[0] = 0; -	return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); +	fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); +done: +	free(finfo); +	free(linfo); +	return fd;  }  int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, @@ -231,9 +310,9 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,  }  int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns, -		       size_t insns_cnt, int strict_alignment, -		       const char *license, __u32 kern_version, -		       char *log_buf, size_t log_buf_sz, int log_level) +		       size_t insns_cnt, __u32 prog_flags, const char *license, +		       __u32 kern_version, char *log_buf, size_t log_buf_sz, +		       int log_level)  {  	union bpf_attr attr; @@ -247,7 +326,7 @@ int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,  	attr.log_level = log_level;  	log_buf[0] = 0;  	attr.kern_version = kern_version; -	attr.prog_flags = strict_alignment ? BPF_F_STRICT_ALIGNMENT : 0; +	attr.prog_flags = prog_flags;  	return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));  } @@ -415,6 +494,29 @@ int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size,  	return ret;  } +int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr) +{ +	union bpf_attr attr; +	int ret; + +	if (!test_attr->data_out && test_attr->data_size_out > 0) +		return -EINVAL; + +	bzero(&attr, sizeof(attr)); +	attr.test.prog_fd = test_attr->prog_fd; +	attr.test.data_in = ptr_to_u64(test_attr->data_in); +	attr.test.data_out = ptr_to_u64(test_attr->data_out); +	attr.test.data_size_in = test_attr->data_size_in; +	attr.test.data_size_out = test_attr->data_size_out; +	attr.test.repeat = test_attr->repeat; + +	ret = sys_bpf(BPF_PROG_TEST_RUN, &attr, sizeof(attr)); +	test_attr->data_size_out = attr.test.data_size_out; +	test_attr->retval = attr.test.retval; +	test_attr->duration = attr.test.duration; +	return ret; +} +  int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id)  {  	union bpf_attr attr;  | 
