net: add tcp drop stats

Upstream: no

Signed-off-by: Hongbo Li <herberthbli@tencent.com>
Signed-off-by: katrinzhou <katrinzhou@tencent.com>
Signed-off-by: Kairui Song <kasong@tencent.com>
This commit is contained in:
Hongbo Li 2023-11-16 18:25:38 +08:00 committed by Kairui Song
parent e52d5b5603
commit 8a4d973e43
8 changed files with 132 additions and 3 deletions

View File

@ -302,6 +302,11 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
#define NET_ADD_STATS(net, field, adnd) SNMP_ADD_STATS((net)->mib.net_statistics, field, adnd) #define NET_ADD_STATS(net, field, adnd) SNMP_ADD_STATS((net)->mib.net_statistics, field, adnd)
#define __NET_ADD_STATS(net, field, adnd) __SNMP_ADD_STATS((net)->mib.net_statistics, field, adnd) #define __NET_ADD_STATS(net, field, adnd) __SNMP_ADD_STATS((net)->mib.net_statistics, field, adnd)
#define NET_INC_DROPSTATS(net, field) \
SNMP_INC_STATS((net)->mib.netdrop_statistics, field)
#define __NET_INC_DROPSTATS(net, field) \
__SNMP_INC_STATS((net)->mib.netdrop_statistics, field)
static inline u64 snmp_get_cpu_field(void __percpu *mib, int cpu, int offt) static inline u64 snmp_get_cpu_field(void __percpu *mib, int cpu, int offt)
{ {
return *(((unsigned long *)per_cpu_ptr(mib, cpu)) + offt); return *(((unsigned long *)per_cpu_ptr(mib, cpu)) + offt);

View File

@ -12,6 +12,7 @@ struct netns_mib {
DEFINE_SNMP_STAT(struct tcp_mib, tcp_statistics); DEFINE_SNMP_STAT(struct tcp_mib, tcp_statistics);
DEFINE_SNMP_STAT(struct linux_mib, net_statistics); DEFINE_SNMP_STAT(struct linux_mib, net_statistics);
DEFINE_SNMP_STAT(struct linux_drop_mib, netdrop_statistics);
DEFINE_SNMP_STAT(struct udp_mib, udp_statistics); DEFINE_SNMP_STAT(struct udp_mib, udp_statistics);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)

View File

@ -117,6 +117,11 @@ struct linux_tls_mib {
unsigned long mibs[LINUX_MIB_TLSMAX]; unsigned long mibs[LINUX_MIB_TLSMAX];
}; };
#define LINUX_DROPSTAT_MIB_MAX __LINUX_DROPSTAT_MIB_MAX
struct linux_drop_mib {
unsigned long mibs[LINUX_DROPSTAT_MIB_MAX];
};
#define DEFINE_SNMP_STAT(type, name) \ #define DEFINE_SNMP_STAT(type, name) \
__typeof__(type) __percpu *name __typeof__(type) __percpu *name
#define DEFINE_SNMP_STAT_ATOMIC(type, name) \ #define DEFINE_SNMP_STAT_ATOMIC(type, name) \

View File

@ -353,4 +353,31 @@ enum
__LINUX_MIB_TLSMAX __LINUX_MIB_TLSMAX
}; };
enum {
LINUX_MIB_DROPSTAT_NUM = 0,
LINUX_MIB_TCPDQNODATADROP,
LINUX_MIB_TCPDQNOMEMDROP,
LINUX_MIB_TCPCHECKSEQDROP,
LINUX_MIB_TCPCHECKRSTDROP,
LINUX_MIB_TCPNOACKDROP,
LINUX_MIB_TCPINVALIDACKDROP,
LINUX_MIB_TCPRSTDROP,
LINUX_MIB_TCPNOSYNDROP,
LINUX_MIB_TCPPAWSDROP,
LINUX_MIB_TCPBADPKTDROP,
LINUX_MIB_TCPNOSOCKETDROP,
LINUX_MIB_TCPXFRMDROP,
LINUX_MIB_TCPFILTERDROP,
LINUX_MIB_TCPMD5DROP,
LINUX_MIB_TCPTWDROP,
LINUX_MIB_TCPRCVESTDROP,
LINUX_MIB_TCPNSKDROP,
LINUX_MIB_TCPCHILDPROCDROP,
LINUX_MIB_TCPRCVSTATEPROCDROP,
LINUX_MIB_TCPOFODUPDROP,
LINUX_MIB_TCPURGDROP,
LINUX_MIB_TCPOOWDROP,
__LINUX_DROPSTAT_MIB_MAX
};
#endif /* _LINUX_SNMP_H */ #endif /* _LINUX_SNMP_H */

