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

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/net/tcp_ao/lib/ftrace-tcp.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ 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.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 #include <inttypes.h>
  3 #include <pthread.h>
  4 #include "aolib.h"
  5 
  6 static const char *trace_event_names[__MAX_TRACE_EVENTS] = {
  7         /* TCP_HASH_EVENT */
  8         "tcp_hash_bad_header",
  9         "tcp_hash_md5_required",
 10         "tcp_hash_md5_unexpected",
 11         "tcp_hash_md5_mismatch",
 12         "tcp_hash_ao_required",
 13         /* TCP_AO_EVENT */
 14         "tcp_ao_handshake_failure",
 15         "tcp_ao_wrong_maclen",
 16         "tcp_ao_mismatch",
 17         "tcp_ao_key_not_found",
 18         "tcp_ao_rnext_request",
 19         /* TCP_AO_EVENT_SK */
 20         "tcp_ao_synack_no_key",
 21         /* TCP_AO_EVENT_SNE */
 22         "tcp_ao_snd_sne_update",
 23         "tcp_ao_rcv_sne_update"
 24 };
 25 
 26 struct expected_trace_point {
 27         /* required */
 28         enum trace_events type;
 29         int family;
 30         union tcp_addr src;
 31         union tcp_addr dst;
 32 
 33         /* optional */
 34         int src_port;
 35         int dst_port;
 36         int L3index;
 37 
 38         int fin;
 39         int syn;
 40         int rst;
 41         int psh;
 42         int ack;
 43 
 44         int keyid;
 45         int rnext;
 46         int maclen;
 47         int sne;
 48 
 49         size_t matched;
 50 };
 51 
 52 static struct expected_trace_point *exp_tps;
 53 static size_t exp_tps_nr;
 54 static size_t exp_tps_size;
 55 static pthread_mutex_t exp_tps_mutex = PTHREAD_MUTEX_INITIALIZER;
 56 
 57 int __trace_event_expect(enum trace_events type, int family,
 58                          union tcp_addr src, union tcp_addr dst,
 59                          int src_port, int dst_port, int L3index,
 60                          int fin, int syn, int rst, int psh, int ack,
 61                          int keyid, int rnext, int maclen, int sne)
 62 {
 63         struct expected_trace_point new_tp = {
 64                 .type           = type,
 65                 .family         = family,
 66                 .src            = src,
 67                 .dst            = dst,
 68                 .src_port       = src_port,
 69                 .dst_port       = dst_port,
 70                 .L3index        = L3index,
 71                 .fin            = fin,
 72                 .syn            = syn,
 73                 .rst            = rst,
 74                 .psh            = psh,
 75                 .ack            = ack,
 76                 .keyid          = keyid,
 77                 .rnext          = rnext,
 78                 .maclen         = maclen,
 79                 .sne            = sne,
 80                 .matched        = 0,
 81         };
 82         int ret = 0;
 83 
 84         if (!kernel_config_has(KCONFIG_FTRACE))
 85                 return 0;
 86 
 87         pthread_mutex_lock(&exp_tps_mutex);
 88         if (exp_tps_nr == exp_tps_size) {
 89                 struct expected_trace_point *tmp;
 90 
 91                 if (exp_tps_size == 0)
 92                         exp_tps_size = 10;
 93                 else
 94                         exp_tps_size = exp_tps_size * 1.6;
 95 
 96                 tmp = reallocarray(exp_tps, exp_tps_size, sizeof(exp_tps[0]));
 97                 if (!tmp) {
 98                         ret = -ENOMEM;
 99                         goto out;
100                 }
101                 exp_tps = tmp;
102         }
103         exp_tps[exp_tps_nr] = new_tp;
104         exp_tps_nr++;
105 out:
106         pthread_mutex_unlock(&exp_tps_mutex);
107         return ret;
108 }
109 
110 static void free_expected_events(void)
111 {
112         /* We're from the process destructor - not taking the mutex */
113         exp_tps_size = 0;
114         exp_tps = NULL;
115         free(exp_tps);
116 }
117 
118 struct trace_point {
119         int family;
120         union tcp_addr src;
121         union tcp_addr dst;
122         unsigned int src_port;
123         unsigned int dst_port;
124         int L3index;
125         unsigned int fin:1,
126                      syn:1,
127                      rst:1,
128                      psh:1,
129                      ack:1;
130 
131         unsigned int keyid;
132         unsigned int rnext;
133         unsigned int maclen;
134 
135         unsigned int sne;
136 };
137 
138 static bool lookup_expected_event(int event_type, struct trace_point *e)
139 {
140         size_t i;
141 
142         pthread_mutex_lock(&exp_tps_mutex);
143         for (i = 0; i < exp_tps_nr; i++) {
144                 struct expected_trace_point *p = &exp_tps[i];
145                 size_t sk_size;
146 
147                 if (p->type != event_type)
148                         continue;
149                 if (p->family != e->family)
150                         continue;
151                 if (p->family == AF_INET)
152                         sk_size = sizeof(p->src.a4);
153                 else
154                         sk_size = sizeof(p->src.a6);
155                 if (memcmp(&p->src, &e->src, sk_size))
156                         continue;
157                 if (memcmp(&p->dst, &e->dst, sk_size))
158                         continue;
159                 if (p->src_port >= 0 && p->src_port != e->src_port)
160                         continue;
161                 if (p->dst_port >= 0 && p->dst_port != e->dst_port)
162                         continue;
163                 if (p->L3index >= 0 && p->L3index != e->L3index)
164                         continue;
165 
166                 if (p->fin >= 0 && p->fin != e->fin)
167                         continue;
168                 if (p->syn >= 0 && p->syn != e->syn)
169                         continue;
170                 if (p->rst >= 0 && p->rst != e->rst)
171                         continue;
172                 if (p->psh >= 0 && p->psh != e->psh)
173                         continue;
174                 if (p->ack >= 0 && p->ack != e->ack)
175                         continue;
176 
177                 if (p->keyid >= 0 && p->keyid != e->keyid)
178                         continue;
179                 if (p->rnext >= 0 && p->rnext != e->rnext)
180                         continue;
181                 if (p->maclen >= 0 && p->maclen != e->maclen)
182                         continue;
183                 if (p->sne >= 0 && p->sne != e->sne)
184                         continue;
185                 p->matched++;
186                 pthread_mutex_unlock(&exp_tps_mutex);
187                 return true;
188         }
189         pthread_mutex_unlock(&exp_tps_mutex);
190         return false;
191 }
192 
193 static int check_event_type(const char *line)
194 {
195         size_t i;
196 
197         /*
198          * This should have been a set or hashmap, but it's a selftest,
199          * so... KISS.
200          */
201         for (i = 0; i < __MAX_TRACE_EVENTS; i++) {
202                 if (!strncmp(trace_event_names[i], line, strlen(trace_event_names[i])))
203                         return i;
204         }
205         return -1;
206 }
207 
208 static bool event_has_flags(enum trace_events event)
209 {
210         switch (event) {
211         case TCP_HASH_BAD_HEADER:
212         case TCP_HASH_MD5_REQUIRED:
213         case TCP_HASH_MD5_UNEXPECTED:
214         case TCP_HASH_MD5_MISMATCH:
215         case TCP_HASH_AO_REQUIRED:
216         case TCP_AO_HANDSHAKE_FAILURE:
217         case TCP_AO_WRONG_MACLEN:
218         case TCP_AO_MISMATCH:
219         case TCP_AO_KEY_NOT_FOUND:
220         case TCP_AO_RNEXT_REQUEST:
221                 return true;
222         default:
223                 return false;
224         }
225 }
226 
227 static int tracer_ip_split(int family, char *src, char **addr, char **port)
228 {
229         char *p;
230 
231         if (family == AF_INET) {
232                 /* fomat is <addr>:port, i.e.: 10.0.254.1:7015 */
233                 *addr = src;
234                 p = strchr(src, ':');
235                 if (!p) {
236                         test_print("Couldn't parse trace event addr:port %s", src);
237                         return -EINVAL;
238                 }
239                 *p++ = '\0';
240                 *port = p;
241                 return 0;
242         }
243         if (family != AF_INET6)
244                 return -EAFNOSUPPORT;
245 
246         /* format is [<addr>]:port, i.e.: [2001:db8:254::1]:7013 */
247         *addr = strchr(src, '[');
248         p = strchr(src, ']');
249 
250         if (!p || !*addr) {
251                 test_print("Couldn't parse trace event [addr]:port %s", src);
252                 return -EINVAL;
253         }
254 
255         *addr = *addr + 1;      /* '[' */
256         *p++ = '\0';            /* ']' */
257         if (*p != ':') {
258                 test_print("Couldn't parse trace event :port %s", p);
259                 return -EINVAL;
260         }
261         *p++ = '\0';            /* ':' */
262         *port = p;
263         return 0;
264 }
265 
266 static int tracer_scan_address(int family, char *src,
267                                union tcp_addr *dst, unsigned int *port)
268 {
269         char *addr, *port_str;
270         int ret;
271 
272         ret = tracer_ip_split(family, src, &addr, &port_str);
273         if (ret)
274                 return ret;
275 
276         if (inet_pton(family, addr, dst) != 1) {
277                 test_print("Couldn't parse trace event addr %s", addr);
278                 return -EINVAL;
279         }
280         errno = 0;
281         *port = (unsigned int)strtoul(port_str, NULL, 10);
282         if (errno != 0) {
283                 test_print("Couldn't parse trace event port %s", port_str);
284                 return -errno;
285         }
286         return 0;
287 }
288 
289 static int tracer_scan_event(const char *line, enum trace_events event,
290                              struct trace_point *out)
291 {
292         char *src = NULL, *dst = NULL, *family = NULL;
293         char fin, syn, rst, psh, ack;
294         int nr_matched, ret = 0;
295         uint64_t netns_cookie;
296 
297         switch (event) {
298         case TCP_HASH_BAD_HEADER:
299         case TCP_HASH_MD5_REQUIRED:
300         case TCP_HASH_MD5_UNEXPECTED:
301         case TCP_HASH_MD5_MISMATCH:
302         case TCP_HASH_AO_REQUIRED: {
303                 nr_matched = sscanf(line, "%*s net=%" PRIu64 " state%*s family=%ms src=%ms dest=%ms L3index=%d [%c%c%c%c%c]",
304                                     &netns_cookie, &family,
305                                     &src, &dst, &out->L3index,
306                                     &fin, &syn, &rst, &psh, &ack);
307                 if (nr_matched != 10)
308                         test_print("Couldn't parse trace event, matched = %d/10",
309                                    nr_matched);
310                 break;
311         }
312         case TCP_AO_HANDSHAKE_FAILURE:
313         case TCP_AO_WRONG_MACLEN:
314         case TCP_AO_MISMATCH:
315         case TCP_AO_KEY_NOT_FOUND:
316         case TCP_AO_RNEXT_REQUEST: {
317                 nr_matched = sscanf(line, "%*s net=%" PRIu64 " state%*s family=%ms src=%ms dest=%ms L3index=%d [%c%c%c%c%c] keyid=%u rnext=%u maclen=%u",
318                                     &netns_cookie, &family,
319                                     &src, &dst, &out->L3index,
320                                     &fin, &syn, &rst, &psh, &ack,
321                                     &out->keyid, &out->rnext, &out->maclen);
322                 if (nr_matched != 13)
323                         test_print("Couldn't parse trace event, matched = %d/13",
324                                    nr_matched);
325                 break;
326         }
327         case TCP_AO_SYNACK_NO_KEY: {
328                 nr_matched = sscanf(line, "%*s net=%" PRIu64 " state%*s family=%ms src=%ms dest=%ms keyid=%u rnext=%u",
329                                     &netns_cookie, &family,
330                                     &src, &dst, &out->keyid, &out->rnext);
331                 if (nr_matched != 6)
332                         test_print("Couldn't parse trace event, matched = %d/6",
333                                    nr_matched);
334                 break;
335         }
336         case TCP_AO_SND_SNE_UPDATE:
337         case TCP_AO_RCV_SNE_UPDATE: {
338                 nr_matched = sscanf(line, "%*s net=%" PRIu64 " state%*s family=%ms src=%ms dest=%ms sne=%u",
339                                     &netns_cookie, &family,
340                                     &src, &dst, &out->sne);
341                 if (nr_matched != 5)
342                         test_print("Couldn't parse trace event, matched = %d/5",
343                                    nr_matched);
344                 break;
345         }
346         default:
347                 return -1;
348         }
349 
350         if (family) {
351                 if (!strcmp(family, "AF_INET")) {
352                         out->family = AF_INET;
353                 } else if (!strcmp(family, "AF_INET6")) {
354                         out->family = AF_INET6;
355                 } else {
356                         test_print("Couldn't parse trace event family %s", family);
357                         ret = -EINVAL;
358                         goto out_free;
359                 }
360         }
361 
362         if (event_has_flags(event)) {
363                 out->fin = (fin == 'F');
364                 out->syn = (syn == 'S');
365                 out->rst = (rst == 'R');
366                 out->psh = (psh == 'P');
367                 out->ack = (ack == '.');
368 
369                 if ((fin != 'F' && fin != ' ') ||
370                     (syn != 'S' && syn != ' ') ||
371                     (rst != 'R' && rst != ' ') ||
372                     (psh != 'P' && psh != ' ') ||
373                     (ack != '.' && ack != ' ')) {
374                         test_print("Couldn't parse trace event flags %c%c%c%c%c",
375                                    fin, syn, rst, psh, ack);
376                         ret = -EINVAL;
377                         goto out_free;
378                 }
379         }
380 
381         if (src && tracer_scan_address(out->family, src, &out->src, &out->src_port)) {
382                 ret = -EINVAL;
383                 goto out_free;
384         }
385 
386         if (dst && tracer_scan_address(out->family, dst, &out->dst, &out->dst_port)) {
387                 ret = -EINVAL;
388                 goto out_free;
389         }
390 
391         if (netns_cookie != ns_cookie1 && netns_cookie != ns_cookie2) {
392                 test_print("Net namespace filter for trace event didn't work: %" PRIu64 " != %" PRIu64 " OR %" PRIu64,
393                            netns_cookie, ns_cookie1, ns_cookie2);
394                 ret = -EINVAL;
395         }
396 
397 out_free:
398         free(src);
399         free(dst);
400         free(family);
401         return ret;
402 }
403 
404 static enum ftracer_op aolib_tracer_process_event(const char *line)
405 {
406         int event_type = check_event_type(line);
407         struct trace_point tmp = {};
408 
409         if (event_type < 0)
410                 return FTRACER_LINE_PRESERVE;
411 
412         if (tracer_scan_event(line, event_type, &tmp))
413                 return FTRACER_LINE_PRESERVE;
414 
415         return lookup_expected_event(event_type, &tmp) ?
416                 FTRACER_LINE_DISCARD : FTRACER_LINE_PRESERVE;
417 }
418 
419 static void dump_trace_event(struct expected_trace_point *e)
420 {
421         char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];
422 
423         if (!inet_ntop(e->family, &e->src, src, INET6_ADDRSTRLEN))
424                 test_error("inet_ntop()");
425         if (!inet_ntop(e->family, &e->dst, dst, INET6_ADDRSTRLEN))
426                 test_error("inet_ntop()");
427         test_print("trace event filter %s [%s:%d => %s:%d, L3index %d, flags: %s%s%s%s%s, keyid: %d, rnext: %d, maclen: %d, sne: %d] = %zu",
428                    trace_event_names[e->type],
429                    src, e->src_port, dst, e->dst_port, e->L3index,
430                    (e->fin > 0) ? "F" : (e->fin == 0) ? "!F" : "",
431                    (e->syn > 0) ? "S" : (e->syn == 0) ? "!S" : "",
432                    (e->rst > 0) ? "R" : (e->rst == 0) ? "!R" : "",
433                    (e->psh > 0) ? "P" : (e->psh == 0) ? "!P" : "",
434                    (e->ack > 0) ? "." : (e->ack == 0) ? "!." : "",
435                    e->keyid, e->rnext, e->maclen, e->sne, e->matched);
436 }
437 
438 static void print_match_stats(bool unexpected_events)
439 {
440         size_t matches_per_type[__MAX_TRACE_EVENTS] = {};
441         bool expected_but_none = false;
442         size_t i, total_matched = 0;
443         char *stat_line = NULL;
444 
445         for (i = 0; i < exp_tps_nr; i++) {
446                 struct expected_trace_point *e = &exp_tps[i];
447 
448                 total_matched += e->matched;
449                 matches_per_type[e->type] += e->matched;
450                 if (!e->matched)
451                         expected_but_none = true;
452         }
453         for (i = 0; i < __MAX_TRACE_EVENTS; i++) {
454                 if (!matches_per_type[i])
455                         continue;
456                 stat_line = test_sprintf("%s%s[%zu] ", stat_line ?: "",
457                                          trace_event_names[i],
458                                          matches_per_type[i]);
459                 if (!stat_line)
460                         test_error("test_sprintf()");
461         }
462 
463         if (unexpected_events || expected_but_none) {
464                 for (i = 0; i < exp_tps_nr; i++)
465                         dump_trace_event(&exp_tps[i]);
466         }
467 
468         if (unexpected_events)
469                 return;
470 
471         if (expected_but_none)
472                 test_fail("Some trace events were expected, but didn't occur");
473         else if (total_matched)
474                 test_ok("Trace events matched expectations: %zu %s",
475                         total_matched, stat_line);
476         else
477                 test_ok("No unexpected trace events during the test run");
478 }
479 
480 #define dump_events(fmt, ...)                           \
481         __test_print(__test_msg, fmt, ##__VA_ARGS__)
482 static void check_free_events(struct test_ftracer *tracer)
483 {
484         const char **lines;
485         size_t nr;
486 
487         if (!kernel_config_has(KCONFIG_FTRACE)) {
488                 test_skip("kernel config doesn't have ftrace - no checks");
489                 return;
490         }
491 
492         nr = tracer_get_savedlines_nr(tracer);
493         lines = tracer_get_savedlines(tracer);
494         print_match_stats(!!nr);
495         if (!nr)
496                 return;
497 
498         errno = 0;
499         test_xfail("Trace events [%zu] were not expected:", nr);
500         while (nr)
501                 dump_events("\t%s", lines[--nr]);
502 }
503 
504 static int setup_tcp_trace_events(struct test_ftracer *tracer)
505 {
506         char *filter;
507         size_t i;
508         int ret;
509 
510         filter = test_sprintf("net_cookie == %zu || net_cookie == %zu",
511                               ns_cookie1, ns_cookie2);
512         if (!filter)
513                 return -ENOMEM;
514 
515         for (i = 0; i < __MAX_TRACE_EVENTS; i++) {
516                 char *event_name = test_sprintf("tcp/%s", trace_event_names[i]);
517 
518                 if (!event_name) {
519                         ret = -ENOMEM;
520                         break;
521                 }
522                 ret = setup_trace_event(tracer, event_name, filter);
523                 free(event_name);
524                 if (ret)
525                         break;
526         }
527 
528         free(filter);
529         return ret;
530 }
531 
532 static void aolib_tracer_destroy(struct test_ftracer *tracer)
533 {
534         check_free_events(tracer);
535         free_expected_events();
536 }
537 
538 static bool aolib_tracer_expecting_more(void)
539 {
540         size_t i;
541 
542         for (i = 0; i < exp_tps_nr; i++)
543                 if (!exp_tps[i].matched)
544                         return true;
545         return false;
546 }
547 
548 int setup_aolib_ftracer(void)
549 {
550         struct test_ftracer *f;
551 
552         f = create_ftracer("aolib", aolib_tracer_process_event,
553                            aolib_tracer_destroy, aolib_tracer_expecting_more,
554                            DEFAULT_FTRACE_BUFFER_KB, DEFAULT_TRACER_LINES_ARR);
555         if (!f)
556                 return -1;
557 
558         return setup_tcp_trace_events(f);
559 }
560 

~ [ 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