Skip to content

Commit 96be3dc

Browse files
0x7f454c46davem330
authored andcommitted
net/tcp: Add tcp-md5 and tcp-ao tracepoints
Instead of forcing userspace to parse dmesg (that's what currently is happening, at least in codebase of my current company), provide a better way, that can be enabled/disabled in runtime. Currently, there are already tcp events, add hashing related ones there, too. Rasdaemon currently exercises net_dev_xmit_timeout, devlink_health_report, but it'll be trivial to teach it to deal with failed hashes. Otherwise, BGP may trace/log them itself. Especially exciting for possible investigations is key rotation (RNext_key requests). Suggested-by: Jakub Kicinski <[email protected]> Signed-off-by: Dmitry Safonov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 811efc0 commit 96be3dc

File tree

5 files changed

+355
-2
lines changed

5 files changed

+355
-2
lines changed

include/trace/events/tcp.h

Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,323 @@ TRACE_EVENT(tcp_cong_state_set,
411411
__entry->cong_state)
412412
);
413413

414+
DECLARE_EVENT_CLASS(tcp_hash_event,
415+
416+
TP_PROTO(const struct sock *sk, const struct sk_buff *skb),
417+
418+
TP_ARGS(sk, skb),
419+
420+
TP_STRUCT__entry(
421+
__field(__u64, net_cookie)
422+
__field(const void *, skbaddr)
423+
__field(const void *, skaddr)
424+
__field(int, state)
425+
426+
/* sockaddr_in6 is always bigger than sockaddr_in */
427+
__array(__u8, saddr, sizeof(struct sockaddr_in6))
428+
__array(__u8, daddr, sizeof(struct sockaddr_in6))
429+
__field(int, l3index)
430+
431+
__field(__u16, sport)
432+
__field(__u16, dport)
433+
__field(__u16, family)
434+
435+
__field(bool, fin)
436+
__field(bool, syn)
437+
__field(bool, rst)
438+
__field(bool, psh)
439+
__field(bool, ack)
440+
),
441+
442+
TP_fast_assign(
443+
const struct tcphdr *th = (const struct tcphdr *)skb->data;
444+
445+
__entry->net_cookie = sock_net(sk)->net_cookie;
446+
__entry->skbaddr = skb;
447+
__entry->skaddr = sk;
448+
__entry->state = sk->sk_state;
449+
450+
memset(__entry->saddr, 0, sizeof(struct sockaddr_in6));
451+
memset(__entry->daddr, 0, sizeof(struct sockaddr_in6));
452+
TP_STORE_ADDR_PORTS_SKB(skb, th, __entry->saddr, __entry->daddr);
453+
__entry->l3index = inet_sdif(skb) ? inet_iif(skb) : 0;
454+
455+
/* For filtering use */
456+
__entry->sport = ntohs(th->source);
457+
__entry->dport = ntohs(th->dest);
458+
__entry->family = sk->sk_family;
459+
460+
__entry->fin = th->fin;
461+
__entry->syn = th->syn;
462+
__entry->rst = th->rst;
463+
__entry->psh = th->psh;
464+
__entry->ack = th->ack;
465+
),
466+
467+
TP_printk("net=%llu state=%s family=%s src=%pISpc dest=%pISpc L3index=%d [%c%c%c%c%c]",
468+
__entry->net_cookie,
469+
show_tcp_state_name(__entry->state),
470+
show_family_name(__entry->family),
471+
__entry->saddr, __entry->daddr,
472+
__entry->l3index,
473+
__entry->fin ? 'F' : ' ',
474+
__entry->syn ? 'S' : ' ',
475+
__entry->rst ? 'R' : ' ',
476+
__entry->psh ? 'P' : ' ',
477+
__entry->ack ? '.' : ' ')
478+
);
479+
480+
DEFINE_EVENT(tcp_hash_event, tcp_hash_bad_header,
481+
482+
TP_PROTO(const struct sock *sk, const struct sk_buff *skb),
483+
TP_ARGS(sk, skb)
484+
);
485+
486+
DEFINE_EVENT(tcp_hash_event, tcp_hash_md5_required,
487+
488+
TP_PROTO(const struct sock *sk, const struct sk_buff *skb),
489+
TP_ARGS(sk, skb)
490+
);
491+
492+
DEFINE_EVENT(tcp_hash_event, tcp_hash_md5_unexpected,
493+
494+
TP_PROTO(const struct sock *sk, const struct sk_buff *skb),
495+
TP_ARGS(sk, skb)
496+
);
497+
498+
DEFINE_EVENT(tcp_hash_event, tcp_hash_md5_mismatch,
499+
500+
TP_PROTO(const struct sock *sk, const struct sk_buff *skb),
501+
TP_ARGS(sk, skb)
502+
);
503+
504+
DEFINE_EVENT(tcp_hash_event, tcp_hash_ao_required,
505+
506+
TP_PROTO(const struct sock *sk, const struct sk_buff *skb),
507+
TP_ARGS(sk, skb)
508+
);
509+
510+
DECLARE_EVENT_CLASS(tcp_ao_event,
511+
512+
TP_PROTO(const struct sock *sk, const struct sk_buff *skb,
513+
const __u8 keyid, const __u8 rnext, const __u8 maclen),
514+
515+
TP_ARGS(sk, skb, keyid, rnext, maclen),
516+
517+
TP_STRUCT__entry(
518+
__field(__u64, net_cookie)
519+
__field(const void *, skbaddr)
520+
__field(const void *, skaddr)
521+
__field(int, state)
522+
523+
/* sockaddr_in6 is always bigger than sockaddr_in */
524+
__array(__u8, saddr, sizeof(struct sockaddr_in6))
525+
__array(__u8, daddr, sizeof(struct sockaddr_in6))
526+
__field(int, l3index)
527+
528+
__field(__u16, sport)
529+
__field(__u16, dport)
530+
__field(__u16, family)
531+
532+
__field(bool, fin)
533+
__field(bool, syn)
534+
__field(bool, rst)
535+
__field(bool, psh)
536+
__field(bool, ack)
537+
538+
__field(__u8, keyid)
539+
__field(__u8, rnext)
540+
__field(__u8, maclen)
541+
),
542+
543+
TP_fast_assign(
544+
const struct tcphdr *th = (const struct tcphdr *)skb->data;
545+
546+
__entry->net_cookie = sock_net(sk)->net_cookie;
547+
__entry->skbaddr = skb;
548+
__entry->skaddr = sk;
549+
__entry->state = sk->sk_state;
550+
551+
memset(__entry->saddr, 0, sizeof(struct sockaddr_in6));
552+
memset(__entry->daddr, 0, sizeof(struct sockaddr_in6));
553+
TP_STORE_ADDR_PORTS_SKB(skb, th, __entry->saddr, __entry->daddr);
554+
__entry->l3index = inet_sdif(skb) ? inet_iif(skb) : 0;
555+
556+
/* For filtering use */
557+
__entry->sport = ntohs(th->source);
558+
__entry->dport = ntohs(th->dest);
559+
__entry->family = sk->sk_family;
560+
561+
__entry->fin = th->fin;
562+
__entry->syn = th->syn;
563+
__entry->rst = th->rst;
564+
__entry->psh = th->psh;
565+
__entry->ack = th->ack;
566+
567+
__entry->keyid = keyid;
568+
__entry->rnext = rnext;
569+
__entry->maclen = maclen;
570+
),
571+
572+
TP_printk("net=%llu state=%s family=%s src=%pISpc dest=%pISpc L3index=%d [%c%c%c%c%c] keyid=%u rnext=%u maclen=%u",
573+
__entry->net_cookie,
574+
show_tcp_state_name(__entry->state),
575+
show_family_name(__entry->family),
576+
__entry->saddr, __entry->daddr,
577+
__entry->l3index,
578+
__entry->fin ? 'F' : ' ',
579+
__entry->syn ? 'S' : ' ',
580+
__entry->rst ? 'R' : ' ',
581+
__entry->psh ? 'P' : ' ',
582+
__entry->ack ? '.' : ' ',
583+
__entry->keyid, __entry->rnext, __entry->maclen)
584+
);
585+
586+
DEFINE_EVENT(tcp_ao_event, tcp_ao_handshake_failure,
587+
TP_PROTO(const struct sock *sk, const struct sk_buff *skb,
588+
const __u8 keyid, const __u8 rnext, const __u8 maclen),
589+
TP_ARGS(sk, skb, keyid, rnext, maclen)
590+
);
591+
592+
DEFINE_EVENT(tcp_ao_event, tcp_ao_wrong_maclen,
593+
TP_PROTO(const struct sock *sk, const struct sk_buff *skb,
594+
const __u8 keyid, const __u8 rnext, const __u8 maclen),
595+
TP_ARGS(sk, skb, keyid, rnext, maclen)
596+
);
597+
598+
DEFINE_EVENT(tcp_ao_event, tcp_ao_mismatch,
599+
TP_PROTO(const struct sock *sk, const struct sk_buff *skb,
600+
const __u8 keyid, const __u8 rnext, const __u8 maclen),
601+
TP_ARGS(sk, skb, keyid, rnext, maclen)
602+
);
603+
604+
DEFINE_EVENT(tcp_ao_event, tcp_ao_key_not_found,
605+
TP_PROTO(const struct sock *sk, const struct sk_buff *skb,
606+
const __u8 keyid, const __u8 rnext, const __u8 maclen),
607+
TP_ARGS(sk, skb, keyid, rnext, maclen)
608+
);
609+
610+
DEFINE_EVENT(tcp_ao_event, tcp_ao_rnext_request,
611+
TP_PROTO(const struct sock *sk, const struct sk_buff *skb,
612+
const __u8 keyid, const __u8 rnext, const __u8 maclen),
613+
TP_ARGS(sk, skb, keyid, rnext, maclen)
614+
);
615+
616+
DECLARE_EVENT_CLASS(tcp_ao_event_sk,
617+
618+
TP_PROTO(const struct sock *sk, const __u8 keyid, const __u8 rnext),
619+
620+
TP_ARGS(sk, keyid, rnext),
621+
622+
TP_STRUCT__entry(
623+
__field(__u64, net_cookie)
624+
__field(const void *, skaddr)
625+
__field(int, state)
626+
627+
/* sockaddr_in6 is always bigger than sockaddr_in */
628+
__array(__u8, saddr, sizeof(struct sockaddr_in6))
629+
__array(__u8, daddr, sizeof(struct sockaddr_in6))
630+
631+
__field(__u16, sport)
632+
__field(__u16, dport)
633+
__field(__u16, family)
634+
635+
__field(__u8, keyid)
636+
__field(__u8, rnext)
637+
),
638+
639+
TP_fast_assign(
640+
const struct inet_sock *inet = inet_sk(sk);
641+
642+
__entry->net_cookie = sock_net(sk)->net_cookie;
643+
__entry->skaddr = sk;
644+
__entry->state = sk->sk_state;
645+
646+
memset(__entry->saddr, 0, sizeof(struct sockaddr_in6));
647+
memset(__entry->daddr, 0, sizeof(struct sockaddr_in6));
648+
TP_STORE_ADDR_PORTS(__entry, inet, sk);
649+
650+
/* For filtering use */
651+
__entry->sport = ntohs(inet->inet_sport);
652+
__entry->dport = ntohs(inet->inet_dport);
653+
__entry->family = sk->sk_family;
654+
655+
__entry->keyid = keyid;
656+
__entry->rnext = rnext;
657+
),
658+
659+
TP_printk("net=%llu state=%s family=%s src=%pISpc dest=%pISpc keyid=%u rnext=%u",
660+
__entry->net_cookie,
661+
show_tcp_state_name(__entry->state),
662+
show_family_name(__entry->family),
663+
__entry->saddr, __entry->daddr,
664+
__entry->keyid, __entry->rnext)
665+
);
666+
667+
DEFINE_EVENT(tcp_ao_event_sk, tcp_ao_synack_no_key,
668+
TP_PROTO(const struct sock *sk, const __u8 keyid, const __u8 rnext),
669+
TP_ARGS(sk, keyid, rnext)
670+
);
671+
672+
DECLARE_EVENT_CLASS(tcp_ao_event_sne,
673+
674+
TP_PROTO(const struct sock *sk, __u32 new_sne),
675+
676+
TP_ARGS(sk, new_sne),
677+
678+
TP_STRUCT__entry(
679+
__field(__u64, net_cookie)
680+
__field(const void *, skaddr)
681+
__field(int, state)
682+
683+
/* sockaddr_in6 is always bigger than sockaddr_in */
684+
__array(__u8, saddr, sizeof(struct sockaddr_in6))
685+
__array(__u8, daddr, sizeof(struct sockaddr_in6))
686+
687+
__field(__u16, sport)
688+
__field(__u16, dport)
689+
__field(__u16, family)
690+
691+
__field(__u32, new_sne)
692+
),
693+
694+
TP_fast_assign(
695+
const struct inet_sock *inet = inet_sk(sk);
696+
697+
__entry->net_cookie = sock_net(sk)->net_cookie;
698+
__entry->skaddr = sk;
699+
__entry->state = sk->sk_state;
700+
701+
memset(__entry->saddr, 0, sizeof(struct sockaddr_in6));
702+
memset(__entry->daddr, 0, sizeof(struct sockaddr_in6));
703+
TP_STORE_ADDR_PORTS(__entry, inet, sk);
704+
705+
/* For filtering use */
706+
__entry->sport = ntohs(inet->inet_sport);
707+
__entry->dport = ntohs(inet->inet_dport);
708+
__entry->family = sk->sk_family;
709+
710+
__entry->new_sne = new_sne;
711+
),
712+
713+
TP_printk("net=%llu state=%s family=%s src=%pISpc dest=%pISpc sne=%u",
714+
__entry->net_cookie,
715+
show_tcp_state_name(__entry->state),
716+
show_family_name(__entry->family),
717+
__entry->saddr, __entry->daddr,
718+
__entry->new_sne)
719+
);
720+
721+
DEFINE_EVENT(tcp_ao_event_sne, tcp_ao_snd_sne_update,
722+
TP_PROTO(const struct sock *sk, __u32 new_sne),
723+
TP_ARGS(sk, new_sne)
724+
);
725+
726+
DEFINE_EVENT(tcp_ao_event_sne, tcp_ao_rcv_sne_update,
727+
TP_PROTO(const struct sock *sk, __u32 new_sne),
728+
TP_ARGS(sk, new_sne)
729+
);
730+
414731
#endif /* _TRACE_TCP_H */
415732

