Skip to content

Commit d4b62c8

Browse files
committed
selftests/bpf: support array presets in veristat
Implement support for presetting values for array elements in veristat. For example: ``` sudo ./veristat set_global_vars.bpf.o -G "arr[3] = 1" ``` Arrays of structures and structure of arrays work, but each individual scalar value has to be set separately: `foo[1].bar[2] = value`. Signed-off-by: Mykyta Yatsenko <yatsenko@meta.com>
1 parent c4fc432 commit d4b62c8

File tree

1 file changed

+128
-18
lines changed

1 file changed

+128
-18
lines changed

tools/testing/selftests/bpf/veristat.c

Lines changed: 128 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ struct variant {
165165

166166
struct var_preset_atom {
167167
char *name;
168+
struct variant index;
168169
};
169170

170171
struct var_preset {
@@ -1375,8 +1376,8 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf
13751376

13761377
static int parse_var_atoms(const char *full_var, struct var_preset *preset)
13771378
{
1378-
char expr[256], *name, *saveptr;
1379-
int i = 0;
1379+
char expr[256], var[256], idx[256], *name, *saveptr;
1380+
int i = 0, n;
13801381

13811382
snprintf(expr, sizeof(expr), "%s", full_var);
13821383

@@ -1385,7 +1386,27 @@ static int parse_var_atoms(const char *full_var, struct var_preset *preset)
13851386
if (!preset->atoms)
13861387
return -ENOMEM;
13871388

1388-
preset->atoms[i].name = strdup(name);
1389+
if (sscanf(name, "%[a-zA-Z0-9_][%[a-zA-Z0-9]] %n", var, idx, &n) == 2 &&
1390+
strlen(name) == n) {
1391+
/* current atom is an array, parse index */
1392+
preset->atoms[i].name = strdup(var);
1393+
if (sscanf(idx, "%d", &n) == 1) {
1394+
preset->atoms[i].index.type = INTEGRAL;
1395+
preset->atoms[i].index.ivalue = n;
1396+
} else {
1397+
/* index is not a number, assume it's an enum */
1398+
preset->atoms[i].index.type = ENUMERATOR;
1399+
preset->atoms[i].index.svalue = strdup(idx);
1400+
}
1401+
} else if (sscanf(name, "%[a-zA-Z0-9_] %n", var, &n) == 1 &&
1402+
strlen(name) == n) {
1403+
preset->atoms[i].name = strdup(name);
1404+
preset->atoms[i].index.type = NONE;
1405+
} else {
1406+
fprintf(stderr, "Could not parse '%s'", name);
1407+
return -EINVAL;
1408+
}
1409+
13891410
if (!preset->atoms[i].name)
13901411
return -ENOMEM;
13911412
++i;
@@ -1410,7 +1431,7 @@ static int append_var_preset(struct var_preset **presets, int *cnt, const char *
14101431
memset(cur, 0, sizeof(*cur));
14111432
(*cnt)++;
14121433

1413-
if (sscanf(expr, "%s = %s %n", var, val, &n) != 2 || n != strlen(expr)) {
1434+
if (sscanf(expr, "%[][a-zA-Z0-9_.] = %s %n", var, val, &n) != 2 || n != strlen(expr)) {
14141435
fprintf(stderr, "Failed to parse expression '%s'\n", expr);
14151436
return -EINVAL;
14161437
}
@@ -1521,14 +1542,82 @@ static bool is_preset_supported(const struct btf_type *t)
15211542
return btf_is_int(t) || btf_is_enum(t) || btf_is_enum64(t);
15221543
}
15231544

1545+
static int find_enum_value(const struct btf *btf, const char *name, int *value)
1546+
{
1547+
const struct btf_type *t;
1548+
int cnt, i;
1549+
long long lvalue;
1550+
1551+
cnt = btf__type_cnt(btf);
1552+
for (i = 1; i != cnt; ++i) {
1553+
t = btf__type_by_id(btf, i);
1554+
1555+
if (!btf_is_any_enum(t))
1556+
continue;
1557+
1558+
if (enum_value_from_name(btf, t, name, &lvalue) == 0) {
1559+
*value = (int)lvalue;
1560+
return 0;
1561+
}
1562+
}
1563+
return -ESRCH;
1564+
}
1565+
1566+
static int adjust_array_secinfo(const struct btf *btf, const struct btf_type *t,
1567+
const struct var_preset_atom *var_atom,
1568+
struct btf_var_secinfo *sinfo)
1569+
{
1570+
struct btf_array *barr;
1571+
const struct btf_type *type;
1572+
int tid, index;
1573+
1574+
if (!btf_is_array(t))
1575+
return -EINVAL;
1576+
1577+
barr = btf_array(t);
1578+
tid = btf__resolve_type(btf, barr->type);
1579+
type = btf__type_by_id(btf, tid);
1580+
if (!btf_is_int(type) && !btf_is_any_enum(type) && !btf_is_composite(type)) {
1581+
fprintf(stderr,
1582+
"Unsupported array type for variable %s. Only int, enum, struct, union are supported\n",
1583+
var_atom->name);
1584+
return -EINVAL;
1585+
}
1586+
switch (var_atom->index.type) {
1587+
case INTEGRAL:
1588+
index = var_atom->index.ivalue;
1589+
break;
1590+
case ENUMERATOR:
1591+
if (find_enum_value(btf, var_atom->index.svalue, &index) != 0) {
1592+
fprintf(stderr, "Could not find array index as enum value %s",
1593+
var_atom->index.svalue);
1594+
return -EINVAL;
1595+
}
1596+
break;
1597+
case NONE:
1598+
fprintf(stderr, "Array index is expected for %s\n", var_atom->name);
1599+
return -EINVAL;
1600+
}
1601+
1602+
if (index < 0 || index >= barr->nelems) {
1603+
fprintf(stderr, "Preset index %d is invalid or out of bounds [0, %d]\n",
1604+
index, barr->nelems);
1605+
return -EINVAL;
1606+
}
1607+
sinfo->size = type->size;
1608+
sinfo->type = tid;
1609+
sinfo->offset += index * type->size;
1610+
return 0;
1611+
}
1612+
15241613
const int btf_find_member(const struct btf *btf,
15251614
const struct btf_type *parent_type,
15261615
__u32 parent_offset,
15271616
struct var_preset_atom *var_atom,
15281617
int *member_tid,
15291618
__u32 *member_offset)
15301619
{
1531-
int i;
1620+
int i, err;
15321621

15331622
if (!btf_is_composite(parent_type))
15341623
return -EINVAL;
@@ -1547,16 +1636,27 @@ const int btf_find_member(const struct btf *btf,
15471636
if (member->name_off) {
15481637
const char *name = btf__name_by_offset(btf, member->name_off);
15491638

1550-
if (strcmp(var_atom->name, name) == 0) {
1551-
if (btf_member_bitfield_size(parent_type, i) != 0) {
1552-
fprintf(stderr, "Bitfield presets are not supported %s\n",
1553-
name);
1554-
return -EINVAL;
1555-
}
1556-
*member_offset = parent_offset + member->offset;
1557-
*member_tid = tid;
1558-
return 0;
1639+
if (strcmp(var_atom->name, name) != 0)
1640+
continue;
1641+
1642+
if (btf_member_bitfield_size(parent_type, i) != 0) {
1643+
fprintf(stderr, "Bitfield presets are not supported %s\n",
1644+
name);
1645+
return -EINVAL;
15591646
}
1647+
*member_offset = parent_offset + member->offset;
1648+
*member_tid = tid;
1649+
if (btf_is_array(member_type)) {
1650+
struct btf_var_secinfo sinfo = {.offset = 0};
1651+
1652+
err = adjust_array_secinfo(btf, member_type,
1653+
var_atom, &sinfo);
1654+
if (err)
1655+
return err;
1656+
*member_tid = sinfo.type;
1657+
*member_offset += sinfo.offset * 8;
1658+
}
1659+
return 0;
15601660
} else if (btf_is_composite(member_type)) {
15611661
int err;
15621662

@@ -1567,7 +1667,7 @@ const int btf_find_member(const struct btf *btf,
15671667
}
15681668
}
15691669

1570-
return -EINVAL;
1670+
return -ESRCH;
15711671
}
15721672

15731673
static int adjust_var_secinfo(struct btf *btf, const struct btf_type *t,
@@ -1578,6 +1678,12 @@ static int adjust_var_secinfo(struct btf *btf, const struct btf_type *t,
15781678
__u32 member_offset = 0;
15791679

15801680
base_type = btf__type_by_id(btf, btf__resolve_type(btf, t->type));
1681+
if (btf_is_array(base_type)) {
1682+
err = adjust_array_secinfo(btf, base_type, &preset->atoms[0], sinfo);
1683+
if (err)
1684+
return err;
1685+
base_type = btf__type_by_id(btf, sinfo->type);
1686+
}
15811687

15821688
for (i = 1; i < preset->atom_count; ++i) {
15831689
err = btf_find_member(btf, base_type, 0, &preset->atoms[i],
@@ -1727,8 +1833,9 @@ static int set_global_vars(struct bpf_object *obj, struct var_preset *presets, i
17271833
}
17281834
for (i = 0; i < npresets; ++i) {
17291835
if (!presets[i].applied) {
1730-
fprintf(stderr, "Global variable preset %s has not been applied\n",
1731-
presets[i].full_name);
1836+
fprintf(stderr, "Global variable preset %s has not been applied %s\n",
1837+
presets[i].full_name, presets[i].atoms[0].name);
1838+
err = -EINVAL;
17321839
}
17331840
presets[i].applied = false;
17341841
}
@@ -2916,8 +3023,11 @@ int main(int argc, char **argv)
29163023
free(env.deny_filters);
29173024
for (i = 0; i < env.npresets; ++i) {
29183025
free(env.presets[i].full_name);
2919-
for (j = 0; j < env.presets[i].atom_count; ++j)
3026+
for (j = 0; j < env.presets[i].atom_count; ++j) {
29203027
free(env.presets[i].atoms[j].name);
3028+
if (env.presets[i].atoms[j].index.type == ENUMERATOR)
3029+
free(env.presets[i].atoms[j].index.svalue);
3030+
}
29213031
free(env.presets[i].atoms);
29223032
if (env.presets[i].value.type == ENUMERATOR)
29233033
free(env.presets[i].value.svalue);

0 commit comments

Comments
 (0)