This repository has been archived by the owner on Jul 6, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
prog_meta.c
173 lines (142 loc) · 5.73 KB
/
prog_meta.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include "xdptrace.h"
#include <pcap/dlt.h>
#include <bpf/bpf.h>
#include <bpf/btf.h>
#include <bpf/libbpf.h>
// BPF program name as reported by introspection APIs is limited to 15 chars.
// Find the full name using BTF. The returned pointer refers to a
// string inside the passed BTF (no copying).
//
// Even if the name wasn't truncated in the first place, scan BTF
// anyway. This is to ensure that memory management and requirements on
// the BTF are the same for both truncated and pristine names.
struct rc
bpf_prog_full_name(struct btf *btf, struct bpf_prog_short_name short_name,
struct bpf_prog_name *name) {
size_t len = strlen(short_name.name);
const char *match = 0;
for (__u32 i = btf__get_nr_types(btf); i--; ) {
const struct btf_type *t = btf__type_by_id(btf, i);
const char *name;
if (!t || !btf_is_func(t) || !(name = btf__name_by_offset(btf, t->name_off)))
continue;
// Prefix mismatch?
if (strncmp(short_name.name, name, len)) continue;
// Not a full match and the name wasn't truncated?
if (name[len] && len != BPF_OBJ_NAME_LEN - 1) continue;
if (match) {
fprintf(stderr, "Failed to determine the full name of %s (%d): "
"ambiguous prefix, possible matches '%s', '%s'\n",
short_name.name, short_name.id, match, name);
return FAILURE;
}
match = name;
}
if (!match) {
fprintf(stderr, "Failed to determine the full name of %s (%d): "
"no matches found in BTF\n",
short_name.name, short_name.id);
return FAILURE;
}
name->name = match;
name->id = short_name.id;
return SUCCESS;
}
// Locate VAR 'xdp_metadata_<progname>' and return the type id
static int
locate_xdp_prog_meta(struct btf *btf, struct bpf_prog_name progname) {
// locate SEC '.maps.xdp.meta'
__s32 secid = btf__find_by_name_kind(btf, ".maps.xdp.meta", BTF_KIND_DATASEC);
const struct btf_type *sect;
if (secid < 0
|| !(sect = btf__type_by_id(btf, secid))) return -1;
// iterate through SEC and locate VAR 'xdp_metadata_<progname>'
struct btf_var_secinfo *si = btf_var_secinfos(sect);
for (int i = 0; i < btf_vlen(sect); ++i) {
const struct btf_type *vt = btf__type_by_id(btf, si[i].type);
const char *name;
if (!vt || !btf_is_var(vt)
|| !(name = btf__name_by_offset(btf, vt->name_off))) continue;
static const char prefix[] = {
'x', 'd', 'p', '_', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '_'
};
if (!strncmp(name, prefix, sizeof(prefix))
&& !strcmp(progname.name, name + sizeof(prefix))
) return vt->type;
}
return -1;
}
// Parse uint as encoded by __uint(name, val) macro (bpf/bpf_helpers.h).
// It expands into int (*name) [val], a pointer to array of [val] ints.
static struct rc
meta__uint(const struct btf *btf, const struct btf_member *m, __u32 *val) {
const struct btf_type *pt = btf__type_by_id(btf, m->type);
if (!pt || !btf_is_ptr(pt)) return FAILURE;
const struct btf_type *at = btf__type_by_id(btf, pt->type);
if (!at || !btf_is_array(at)) return FAILURE;
*val = btf_array(at)->nelems;
return SUCCESS;
}
// Parse type as encoded by __type(name, val) macro (bpf/bpf_helpers.h).
// It expands into typeof(val) *name, a pointer to val.
static int
meta__type(const struct btf *btf, const struct btf_member *m) {
const struct btf_type *pt = btf__type_by_id(btf, m->type);
return pt && btf_is_ptr(pt) ? pt->type : -1;
}
// Parse XDP_METADATA() section for the particular program.
struct rc
parse_xdp_prog_meta(struct btf *btf, struct bpf_prog_name progname,
struct xdp_prog_meta *meta) {
meta->entry.link_type = DLT_EN10MB;
meta->entry.pseudo_sz = 0;
meta->entry.pseudo_type_id = -1;
meta->exit.link_type = DLT_EN10MB;
meta->exit.pseudo_sz = 0;
meta->exit.pseudo_type_id = -1;
// Note irt diagnostics: we trust that the basic structure of BTF is
// correct (e.g. name offsets are valid). We still check but don't
// produce helpful diagnostics if BTF itself is borked.
int tid = locate_xdp_prog_meta(btf, progname);
if (tid < 0) {
// Missing metadata is OK
return SUCCESS;
}
const struct btf_type *t = btf__type_by_id(btf, tid);
if (!t || !btf_is_struct(t)) {
fprintf(stderr, "Malformed metadata for %s (%d)\n", progname.name, progname.id);
return FAILURE;
}
const struct btf_member *member = btf_members(t);
for (int i = 0; i < btf_vlen(t); ++i) {
const char *name = btf__name_by_offset(btf, member[i].name_off);
if (!name) continue;
if (!strcmp(name, "link_type")) {
__u32 link_type;
if (failed(meta__uint(btf, &member[i], &link_type))) {
fprintf(stderr, "Error parsing 'link_type' for %s (%d)\n",
progname.name, progname.id);
return FAILURE;
}
meta->entry.link_type = link_type;
continue;
}
if (!strcmp(name, "pseudo")) {
int tid = meta__type(btf, &member[i]);
__s64 sz;
if (tid < 0 || (sz = btf__resolve_size(btf, tid)) < 0) {
fprintf(stderr, "Error parsing 'pseudo' for %s (%d)\n",
progname.name, progname.id);
return FAILURE;
}
meta->entry.pseudo_sz = sz;
meta->entry.pseudo_type_id = tid;
continue;
}
if (verbose) {
fprintf(stderr, "Unknown attribute '%s' in %s (%d) metadata\n",
name, progname.name, progname.id);
}
}
return SUCCESS;
}