416733
/* This part must be outside protection */

net/ipv4/tcp.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@
282282
#include <asm/ioctls.h>
283283
#include <net/busy_poll.h>
284284
#include <net/hotdata.h>
285+
#include <trace/events/tcp.h>
285286
#include <net/rps.h>
286287

287288
/* Track pending CMSGs. */
@@ -4484,6 +4485,7 @@ tcp_inbound_md5_hash(const struct sock *sk, const struct sk_buff *skb,
44844485
if (!key && hash_location) {
44854486
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5UNEXPECTED);
44864487
tcp_hash_fail("Unexpected MD5 Hash found", family, skb, "");
4488+
trace_tcp_hash_md5_unexpected(sk, skb);
44874489
return SKB_DROP_REASON_TCP_MD5UNEXPECTED;
44884490
}
44894491

@@ -4513,6 +4515,7 @@ tcp_inbound_md5_hash(const struct sock *sk, const struct sk_buff *skb,
45134515
l3index);
45144516
}
45154517
}
4518+
trace_tcp_hash_md5_mismatch(sk, skb);
45164519
return SKB_DROP_REASON_TCP_MD5FAILURE;
45174520
}
45184521
return SKB_NOT_DROPPED_YET;
@@ -4544,15 +4547,27 @@ tcp_inbound_hash(struct sock *sk, const struct request_sock *req,
45444547
if (tcp_parse_auth_options(th, &md5_location, &aoh)) {
45454548
tcp_hash_fail("TCP segment has incorrect auth options set",
45464549
family, skb, "");
4550+
trace_tcp_hash_bad_header(sk, skb);
45474551
return SKB_DROP_REASON_TCP_AUTH_HDR;
45484552
}
45494553

45504554
if (req) {
45514555
if (tcp_rsk_used_ao(req) != !!aoh) {
4556+
u8 keyid, rnext, maclen;
4557+
4558+
if (aoh) {
4559+
keyid = aoh->keyid;
4560+
rnext = aoh->rnext_keyid;
4561+
maclen = tcp_ao_hdr_maclen(aoh);
4562+
} else {
4563+
keyid = rnext = maclen = 0;
4564+
}
4565+
45524566
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAOBAD);
45534567
tcp_hash_fail("TCP connection can't start/end using TCP-AO",
45544568
family, skb, "%s",
45554569
!aoh ? "missing AO" : "AO signed");
4570+
trace_tcp_ao_handshake_failure(sk, skb, keyid, rnext, maclen);
45564571
return SKB_DROP_REASON_TCP_AOFAILURE;
45574572
}
45584573
}
@@ -4572,12 +4587,14 @@ tcp_inbound_hash(struct sock *sk, const struct request_sock *req,
45724587
if (tcp_ao_required(sk, saddr, family, l3index, true)) {
45734588
tcp_hash_fail("AO hash is required, but not found",
45744589
family, skb, "L3 index %d", l3index);
4590+
trace_tcp_hash_ao_required(sk, skb);
45754591
return SKB_DROP_REASON_TCP_AONOTFOUND;
45764592
}
45774593
if (unlikely(tcp_md5_do_lookup(sk, l3index, saddr, family))) {
45784594
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND);
45794595
tcp_hash_fail("MD5 Hash not found",
45804596
family, skb, "L3 index %d", l3index);
4597+
trace_tcp_hash_md5_required(sk, skb);
45814598
return SKB_DROP_REASON_TCP_MD5NOTFOUND;
45824599
}
45834600
return SKB_NOT_DROPPED_YET;

0 commit comments

Comments
 (0)