]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
selftests/bpf: Separate var preset parsing in veristat
authorMykyta Yatsenko <yatsenko@meta.com>
Wed, 25 Jun 2025 16:59:02 +0000 (17:59 +0100)
committerAndrii Nakryiko <andrii@kernel.org>
Thu, 26 Jun 2025 17:28:50 +0000 (10:28 -0700)
Refactor var preset parsing in veristat to simplify implementation.
Prepare parsed variable beforehand so that parsing logic is separated
from functionality of calculating offsets and searching fields.
Introduce rvalue struct, storing either int or enum (string value),
will be reused in the next patch, extract parsing rvalue into a
separate function.

Signed-off-by: Mykyta Yatsenko <yatsenko@meta.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/bpf/20250625165904.87820-2-mykyta.yatsenko5@gmail.com
tools/testing/selftests/bpf/veristat.c

index 4da627ca57496905e63a64db0aea6b3ae1242b13..4049d4dda97ae25094708585da5bb0e78b4d3031 100644 (file)
@@ -156,13 +156,23 @@ struct filter {
        bool abs;
 };
 
-struct var_preset {
-       char *name;
+struct rvalue {
        enum { INTEGRAL, ENUMERATOR } type;
        union {
                long long ivalue;
                char *svalue;
        };
+};
+
+struct field_access {
+       char *name;
+};
+
+struct var_preset {
+       struct field_access *atoms;
+       int atom_count;
+       char *full_name;
+       struct rvalue value;
        bool applied;
 };
 
@@ -1498,6 +1508,35 @@ static int reset_stat_cgroup(void)
        return 0;
 }
 
+static int parse_rvalue(const char *val, struct rvalue *rvalue)
+{
+       long long value;
+       char *val_end;
+
+       if (val[0] == '-' || isdigit(val[0])) {
+               /* must be a number */
+               errno = 0;
+               value = strtoll(val, &val_end, 0);
+               if (errno == ERANGE) {
+                       errno = 0;
+                       value = strtoull(val, &val_end, 0);
+               }
+               if (errno || *val_end != '\0') {
+                       fprintf(stderr, "Failed to parse value '%s'\n", val);
+                       return -EINVAL;
+               }
+               rvalue->ivalue = value;
+               rvalue->type = INTEGRAL;
+       } else {
+               /* if not a number, consider it enum value */
+               rvalue->svalue = strdup(val);
+               if (!rvalue->svalue)
+                       return -ENOMEM;
+               rvalue->type = ENUMERATOR;
+       }
+       return 0;
+}
+
 static int process_prog(const char *filename, struct bpf_object *obj, struct bpf_program *prog)
 {
        const char *base_filename = basename(strdupa(filename));
@@ -1593,13 +1632,36 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf
        return 0;
 };
 
+static int parse_var_atoms(const char *full_var, struct var_preset *preset)
+{
+       char expr[256], *name, *saveptr;
+
+       snprintf(expr, sizeof(expr), "%s", full_var);
+       preset->atom_count = 0;
+       while ((name = strtok_r(preset->atom_count ? NULL : expr, ".", &saveptr))) {
+               struct field_access *tmp;
+               int i = preset->atom_count;
+
+               tmp = reallocarray(preset->atoms, i + 1, sizeof(*preset->atoms));
+               if (!tmp)
+                       return -ENOMEM;
+
+               preset->atoms = tmp;
+               preset->atom_count++;
+
+               preset->atoms[i].name = strdup(name);
+               if (!preset->atoms[i].name)
+                       return -ENOMEM;
+       }
+       return 0;
+}
+
 static int append_var_preset(struct var_preset **presets, int *cnt, const char *expr)
 {
        void *tmp;
        struct var_preset *cur;
-       char var[256], val[256], *val_end;
-       long long value;
-       int n;
+       char var[256], val[256];
+       int n, err;
 
        tmp = realloc(*presets, (*cnt + 1) * sizeof(**presets));
        if (!tmp)
@@ -1614,32 +1676,18 @@ static int append_var_preset(struct var_preset **presets, int *cnt, const char *
                return -EINVAL;
        }
 
-       if (val[0] == '-' || isdigit(val[0])) {
-               /* must be a number */
-               errno = 0;
-               value = strtoll(val, &val_end, 0);
-               if (errno == ERANGE) {
-                       errno = 0;
-                       value = strtoull(val, &val_end, 0);
-               }
-               if (errno || *val_end != '\0') {
-                       fprintf(stderr, "Failed to parse value '%s'\n", val);
-                       return -EINVAL;
-               }
-               cur->ivalue = value;
-               cur->type = INTEGRAL;
-       } else {
-               /* if not a number, consider it enum value */
-               cur->svalue = strdup(val);
-               if (!cur->svalue)
-                       return -ENOMEM;
-               cur->type = ENUMERATOR;
-       }
+       err = parse_rvalue(val, &cur->value);
+       if (err)
+               return err;
 
-       cur->name = strdup(var);
-       if (!cur->name)
+       cur->full_name = strdup(var);
+       if (!cur->full_name)
                return -ENOMEM;
 
+       err = parse_var_atoms(var, cur);
+       if (err)
+               return err;
+
        return 0;
 }
 