View File

@ -1784,6 +1784,9 @@ static __net_init int ipv4_mib_init_net(struct net *net)
net->mib.net_statistics = alloc_percpu(struct linux_mib); net->mib.net_statistics = alloc_percpu(struct linux_mib);
if (!net->mib.net_statistics) if (!net->mib.net_statistics)
goto err_net_mib; goto err_net_mib;
net->mib.netdrop_statistics = alloc_percpu(struct linux_drop_mib);
if (!net->mib.netdrop_statistics)
goto err_netdrop_mib;
net->mib.udp_statistics = alloc_percpu(struct udp_mib); net->mib.udp_statistics = alloc_percpu(struct udp_mib);
if (!net->mib.udp_statistics) if (!net->mib.udp_statistics)
goto err_udp_mib; goto err_udp_mib;
@ -1808,6 +1811,8 @@ err_icmp_mib:
err_udplite_mib: err_udplite_mib:
free_percpu(net->mib.udp_statistics); free_percpu(net->mib.udp_statistics);
err_udp_mib: err_udp_mib:
free_percpu(net->mib.netdrop_statistics);
err_netdrop_mib:
free_percpu(net->mib.net_statistics); free_percpu(net->mib.net_statistics);
err_net_mib: err_net_mib:
free_percpu(net->mib.ip_statistics); free_percpu(net->mib.ip_statistics);
@ -1823,6 +1828,7 @@ static __net_exit void ipv4_mib_exit_net(struct net *net)
free_percpu(net->mib.icmp_statistics); free_percpu(net->mib.icmp_statistics);
free_percpu(net->mib.udplite_statistics); free_percpu(net->mib.udplite_statistics);
free_percpu(net->mib.udp_statistics); free_percpu(net->mib.udp_statistics);
free_percpu(net->mib.netdrop_statistics);
free_percpu(net->mib.net_statistics); free_percpu(net->mib.net_statistics);
free_percpu(net->mib.ip_statistics); free_percpu(net->mib.ip_statistics);
free_percpu(net->mib.tcp_statistics); free_percpu(net->mib.tcp_statistics);

View File

