1 // SPDX-License-Identifier: GPL-2.0
6 static const char *trace_event_names
[__MAX_TRACE_EVENTS
] = {
9 "tcp_hash_md5_required",
10 "tcp_hash_md5_unexpected",
11 "tcp_hash_md5_mismatch",
12 "tcp_hash_ao_required",
14 "tcp_ao_handshake_failure",
15 "tcp_ao_wrong_maclen",
17 "tcp_ao_key_not_found",
18 "tcp_ao_rnext_request",
20 "tcp_ao_synack_no_key",
21 /* TCP_AO_EVENT_SNE */
22 "tcp_ao_snd_sne_update",
23 "tcp_ao_rcv_sne_update"
26 struct expected_trace_point
{
28 enum trace_events type
;
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
;
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
)
63 struct expected_trace_point new_tp
= {
84 if (!kernel_config_has(KCONFIG_FTRACE
))
87 pthread_mutex_lock(&exp_tps_mutex
);
88 if (exp_tps_nr
== exp_tps_size
) {
89 struct expected_trace_point
*tmp
;
91 if (exp_tps_size
== 0)
94 exp_tps_size
= exp_tps_size
* 1.6;
96 tmp
= reallocarray(exp_tps
, exp_tps_size
, sizeof(exp_tps
[0]));
103 exp_tps
[exp_tps_nr
] = new_tp
;
106 pthread_mutex_unlock(&exp_tps_mutex
);
110 static void free_expected_events(void)
112 /* We're from the process destructor - not taking the mutex */
122 unsigned int src_port
;
123 unsigned int dst_port
;
138 static bool lookup_expected_event(int event_type
, struct trace_point
*e
)
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
];
147 if (p
->type
!= event_type
)
149 if (p
->family
!= e
->family
)
151 if (p
->family
== AF_INET
)
152 sk_size
= sizeof(p
->src
.a4
);
154 sk_size
= sizeof(p
->src
.a6
);
155 if (memcmp(&p
->src
, &e
->src
, sk_size
))
157 if (memcmp(&p
->dst
, &e
->dst
, sk_size
))
159 if (p
->src_port
>= 0 && p
->src_port
!= e
->src_port
)
161 if (p
->dst_port
>= 0 && p
->dst_port
!= e
->dst_port
)
163 if (p
->L3index
>= 0 && p
->L3index
!= e
->L3index
)
166 if (p
->fin
>= 0 && p
->fin
!= e
->fin
)
168 if (p
->syn
>= 0 && p
->syn
!= e
->syn
)
170 if (p
->rst
>= 0 && p
->rst
!= e
->rst
)
172 if (p
->psh
>= 0 && p
->psh
!= e
->psh
)
174 if (p
->ack
>= 0 && p
->ack
!= e
->ack
)
177 if (p
->keyid
>= 0 && p
->keyid
!= e
->keyid
)
179 if (p
->rnext
>= 0 && p
->rnext
!= e
->rnext
)
181 if (p
->maclen
>= 0 && p
->maclen
!= e
->maclen
)
183 if (p
->sne
>= 0 && p
->sne
!= e
->sne
)
186 pthread_mutex_unlock(&exp_tps_mutex
);
189 pthread_mutex_unlock(&exp_tps_mutex
);
193 static int check_event_type(const char *line
)
198 * This should have been a set or hashmap, but it's a selftest,
201 for (i
= 0; i
< __MAX_TRACE_EVENTS
; i
++) {
202 if (!strncmp(trace_event_names
[i
], line
, strlen(trace_event_names
[i
])))
208 static bool event_has_flags(enum trace_events 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
:
227 static int tracer_ip_split(int family
, char *src
, char **addr
, char **port
)
231 if (family
== AF_INET
) {
232 /* fomat is <addr>:port, i.e.: 10.0.254.1:7015 */
234 p
= strchr(src
, ':');
236 test_print("Couldn't parse trace event addr:port %s", src
);
243 if (family
!= AF_INET6
)
244 return -EAFNOSUPPORT
;
246 /* format is [<addr>]:port, i.e.: [2001:db8:254::1]:7013 */
247 *addr
= strchr(src
, '[');
248 p
= strchr(src
, ']');
251 test_print("Couldn't parse trace event [addr]:port %s", src
);
255 *addr
= *addr
+ 1; /* '[' */
256 *p
++ = '\0'; /* ']' */
258 test_print("Couldn't parse trace event :port %s", p
);
261 *p
++ = '\0'; /* ':' */
266 static int tracer_scan_address(int family
, char *src
,
267 union tcp_addr
*dst
, unsigned int *port
)
269 char *addr
, *port_str
;
272 ret
= tracer_ip_split(family
, src
, &addr
, &port_str
);
276 if (inet_pton(family
, addr
, dst
) != 1) {
277 test_print("Couldn't parse trace event addr %s", addr
);
281 *port
= (unsigned int)strtoul(port_str
, NULL
, 10);
283 test_print("Couldn't parse trace event port %s", port_str
);
289 static int tracer_scan_event(const char *line
, enum trace_events event
,
290 struct trace_point
*out
)
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
;
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",
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",
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
);
332 test_print("Couldn't parse trace event, matched = %d/6",
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
);
342 test_print("Couldn't parse trace event, matched = %d/5",
351 if (!strcmp(family
, "AF_INET")) {
352 out
->family
= AF_INET
;
353 } else if (!strcmp(family
, "AF_INET6")) {
354 out
->family
= AF_INET6
;
356 test_print("Couldn't parse trace event family %s", family
);
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
== '.');
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
);
381 if (src
&& tracer_scan_address(out
->family
, src
, &out
->src
, &out
->src_port
)) {
386 if (dst
&& tracer_scan_address(out
->family
, dst
, &out
->dst
, &out
->dst_port
)) {
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
);
404 static enum ftracer_op
aolib_tracer_process_event(const char *line
)
406 int event_type
= check_event_type(line
);
407 struct trace_point tmp
= {};
410 return FTRACER_LINE_PRESERVE
;
412 if (tracer_scan_event(line
, event_type
, &tmp
))
413 return FTRACER_LINE_PRESERVE
;
415 return lookup_expected_event(event_type
, &tmp
) ?
416 FTRACER_LINE_DISCARD
: FTRACER_LINE_PRESERVE
;
419 static void dump_trace_event(struct expected_trace_point
*e
)
421 char src
[INET6_ADDRSTRLEN
], dst
[INET6_ADDRSTRLEN
];
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
);
438 static void print_match_stats(bool unexpected_events
)
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
;
445 for (i
= 0; i
< exp_tps_nr
; i
++) {
446 struct expected_trace_point
*e
= &exp_tps
[i
];
448 total_matched
+= e
->matched
;
449 matches_per_type
[e
->type
] += e
->matched
;
451 expected_but_none
= true;
453 for (i
= 0; i
< __MAX_TRACE_EVENTS
; i
++) {
454 if (!matches_per_type
[i
])
456 stat_line
= test_sprintf("%s%s[%zu] ", stat_line
?: "",
457 trace_event_names
[i
],
458 matches_per_type
[i
]);
460 test_error("test_sprintf()");
463 if (unexpected_events
|| expected_but_none
) {
464 for (i
= 0; i
< exp_tps_nr
; i
++)
465 dump_trace_event(&exp_tps
[i
]);
468 if (unexpected_events
)
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
);
477 test_ok("No unexpected trace events during the test run");
480 #define dump_events(fmt, ...) \
481 __test_print(__test_msg, fmt, ##__VA_ARGS__)
482 static void check_free_events(struct test_ftracer
*tracer
)
487 if (!kernel_config_has(KCONFIG_FTRACE
)) {
488 test_skip("kernel config doesn't have ftrace - no checks");
492 nr
= tracer_get_savedlines_nr(tracer
);
493 lines
= tracer_get_savedlines(tracer
);
494 print_match_stats(!!nr
);
499 test_xfail("Trace events [%zu] were not expected:", nr
);
501 dump_events("\t%s", lines
[--nr
]);
504 static int setup_tcp_trace_events(struct test_ftracer
*tracer
)
510 filter
= test_sprintf("net_cookie == %zu || net_cookie == %zu",
511 ns_cookie1
, ns_cookie2
);
515 for (i
= 0; i
< __MAX_TRACE_EVENTS
; i
++) {
516 char *event_name
= test_sprintf("tcp/%s", trace_event_names
[i
]);
522 ret
= setup_trace_event(tracer
, event_name
, filter
);
532 static void aolib_tracer_destroy(struct test_ftracer
*tracer
)
534 check_free_events(tracer
);
535 free_expected_events();
538 static bool aolib_tracer_expecting_more(void)
542 for (i
= 0; i
< exp_tps_nr
; i
++)
543 if (!exp_tps
[i
].matched
)
548 int setup_aolib_ftracer(void)
550 struct test_ftracer
*f
;
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
);
558 return setup_tcp_trace_events(f
);