Commit be898cb5 authored by Mykyta Yatsenko's avatar Mykyta Yatsenko Committed by Andrii Nakryiko
Browse files

selftests/bpf: Separate var preset parsing in veristat



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: default avatarMykyta Yatsenko <yatsenko@meta.com>
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/bpf/20250625165904.87820-2-mykyta.yatsenko5@gmail.com
parent 886178a3
Loading
Loading
Loading
Loading
+99 −53
Original line number Diff line number Diff line
@@ -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;