@@ -1766,22 +1814,20 @@ const int btf_find_member(const struct btf *btf,
 }
 
 static int adjust_var_secinfo(struct btf *btf, const struct btf_type *t,
-                             struct btf_var_secinfo *sinfo, const char *var)
+                             struct btf_var_secinfo *sinfo, struct var_preset *preset)
 {
-       char expr[256], *saveptr;
        const struct btf_type *base_type, *member_type;
-       int err, member_tid;
-       char *name;
+       int err, member_tid, i;
        __u32 member_offset = 0;
 
        base_type = btf__type_by_id(btf, btf__resolve_type(btf, t->type));
-       snprintf(expr, sizeof(expr), "%s", var);
-       strtok_r(expr, ".", &saveptr);
 
-       while ((name = strtok_r(NULL, ".", &saveptr))) {
-               err = btf_find_member(btf, base_type, 0, name, &member_tid, &member_offset);
+       for (i = 1; i < preset->atom_count; ++i) {
+               err = btf_find_member(btf, base_type, 0, preset->atoms[i].name,
+                                     &member_tid, &member_offset);
                if (err) {
-                       fprintf(stderr, "Could not find member %s for variable %s\n", name, var);
+                       fprintf(stderr, "Could not find member %s for variable %s\n",
+                               preset->atoms[i].name, preset->atoms[i - 1].name);
                        return err;
                }
                member_type = btf__type_by_id(btf, member_tid);
@@ -1799,7 +1845,7 @@ static int set_global_var(struct bpf_object *obj, struct btf *btf,
 {
        const struct btf_type *base_type;
        void *ptr;
-       long long value = preset->ivalue;
+       long long value = preset->value.ivalue;
        size_t size;
 
        base_type = btf__type_by_id(btf, btf__resolve_type(btf, sinfo->type));
@@ -1813,17 +1859,18 @@ static int set_global_var(struct bpf_object *obj, struct btf *btf,
                return -EINVAL;
        }
 
-       if (preset->type == ENUMERATOR) {
+       if (preset->value.type == ENUMERATOR) {
                if (btf_is_any_enum(base_type)) {
-                       if (enum_value_from_name(btf, base_type, preset->svalue, &value)) {
+                       if (enum_value_from_name(btf, base_type, preset->value.svalue, &value)) {
                                fprintf(stderr,
                                        "Failed to find integer value for enum element %s\n",
-                                       preset->svalue);
+                                       preset->value.svalue);
                                return -EINVAL;
                        }
                } else {
                        fprintf(stderr, "Value %s is not supported for type %s\n",
-                               preset->svalue, btf__name_by_offset(btf, base_type->name_off));
+                               preset->value.svalue,
+                               btf__name_by_offset(btf, base_type->name_off));
                        return -EINVAL;
                }
        }
@@ -1890,20 +1937,16 @@ static int set_global_vars(struct bpf_object *obj, struct var_preset *presets, i
                for (j = 0; j < n; ++j, ++sinfo) {
                        const struct btf_type *var_type = btf__type_by_id(btf, sinfo->type);
                        const char *var_name;
-                       int var_len;
 
                        if (!btf_is_var(var_type))
                                continue;
 
                        var_name = btf__name_by_offset(btf, var_type->name_off);
-                       var_len = strlen(var_name);
 
                        for (k = 0; k < npresets; ++k) {
                                struct btf_var_secinfo tmp_sinfo;
 
-                               if (strncmp(var_name, presets[k].name, var_len) != 0 ||
-                                   (presets[k].name[var_len] != '\0' &&
-                                    presets[k].name[var_len] != '.'))
+                               if (strcmp(var_name, presets[k].atoms[0].name) != 0)
                                        continue;
 
                                if (presets[k].applied) {
@@ -1913,7 +1956,7 @@ static int set_global_vars(struct bpf_object *obj, struct var_preset *presets, i
                                }
                                tmp_sinfo = *sinfo;
                                err = adjust_var_secinfo(btf, var_type,
-                                                        &tmp_sinfo, presets[k].name);
+                                                        &tmp_sinfo, presets + k);
                                if (err)
                                        return err;
 
@@ -1928,7 +1971,7 @@ static int set_global_vars(struct bpf_object *obj, struct var_preset *presets, i
        for (i = 0; i < npresets; ++i) {
                if (!presets[i].applied) {
                        fprintf(stderr, "Global variable preset %s has not been applied\n",
-                               presets[i].name);
+                               presets[i].full_name);
                }
                presets[i].applied = false;
        }
@@ -3062,7 +3105,7 @@ static int handle_replay_mode(void)
 
 int main(int argc, char **argv)
 {
-       int err = 0, i;
+       int err = 0, i, j;
 
        if (argp_parse(&argp, argc, argv, 0, NULL, NULL))
                return 1;
@@ -3121,9 +3164,12 @@ int main(int argc, char **argv)
        }
        free(env.deny_filters);
        for (i = 0; i < env.npresets; ++i) {
-               free(env.presets[i].name);
-               if (env.presets[i].type == ENUMERATOR)
-                       free(env.presets[i].svalue);
+               free(env.presets[i].full_name);
+               for (j = 0; j < env.presets[i].atom_count; ++j)
+                       free(env.presets[i].atoms[j].name);
+               free(env.presets[i].atoms);
+               if (env.presets[i].value.type == ENUMERATOR)
+                       free(env.presets[i].value.svalue);
        }
        free(env.presets);
        return -err;