Skip to content

Commit 06ee711

Browse files
Alexei Starovoitovborkmann
authored andcommitted
bpf: add verifier stats and log_level bit 2
In order to understand the verifier bottlenecks add various stats and extend log_level: log_level 1 and 2 are kept as-is: bit 0 - level=1 - print every insn and verifier state at branch points bit 1 - level=2 - print every insn and verifier state at every insn bit 2 - level=4 - print verifier error and stats at the end of verification When verifier rejects the program the libbpf is trying to load the program twice. Once with log_level=0 (no messages, only error code is reported to user space) and second time with log_level=1 to tell the user why the verifier rejected it. With introduction of bit 2 - level=4 the libbpf can choose to always use that level and load programs once, since the verification speed is not affected and in case of error the verbose message will be available. Note that the verifier stats are not part of uapi just like all other verbose messages. They're expected to change in the future. Signed-off-by: Alexei Starovoitov <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]>
1 parent e83b9f5 commit 06ee711

File tree

2 files changed

+73
-24
lines changed

2 files changed

+73
-24
lines changed

include/linux/bpf_verifier.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,12 @@ static inline bool bpf_verifier_log_full(const struct bpf_verifier_log *log)
248248
return log->len_used >= log->len_total - 1;
249249
}
250250

251+
#define BPF_LOG_LEVEL1 1
252+
#define BPF_LOG_LEVEL2 2
253+
#define BPF_LOG_STATS 4
254+
#define BPF_LOG_LEVEL (BPF_LOG_LEVEL1 | BPF_LOG_LEVEL2)
255+
#define BPF_LOG_MASK (BPF_LOG_LEVEL | BPF_LOG_STATS)
256+
251257
static inline bool bpf_verifier_log_needed(const struct bpf_verifier_log *log)
252258
{
253259
return log->level && log->ubuf && !bpf_verifier_log_full(log);
@@ -284,6 +290,21 @@ struct bpf_verifier_env {
284290
struct bpf_verifier_log log;
285291
struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 1];
286292
u32 subprog_cnt;
293+
/* number of instructions analyzed by the verifier */
294+
u32 insn_processed;
295+
/* total verification time */
296+
u64 verification_time;
297+
/* maximum number of verifier states kept in 'branching' instructions */
298+
u32 max_states_per_insn;
299+
/* total number of allocated verifier states */
300+
u32 total_states;
301+
/* some states are freed during program analysis.
302+
* this is peak number of states. this number dominates kernel
303+
* memory consumption during verification
304+
*/
305+
u32 peak_states;
306+
/* longest register parentage chain walked for liveness marking */
307+
u32 longest_mark_read_walk;
287308
};
288309

