~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/perf/util/bpf-filter.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* SPDX-License-Identifier: GPL-2.0 */
  2 #include <stdlib.h>
  3 
  4 #include <bpf/bpf.h>
  5 #include <linux/err.h>
  6 #include <internal/xyarray.h>
  7 
  8 #include "util/debug.h"
  9 #include "util/evsel.h"
 10 
 11 #include "util/bpf-filter.h"
 12 #include <util/bpf-filter-flex.h>
 13 #include <util/bpf-filter-bison.h>
 14 
 15 #include "bpf_skel/sample-filter.h"
 16 #include "bpf_skel/sample_filter.skel.h"
 17 
 18 #define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y))
 19 
 20 #define __PERF_SAMPLE_TYPE(tt, st, opt) { tt, #st, opt }
 21 #define PERF_SAMPLE_TYPE(_st, opt)      __PERF_SAMPLE_TYPE(PBF_TERM_##_st, PERF_SAMPLE_##_st, opt)
 22 
 23 static const struct perf_sample_info {
 24         enum perf_bpf_filter_term type;
 25         const char *name;
 26         const char *option;
 27 } sample_table[] = {
 28         /* default sample flags */
 29         PERF_SAMPLE_TYPE(IP, NULL),
 30         PERF_SAMPLE_TYPE(TID, NULL),
 31         PERF_SAMPLE_TYPE(PERIOD, NULL),
 32         /* flags mostly set by default, but still have options */
 33         PERF_SAMPLE_TYPE(ID, "--sample-identifier"),
 34         PERF_SAMPLE_TYPE(CPU, "--sample-cpu"),
 35         PERF_SAMPLE_TYPE(TIME, "-T"),
 36         /* optional sample flags */
 37         PERF_SAMPLE_TYPE(ADDR, "-d"),
 38         PERF_SAMPLE_TYPE(DATA_SRC, "-d"),
 39         PERF_SAMPLE_TYPE(PHYS_ADDR, "--phys-data"),
 40         PERF_SAMPLE_TYPE(WEIGHT, "-W"),
 41         PERF_SAMPLE_TYPE(WEIGHT_STRUCT, "-W"),
 42         PERF_SAMPLE_TYPE(TRANSACTION, "--transaction"),
 43         PERF_SAMPLE_TYPE(CODE_PAGE_SIZE, "--code-page-size"),
 44         PERF_SAMPLE_TYPE(DATA_PAGE_SIZE, "--data-page-size"),
 45 };
 46 
 47 static const struct perf_sample_info *get_sample_info(enum perf_bpf_filter_term type)
 48 {
 49         size_t i;
 50 
 51         for (i = 0; i < ARRAY_SIZE(sample_table); i++) {
 52                 if (sample_table[i].type == type)
 53                         return &sample_table[i];
 54         }
 55         return NULL;
 56 }
 57 
 58 static int check_sample_flags(struct evsel *evsel, struct perf_bpf_filter_expr *expr)
 59 {
 60         const struct perf_sample_info *info;
 61 
 62         if (expr->term >= PBF_TERM_SAMPLE_START && expr->term <= PBF_TERM_SAMPLE_END &&
 63             (evsel->core.attr.sample_type & (1 << (expr->term - PBF_TERM_SAMPLE_START))))
 64                 return 0;
 65 
 66         if (expr->term == PBF_TERM_UID || expr->term == PBF_TERM_GID) {
 67                 /* Not dependent on the sample_type as computed from a BPF helper. */
 68                 return 0;
 69         }
 70 
 71         if (expr->op == PBF_OP_GROUP_BEGIN) {
 72                 struct perf_bpf_filter_expr *group;
 73 
 74                 list_for_each_entry(group, &expr->groups, list) {
 75                         if (check_sample_flags(evsel, group) < 0)
 76                                 return -1;
 77                 }
 78                 return 0;
 79         }
 80 
 81         info = get_sample_info(expr->term);
 82         if (info == NULL) {
 83                 pr_err("Error: %s event does not have sample flags %d\n",
 84                        evsel__name(evsel), expr->term);
 85                 return -1;
 86         }
 87 
 88         pr_err("Error: %s event does not have %s\n", evsel__name(evsel), info->name);
 89         if (info->option)
 90                 pr_err(" Hint: please add %s option to perf record\n", info->option);
 91         return -1;
 92 }
 93 
 94 int perf_bpf_filter__prepare(struct evsel *evsel)
 95 {
 96         int i, x, y, fd;
 97         struct sample_filter_bpf *skel;
 98         struct bpf_program *prog;
 99         struct bpf_link *link;
100         struct perf_bpf_filter_expr *expr;
101 
102         skel = sample_filter_bpf__open_and_load();
103         if (!skel) {
104                 pr_err("Failed to load perf sample-filter BPF skeleton\n");
105                 return -1;
106         }
107 
108         i = 0;
109         fd = bpf_map__fd(skel->maps.filters);
110         list_for_each_entry(expr, &evsel->bpf_filters, list) {
111                 struct perf_bpf_filter_entry entry = {
112                         .op = expr->op,
113                         .part = expr->part,
114                         .term = expr->term,
115                         .value = expr->val,
116                 };
117 
118                 if (check_sample_flags(evsel, expr) < 0)
119                         return -1;
120 
121                 bpf_map_update_elem(fd, &i, &entry, BPF_ANY);
122                 i++;
123 
124                 if (expr->op == PBF_OP_GROUP_BEGIN) {
125                         struct perf_bpf_filter_expr *group;
126 
127                         list_for_each_entry(group, &expr->groups, list) {
128                                 struct perf_bpf_filter_entry group_entry = {
129                                         .op = group->op,
130                                         .part = group->part,
131                                         .term = group->term,
132                                         .value = group->val,
133                                 };
134                                 bpf_map_update_elem(fd, &i, &group_entry, BPF_ANY);
135                                 i++;
136                         }
137 
138                         memset(&entry, 0, sizeof(entry));
139                         entry.op = PBF_OP_GROUP_END;
140                         bpf_map_update_elem(fd, &i, &entry, BPF_ANY);
141                         i++;
142                 }
143         }
144 
145         if (i > MAX_FILTERS) {
146                 pr_err("Too many filters: %d (max = %d)\n", i, MAX_FILTERS);
147                 return -1;
148         }
149         prog = skel->progs.perf_sample_filter;
150         for (x = 0; x < xyarray__max_x(evsel->core.fd); x++) {
151                 for (y = 0; y < xyarray__max_y(evsel->core.fd); y++) {
152                         link = bpf_program__attach_perf_event(prog, FD(evsel, x, y));
153                         if (IS_ERR(link)) {
154                                 pr_err("Failed to attach perf sample-filter program\n");
155                                 return PTR_ERR(link);
156                         }
157                 }
158         }
159         evsel->bpf_skel = skel;
160         return 0;
161 }
162 
163 int perf_bpf_filter__destroy(struct evsel *evsel)
164 {
165         struct perf_bpf_filter_expr *expr, *tmp;
166 
167         list_for_each_entry_safe(expr, tmp, &evsel->bpf_filters, list) {
168                 list_del(&expr->list);
169                 free(expr);
170         }
171         sample_filter_bpf__destroy(evsel->bpf_skel);
172         return 0;
173 }
174 
175 u64 perf_bpf_filter__lost_count(struct evsel *evsel)
176 {
177         struct sample_filter_bpf *skel = evsel->bpf_skel;
178 
179         return skel ? skel->bss->dropped : 0;
180 }
181 
182 struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(enum perf_bpf_filter_term term,
183                                                        int part,
184                                                        enum perf_bpf_filter_op op,
185                                                        unsigned long val)
186 {
187         struct perf_bpf_filter_expr *expr;
188 
189         expr = malloc(sizeof(*expr));
190         if (expr != NULL) {
191                 expr->term = term;
192                 expr->part = part;
193                 expr->op = op;
194                 expr->val = val;
195                 INIT_LIST_HEAD(&expr->groups);
196         }
197         return expr;
198 }
199 
200 int perf_bpf_filter__parse(struct list_head *expr_head, const char *str)
201 {
202         YY_BUFFER_STATE buffer;
203         int ret;
204 
205         buffer = perf_bpf_filter__scan_string(str);
206 
207         ret = perf_bpf_filter_parse(expr_head);
208 
209         perf_bpf_filter__flush_buffer(buffer);
210         perf_bpf_filter__delete_buffer(buffer);
211         perf_bpf_filter_lex_destroy();
212 
213         return ret;
214 }
215 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php