@ -520,6 +520,46 @@ static int netstat_seq_show(struct seq_file *seq, void *v)
return 0; return 0;
} }
static const struct snmp_mib snmp4_dropstat_list[] = {
SNMP_MIB_ITEM("TCPDataQueueNoDataDrop", LINUX_MIB_TCPDQNODATADROP),
SNMP_MIB_ITEM("TCPDataQueueNoMemDrop", LINUX_MIB_TCPDQNOMEMDROP),
SNMP_MIB_ITEM("TCPCheckSeqDrop", LINUX_MIB_TCPCHECKSEQDROP),
SNMP_MIB_ITEM("TCPCheckRstDrop", LINUX_MIB_TCPCHECKRSTDROP),
SNMP_MIB_ITEM("TCPNoAckDrop", LINUX_MIB_TCPNOACKDROP),
SNMP_MIB_ITEM("TCPInvalidAckDrop", LINUX_MIB_TCPINVALIDACKDROP),
SNMP_MIB_ITEM("TCPRstDrop", LINUX_MIB_TCPRSTDROP),
SNMP_MIB_ITEM("TCPNoSynDrop", LINUX_MIB_TCPNOSYNDROP),
SNMP_MIB_ITEM("TCPPawsDrop", LINUX_MIB_TCPPAWSDROP),
SNMP_MIB_ITEM("TCPBadPktDrop", LINUX_MIB_TCPBADPKTDROP),
SNMP_MIB_ITEM("TCPNoSocketDrop", LINUX_MIB_TCPNOSOCKETDROP),
SNMP_MIB_ITEM("TCPXfrmDrop", LINUX_MIB_TCPXFRMDROP),
SNMP_MIB_ITEM("TCPFilterDrop", LINUX_MIB_TCPFILTERDROP),
SNMP_MIB_ITEM("TCPMd5Drop", LINUX_MIB_TCPMD5DROP),
SNMP_MIB_ITEM("TCPTimewaitDrop", LINUX_MIB_TCPTWDROP),
SNMP_MIB_ITEM("TCPRcvEstDrop", LINUX_MIB_TCPRCVESTDROP),
SNMP_MIB_ITEM("TCPNewSkDrop", LINUX_MIB_TCPNSKDROP),
SNMP_MIB_ITEM("TCPChildProcDrop", LINUX_MIB_TCPCHILDPROCDROP),
SNMP_MIB_ITEM("TCPRcvStateProcDrop", LINUX_MIB_TCPRCVSTATEPROCDROP),
SNMP_MIB_ITEM("TCPOfoDupDrop", LINUX_MIB_TCPOFODUPDROP),
SNMP_MIB_ITEM("TCPUrgDrop", LINUX_MIB_TCPURGDROP),
SNMP_MIB_ITEM("TCPOutOfWindowDrop", LINUX_MIB_TCPOOWDROP),
SNMP_MIB_SENTINEL
};
/* Output /proc/net/dropstat */
static int dropstat_seq_show(struct seq_file *seq, void *v)
{
struct net *net = seq->private;
int i;
for (i = 0; snmp4_dropstat_list[i].name; i++)
seq_printf(seq, "%s : %lu\n", snmp4_dropstat_list[i].name,
snmp_fold_field(net->mib.netdrop_statistics,
snmp4_dropstat_list[i].entry));
return 0;
}
static __net_init int ip_proc_init_net(struct net *net) static __net_init int ip_proc_init_net(struct net *net)
{ {
if (!proc_create_net_single("sockstat", 0444, net->proc_net, if (!proc_create_net_single("sockstat", 0444, net->proc_net,
@ -531,9 +571,15 @@ static __net_init int ip_proc_init_net(struct net *net)
if (!proc_create_net_single("snmp", 0444, net->proc_net, snmp_seq_show, if (!proc_create_net_single("snmp", 0444, net->proc_net, snmp_seq_show,
NULL)) NULL))
goto out_snmp; goto out_snmp;
if (!proc_create_net_single("dropstat", 0444, net->proc_net,
dropstat_seq_show, NULL))
goto out_dropstat;
return 0; return 0;
out_dropstat:
remove_proc_entry("snmp", net->proc_net);
out_snmp: out_snmp:
remove_proc_entry("netstat", net->proc_net); remove_proc_entry("netstat", net->proc_net);
out_netstat: out_netstat:
@ -547,6 +593,7 @@ static __net_exit void ip_proc_exit_net(struct net *net)
remove_proc_entry("snmp", net->proc_net); remove_proc_entry("snmp", net->proc_net);
remove_proc_entry("netstat", net->proc_net); remove_proc_entry("netstat", net->proc_net);
remove_proc_entry("sockstat", net->proc_net); remove_proc_entry("sockstat", net->proc_net);
remove_proc_entry("dropstat", net->proc_net);
} }
static __net_initdata struct pernet_operations ip_proc_ops = { static __net_initdata struct pernet_operations ip_proc_ops = {

View File

@ -4772,6 +4772,8 @@ static void tcp_ofo_queue(struct sock *sk)
if (unlikely(!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt))) { if (unlikely(!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt))) {
tcp_drop_reason(sk, skb, SKB_DROP_REASON_TCP_OFO_DROP); tcp_drop_reason(sk, skb, SKB_DROP_REASON_TCP_OFO_DROP);
NET_INC_DROPSTATS(sock_net(sk),
LINUX_MIB_TCPOFODUPDROP);
continue; continue;
} }
@ -5051,6 +5053,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
} }
if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) { if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) {
NET_INC_DROPSTATS(sock_net(sk), LINUX_MIB_TCPDQNODATADROP);
__kfree_skb(skb); __kfree_skb(skb);
return; return;
} }
@ -5124,6 +5127,7 @@ queue_and_out:
tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq);
out_of_window: out_of_window:
NET_INC_DROPSTATS(sock_net(sk), LINUX_MIB_TCPOOWDROP);
tcp_enter_quickack_mode(sk, TCP_MAX_QUICKACKS); tcp_enter_quickack_mode(sk, TCP_MAX_QUICKACKS);
inet_csk_schedule_ack(sk); inet_csk_schedule_ack(sk);
drop: drop:
@ -5682,6 +5686,8 @@ static void tcp_check_urg(struct sock *sk, const struct tcphdr *th)
if (skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq)) { if (skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq)) {
__skb_unlink(skb, &sk->sk_receive_queue); __skb_unlink(skb, &sk->sk_receive_queue);
__kfree_skb(skb); __kfree_skb(skb);
NET_INC_DROPSTATS(sock_net(sk),
LINUX_MIB_TCPURGDROP);
} }
} }
@ -5781,6 +5787,7 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
} else if (tcp_reset_check(sk, skb)) { } else if (tcp_reset_check(sk, skb)) {
goto reset; goto reset;
} }
NET_INC_DROPSTATS(sock_net(sk), LINUX_MIB_TCPCHECKSEQDROP);
goto discard; goto discard;
} }
@ -5824,6 +5831,7 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
tcp_fastopen_active_disable(sk); tcp_fastopen_active_disable(sk);
tcp_send_challenge_ack(sk); tcp_send_challenge_ack(sk);
SKB_DR_SET(reason, TCP_RESET); SKB_DR_SET(reason, TCP_RESET);
NET_INC_DROPSTATS(sock_net(sk), LINUX_MIB_TCPCHECKRSTDROP);
goto discard; goto discard;
} }
@ -6043,8 +6051,10 @@ step5:
reason = tcp_ack(sk, skb, FLAG_SLOWPATH | FLAG_UPDATE_TS_RECENT); reason = tcp_ack(sk, skb, FLAG_SLOWPATH | FLAG_UPDATE_TS_RECENT);
if ((int)reason < 0) { if ((int)reason < 0) {
reason = -reason; reason = -reason;
NET_INC_DROPSTATS(sock_net(sk), LINUX_MIB_TCPINVALIDACKDROP);
goto discard; goto discard;
} }
tcp_rcv_rtt_measure_ts(sk, skb); tcp_rcv_rtt_measure_ts(sk, skb);
/* Process urgent data. */ /* Process urgent data. */
@ -6267,6 +6277,8 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
tcp_reset(sk, skb); tcp_reset(sk, skb);
consume: consume:
__kfree_skb(skb); __kfree_skb(skb);
NET_INC_DROPSTATS(sock_net(sk),
LINUX_MIB_TCPRCVSTATEPROCDROP);
return 0; return 0;
} }
@ -6279,8 +6291,11 @@ consume:
*/ */
if (!th->syn) { if (!th->syn) {
SKB_DR_SET(reason, TCP_FLAGS); SKB_DR_SET(reason, TCP_FLAGS);
NET_INC_DROPSTATS(sock_net(sk),
LINUX_MIB_TCPNOSYNDROP);
goto discard_and_undo; goto discard_and_undo;
} }
/* rfc793: /* rfc793:
* "If the SYN bit is on ... * "If the SYN bit is on ...
* are acceptable then ... * are acceptable then ...
@ -6372,6 +6387,7 @@ consume:
* Otherwise (no ACK) drop the segment and return." * Otherwise (no ACK) drop the segment and return."
*/ */
SKB_DR_SET(reason, TCP_RESET); SKB_DR_SET(reason, TCP_RESET);
NET_INC_DROPSTATS(sock_net(sk), LINUX_MIB_TCPRSTDROP);
goto discard_and_undo; goto discard_and_undo;
} }
@ -6379,8 +6395,10 @@ consume:
if (tp->rx_opt.ts_recent_stamp && tp->rx_opt.saw_tstamp && if (tp->rx_opt.ts_recent_stamp && tp->rx_opt.saw_tstamp &&
tcp_paws_reject(&tp->rx_opt, 0)) { tcp_paws_reject(&tp->rx_opt, 0)) {
SKB_DR_SET(reason, TCP_RFC7323_PAWS); SKB_DR_SET(reason, TCP_RFC7323_PAWS);
NET_INC_DROPSTATS(sock_net(sk), LINUX_MIB_TCPPAWSDROP);
goto discard_and_undo; goto discard_and_undo;
} }
if (th->syn) { if (th->syn) {
/* We see SYN without ACK. It is attempt of /* We see SYN without ACK. It is attempt of
* simultaneous connect with crossed SYNs. * simultaneous connect with crossed SYNs.
@ -6440,6 +6458,8 @@ discard_and_undo:
tcp_clear_options(&tp->rx_opt); tcp_clear_options(&tp->rx_opt);
tp->rx_opt.mss_clamp = saved_clamp; tp->rx_opt.mss_clamp = saved_clamp;
tcp_drop_reason(sk, skb, reason); tcp_drop_reason(sk, skb, reason);
NET_INC_DROPSTATS(sock_net(sk),
LINUX_MIB_TCPRCVSTATEPROCDROP);
return 0; return 0;
reset_and_undo: reset_and_undo:
@ -6565,8 +6585,10 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb)
if (!th->ack && !th->rst && !th->syn) { if (!th->ack && !th->rst && !th->syn) {
SKB_DR_SET(reason, TCP_FLAGS); SKB_DR_SET(reason, TCP_FLAGS);
NET_INC_DROPSTATS(sock_net(sk), LINUX_MIB_TCPNOACKDROP);
goto discard; goto discard;
} }
if (!tcp_validate_incoming(sk, skb, th, 0)) if (!tcp_validate_incoming(sk, skb, th, 0))
return 0; return 0;

View File

@ -1741,6 +1741,8 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
if (nsk != sk) { if (nsk != sk) {
if (tcp_child_process(sk, nsk, skb)) { if (tcp_child_process(sk, nsk, skb)) {
rsk = nsk; rsk = nsk;
NET_INC_DROPSTATS(sock_net(sk),
LINUX_MIB_TCPCHILDPROCDROP);
goto reset; goto reset;
} }
return 0; return 0;
@ -1750,6 +1752,8 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
if (tcp_rcv_state_process(sk, skb)) { if (tcp_rcv_state_process(sk, skb)) {
rsk = sk; rsk = sk;
NET_INC_DROPSTATS(sock_net(sk),
LINUX_MIB_TCPRCVSTATEPROCDROP);
goto reset; goto reset;
} }
return 0; return 0;
@ -1999,8 +2003,10 @@ int tcp_v4_rcv(struct sk_buff *skb)
/* Count it even if it's bad */ /* Count it even if it's bad */
__TCP_INC_STATS(net, TCP_MIB_INSEGS); __TCP_INC_STATS(net, TCP_MIB_INSEGS);
if (!pskb_may_pull(skb, sizeof(struct tcphdr))) if (!pskb_may_pull(skb, sizeof(struct tcphdr))) {
__NET_INC_DROPSTATS(net, LINUX_MIB_TCPBADPKTDROP);
goto discard_it; goto discard_it;
}
th = (const struct tcphdr *)skb->data; th = (const struct tcphdr *)skb->data;
@ -2008,8 +2014,10 @@ int tcp_v4_rcv(struct sk_buff *skb)
drop_reason = SKB_DROP_REASON_PKT_TOO_SMALL; drop_reason = SKB_DROP_REASON_PKT_TOO_SMALL;
goto bad_packet; goto bad_packet;
} }
if (!pskb_may_pull(skb, th->doff * 4)) if (!pskb_may_pull(skb, th->doff * 4)) {
__NET_INC_DROPSTATS(net, LINUX_MIB_TCPBADPKTDROP);
goto discard_it; goto discard_it;
}
/* An explanation is required here, I think. /* An explanation is required here, I think.
* Packet length and doff are validated by header prediction, * Packet length and doff are validated by header prediction,
@ -2047,6 +2055,7 @@ process:
if (unlikely(drop_reason)) { if (unlikely(drop_reason)) {
sk_drops_add(sk, skb); sk_drops_add(sk, skb);
reqsk_put(req); reqsk_put(req);
__NET_INC_DROPSTATS(net, LINUX_MIB_TCPMD5DROP);
goto discard_it; goto discard_it;
} }
if (tcp_checksum_complete(skb)) { if (tcp_checksum_complete(skb)) {
@ -2117,18 +2126,22 @@ process:
if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) { if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) {
drop_reason = SKB_DROP_REASON_XFRM_POLICY; drop_reason = SKB_DROP_REASON_XFRM_POLICY;
__NET_INC_DROPSTATS(net, LINUX_MIB_TCPXFRMDROP);
goto discard_and_relse; goto discard_and_relse;
} }
drop_reason = tcp_inbound_md5_hash(sk, skb, &iph->saddr, drop_reason = tcp_inbound_md5_hash(sk, skb, &iph->saddr,
&iph->daddr, AF_INET, dif, sdif); &iph->daddr, AF_INET, dif, sdif);
if (drop_reason) if (drop_reason) {
__NET_INC_DROPSTATS(net, LINUX_MIB_TCPMD5DROP);
goto discard_and_relse; goto discard_and_relse;
}
nf_reset_ct(skb); nf_reset_ct(skb);
if (tcp_filter(sk, skb)) { if (tcp_filter(sk, skb)) {
drop_reason = SKB_DROP_REASON_SOCKET_FILTER; drop_reason = SKB_DROP_REASON_SOCKET_FILTER;
__NET_INC_DROPSTATS(net, LINUX_MIB_TCPFILTERDROP);
goto discard_and_relse; goto discard_and_relse;
} }
th = (const struct tcphdr *)skb->data; th = (const struct tcphdr *)skb->data;
@ -2162,6 +2175,7 @@ put_and_return:
return ret; return ret;
no_tcp_socket: no_tcp_socket:
__NET_INC_DROPSTATS(net, LINUX_MIB_TCPNOSOCKETDROP);
drop_reason = SKB_DROP_REASON_NO_SOCKET; drop_reason = SKB_DROP_REASON_NO_SOCKET;
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
goto discard_it; goto discard_it;
@ -2195,6 +2209,7 @@ do_time_wait:
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
drop_reason = SKB_DROP_REASON_XFRM_POLICY; drop_reason = SKB_DROP_REASON_XFRM_POLICY;
inet_twsk_put(inet_twsk(sk)); inet_twsk_put(inet_twsk(sk));
__NET_INC_DROPSTATS(net, LINUX_MIB_TCPXFRMDROP);
goto discard_it; goto discard_it;
} }
@ -2232,6 +2247,7 @@ do_time_wait:
goto discard_it; goto discard_it;
case TCP_TW_SUCCESS:; case TCP_TW_SUCCESS:;
} }
__NET_INC_DROPSTATS(net, LINUX_MIB_TCPTWDROP);
goto discard_it; goto discard_it;
} }