289310
__printf(2, 0) void bpf_verifier_vlog(struct bpf_verifier_log *log,

kernel/bpf/verifier.c

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,7 +1092,7 @@ static int check_subprogs(struct bpf_verifier_env *env)
10921092
*/
10931093
subprog[env->subprog_cnt].start = insn_cnt;
10941094

1095-
if (env->log.level > 1)
1095+
if (env->log.level & BPF_LOG_LEVEL2)
10961096
for (i = 0; i < env->subprog_cnt; i++)
10971097
verbose(env, "func#%d @%d\n", i, subprog[i].start);
10981098

@@ -1139,6 +1139,7 @@ static int mark_reg_read(struct bpf_verifier_env *env,
11391139
struct bpf_reg_state *parent)
11401140
{
11411141
bool writes = parent == state->parent; /* Observe write marks */
1142+
int cnt = 0;
11421143

11431144
while (parent) {
11441145
/* if read wasn't screened by an earlier write ... */
@@ -1155,7 +1156,11 @@ static int mark_reg_read(struct bpf_verifier_env *env,
11551156
state = parent;
11561157
parent = state->parent;
11571158
writes = true;
1159+
cnt++;
11581160
}
1161+
1162+
if (env->longest_mark_read_walk < cnt)
1163+
env->longest_mark_read_walk = cnt;
11591164
return 0;
11601165
}
11611166

@@ -1455,7 +1460,7 @@ static int check_map_access(struct bpf_verifier_env *env, u32 regno,
14551460
* need to try adding each of min_value and max_value to off
14561461
* to make sure our theoretical access will be safe.
14571462
*/
1458-
if (env->log.level)
1463+
if (env->log.level & BPF_LOG_LEVEL)
14591464
print_verifier_state(env, state);
14601465

14611466
/* The minimum value is only important with signed
@@ -2938,7 +2943,7 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
29382943
/* and go analyze first insn of the callee */
29392944
*insn_idx = target_insn;
29402945

2941-
if (env->log.level) {
2946+
if (env->log.level & BPF_LOG_LEVEL) {
29422947
verbose(env, "caller:\n");
29432948
print_verifier_state(env, caller);
29442949
verbose(env, "callee:\n");
@@ -2978,7 +2983,7 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
29782983
return err;
29792984

29802985
*insn_idx = callee->callsite + 1;
2981-
if (env->log.level) {
2986+
if (env->log.level & BPF_LOG_LEVEL) {
29822987
verbose(env, "returning from callee:\n");
29832988
print_verifier_state(env, callee);
29842989
verbose(env, "to caller at %d:\n", *insn_idx);
@@ -5001,7 +5006,7 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
50015006
insn->dst_reg);
50025007
return -EACCES;
50035008
}
5004-
if (env->log.level)
5009+
if (env->log.level & BPF_LOG_LEVEL)
50055010
print_verifier_state(env, this_branch->frame[this_branch->curframe]);
50065011
return 0;
50075012
}
@@ -6181,6 +6186,9 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
61816186
states_cnt++;
61826187
}
61836188

6189+
if (env->max_states_per_insn < states_cnt)
6190+
env->max_states_per_insn = states_cnt;
6191+
61846192
if (!env->allow_ptr_leaks && states_cnt > BPF_COMPLEXITY_LIMIT_STATES)
61856193
return 0;
61866194

@@ -6194,6 +6202,8 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
61946202
new_sl = kzalloc(sizeof(struct bpf_verifier_state_list), GFP_KERNEL);
61956203
if (!new_sl)
61966204
return -ENOMEM;
6205+
env->total_states++;
6206+
env->peak_states++;
61976207

61986208
/* add new state to the head of linked list */
61996209
new = &new_sl->state;
@@ -6278,8 +6288,7 @@ static int do_check(struct bpf_verifier_env *env)
62786288
struct bpf_verifier_state *state;
62796289
struct bpf_insn *insns = env->prog->insnsi;
62806290
struct bpf_reg_state *regs;
6281-
int insn_cnt = env->prog->len, i;
6282-
int insn_processed = 0;
6291+
int insn_cnt = env->prog->len;
62836292
bool do_print_state = false;
62846293

62856294
env->prev_linfo = NULL;
@@ -6314,10 +6323,10 @@ static int do_check(struct bpf_verifier_env *env)
63146323
insn = &insns[env->insn_idx];
63156324
class = BPF_CLASS(insn->code);
63166325

6317-
if (++insn_processed > BPF_COMPLEXITY_LIMIT_INSNS) {
6326+
if (++env->insn_processed > BPF_COMPLEXITY_LIMIT_INSNS) {
63186327
verbose(env,
63196328
"BPF program is too large. Processed %d insn\n",
6320-
insn_processed);
6329+
env->insn_processed);
63216330
return -E2BIG;
63226331
}
63236332

@@ -6326,7 +6335,7 @@ static int do_check(struct bpf_verifier_env *env)
63266335
return err;
63276336
if (err == 1) {
63286337
/* found equivalent state, can prune the search */
6329-
if (env->log.level) {
6338+
if (env->log.level & BPF_LOG_LEVEL) {
63306339
if (do_print_state)
63316340
verbose(env, "\nfrom %d to %d%s: safe\n",
63326341
env->prev_insn_idx, env->insn_idx,
@@ -6344,8 +6353,9 @@ static int do_check(struct bpf_verifier_env *env)
63446353
if (need_resched())
63456354
cond_resched();
63466355

6347-
if (env->log.level > 1 || (env->log.level && do_print_state)) {
6348-
if (env->log.level > 1)
6356+
if (env->log.level & BPF_LOG_LEVEL2 ||
6357+
(env->log.level & BPF_LOG_LEVEL && do_print_state)) {
6358+
if (env->log.level & BPF_LOG_LEVEL2)
63496359
verbose(env, "%d:", env->insn_idx);
63506360
else
63516361
verbose(env, "\nfrom %d to %d%s:",
@@ -6356,7 +6366,7 @@ static int do_check(struct bpf_verifier_env *env)
63566366
do_print_state = false;
63576367
}
63586368

6359-
if (env->log.level) {
6369+
if (env->log.level & BPF_LOG_LEVEL) {
63606370
const struct bpf_insn_cbs cbs = {
63616371
.cb_print = verbose,
63626372
.private_data = env,
@@ -6621,16 +6631,6 @@ static int do_check(struct bpf_verifier_env *env)
66216631
env->insn_idx++;
66226632
}
66236633

6624-
verbose(env, "processed %d insns (limit %d), stack depth ",
6625-
insn_processed, BPF_COMPLEXITY_LIMIT_INSNS);
6626-
for (i = 0; i < env->subprog_cnt; i++) {
6627-
u32 depth = env->subprog_info[i].stack_depth;
6628-
6629-
verbose(env, "%d", depth);
6630-
if (i + 1 < env->subprog_cnt)
6631-
verbose(env, "+");
6632-
}
6633-
verbose(env, "\n");
66346634
env->prog->aux->stack_depth = env->subprog_info[0].stack_depth;
66356635
return 0;
66366636
}
@@ -7854,9 +7854,34 @@ static void free_states(struct bpf_verifier_env *env)
78547854
kfree(env->explored_states);
78557855
}
78567856

7857+
static void print_verification_stats(struct bpf_verifier_env *env)
7858+
{
7859+
int i;
7860+
7861+
if (env->log.level & BPF_LOG_STATS) {
7862+
verbose(env, "verification time %lld usec\n",
7863+
div_u64(env->verification_time, 1000));
7864+
verbose(env, "stack depth ");
7865+
for (i = 0; i < env->subprog_cnt; i++) {
7866+
u32 depth = env->subprog_info[i].stack_depth;
7867+
7868+
verbose(env, "%d", depth);
7869+
if (i + 1 < env->subprog_cnt)
7870+
verbose(env, "+");
7871+
}
7872+
verbose(env, "\n");
7873+
}
7874+
verbose(env, "processed %d insns (limit %d) max_states_per_insn %d "
7875+
"total_states %d peak_states %d mark_read %d\n",
7876+
env->insn_processed, BPF_COMPLEXITY_LIMIT_INSNS,
7877+
env->max_states_per_insn, env->total_states,
7878+
env->peak_states, env->longest_mark_read_walk);
7879+
}
7880+
78577881
int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
78587882
union bpf_attr __user *uattr)
78597883
{
7884+
u64 start_time = ktime_get_ns();
78607885
struct bpf_verifier_env *env;
78617886
struct bpf_verifier_log *log;
78627887
int i, len, ret = -EINVAL;
@@ -7899,7 +7924,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
78997924
ret = -EINVAL;
79007925
/* log attributes have to be sane */
79017926
if (log->len_total < 128 || log->len_total > UINT_MAX >> 8 ||
7902-
!log->level || !log->ubuf)
7927+
!log->level || !log->ubuf || log->level & ~BPF_LOG_MASK)
79037928
goto err_unlock;
79047929
}
79057930

@@ -7980,6 +8005,9 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
79808005
if (ret == 0)
79818006
ret = fixup_call_args(env);
79828007

8008+
env->verification_time = ktime_get_ns() - start_time;
8009+
print_verification_stats(env);
8010+
79838011
if (log->level && bpf_verifier_log_full(log))
79848012
ret = -ENOSPC;
79858013
if (log->level && !log->ubuf) {

0 commit comments

Comments
 (0)