写在前面,查netstat -st的相关信息时,意外获悉nstat这个命令,好使的狠,大家可以试试,部分表格整理来自网络
常用的查看丢包的命令
netstat -st | egrep -i "drop|reject|overflowed|listen|filter|reset"
--------------------------快乐的分割线------------------
当执行以下命令查看netstat统计信息来源时,发现一个重要的来源是/proc/net/snmp接口的输出信息,对该文件做下相关的解读,以便后续更加透彻的理解netstat的统计信息。
# strace -e open netstat -s
注:netstat -s的另一个重要的数据来源是/proc/net/netstat下的信息,但鉴于
该接口信息量较大,因此会单独独立整理。
该接口可视化脚本
cat /proc/net/netstat | awk '(f==0) {name=$1; i=2; while ( i<=NF) {n[i] = $i; i++ }; f=1; next} (f==1){ i=2; while ( i<=NF){ printf "%s%s = %d\n", name, n[i], $i; i++}; f=0} '
snmp4_tcp_list数组元素解析
netstat -s的Tcp类选的数据均来自内核中定义的snmp4_tcp_list数组。
struct snmp_mib {
const char *name;
int entry;
};
snmp4_tcp_list数组就是/proc/net/snmp接口输出的TCP部分内容
名称 |
描述 |
Linux 3.10实现 |
RtoAlgorithm |
用于计算RTO的算法 |
RTO算法遵循RFC2698,对应值为1. |
RtoMin |
限定RTO的最小值 |
使用常量HZ/5限定,即200ms |
RtoMax |
限定RTO的最大值 |
使用常量120HZ限定,即120s |
MaxConn |
TCP流数量的上限 |
并不会在协议栈层限制,默认值为-1 |
ActiveOpens |
CLOSE => SYN-SENT次数 |
在tcp_connect()函数中计数 |
PassiveOpens |
LISTEN => SYN-RECV次数 |
实现上则是在三次握手成功后, |
AttemptFails |
SYN-SENT => CLOSE次数 |
回CLOSE部分在tcp_done()函数中计数, |
EstabResets |
ESTABLISHED => CLOSE次数 |
在tcp_set_state()函数中,如果之前的状态是 |
CurrEstab |
ESTABLISHED和CLOSE-WAIT |
在tcp_set_state()中处理 |
InSegs |
所有收到的TCP包 |
在tcp_v4_rcv()和tcp_v6_rcv()中计数 |
OutSegs |
所有发送出去的TCP包 |
tcp_v4_send_reset()中统计reset包 |
RetransSegs |
所有重传出去的TCP包 |
tcp_v4_rtx_synack()和tcp_v6_rtx_synack()中 |
InErrs |
所有收到的有问题的TCP包数量 |
tcp_validate_incoming()中统计seq有问题的包 |
OutRsts |
发送的带RST标记的TCP包数量 |
在tcp_v4_send_reset()、tcp_send_active_reset()、 |
InCsumErrors |
checksum有问题的数据包数量 |
是3.10相对于2.6.32新增的内容,算是细化InErrs统计 |
snmp4_tcp_list统计结果实例一则
# cat /proc/net/snmp |grep Tcp /* 适当调整了输个格式,以增加可读性 */
Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails
Tcp: 1 200 120000 -1 818674494 564859834 83498657
EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors
38663863 4790 213696000469 253602471635 2134386615 18675977 171550781 125433
netstat -st输出的两个重要信息来源分别是/proc/net/snmp和/proc/net/netstat
a. 分类整理:根据涉及的不同TCP细节,对counter做更细致的分类
b. 结合sysctl配置:强调sysctl配置与counter之间的关联
c. 强调异常:哪些counter出现非零值,往往就意味着出现了值得关注的问题
d. 信息抽取: 如何从counter中获取有价值的信息
e. 仅关注TCP相关计数器
计数器分类
类别 |
涉及counters |
常量 |
RtoAlgorithm、RtoMin、RtoMax、MaxConn |
建连统计 |
ActiveOpens、PassiveOpens、AttemptFails、CurrEstab、EstabResets |
数据包统计 |
InSegs、OutSegs、RetransSegs、InErrs、OutRsts、InCsumErrors、EmbryonicRsts |
syncookies功能 |
SyncookiesSent、SyncookiesRecv、SyncookiesFailed |
TIME_WAIT回收 |
TW、TWRecycled、TWKilled、TCPTimeWaitOverflow |
RTO次数 |
TCPTimeouts、TCPSpuriousRTOs、TCPLossProbes、TCPLossProbeRecovery、 |
Retrans数量 |
TCPFastRetrans、TCPForwardRetrans、 |
FastOpen |
TCPFastOpenActive、TCPFastOpenPassive、 |
MD5 |
TCPMD5NotFound、TCPMD5Unexpected |
DelayedACK |
DelayedACKs、DelayedACKLocked、DelayedACKLost、 |
DSACK |
TCPDSACKOldSent、TCPDSACKOfoSent、 |
Reorder |
TCPFACKReorder、TCPSACKReorder、 |
Recovery |
TCPRenoRecovery、TCPSackRecovery、 |
Abort |
TCPAbortOnData、TCPAbortOnClose、 |
reset相关 |
|
内存prune |
PruneCalled、RcvPruned、OfoPruned、 |
PAWS相关 |
PAWSPassive、PAWSActive、PAWSEstab |
Listen相关 |
ListenOverflows、ListenDrops |
undo相关 |
TCPFullUndo、TCPPartialUndo、 |
快速路径与慢速路径 |
TCPHPHits、TCPHPHitsToUser、 |
常量
这些常量是Linux3.10中的默认值,仅在升级了内核版本时才需要关心一下这些值的变化。
RtoAlgorithm:
默认为1,RTO算法与RFC2698一致
RtoMin:
默认值为HZ/5,即200ms
RtoMax:
默认值为120HZ,即120s
MaxConn:
协议栈本身并不会限制TCP连接总数,默认值为-1.
建连统计
这些统计值中,只有CurrEstab反应的是系统当前状态,而其他值则是反应的历史状态
同时需要注意的是,这些计数器将ESTABLISHED和CLOSE-WAIT状态都作为当前连接数。
可以这么理解:这两个状态都以为这local=>peer方向的连接未被关闭
ActiveOpens:
主动建连次数,CLOSE => SYN-SENT次数
PassiveOpens:
被动建连次数,RFC原意是LISTEN => SYN-RECV次数,但Linux选择在三次握手成功后才加1
AttemptFails:
建连失败次数
EstabResets:
连接被reset次数,ESTABLISHED => CLOSE次数 + CLOSE-WAIT => CLOSE次数
CurrEstab:
当前TCP连接数,ESTABLISHED个数 + CLOSE-WAIT个数
数据包统计
这些统计值也是历史值,独立的来看意义并不大。一般可统计一段时间内的变化,关注以下几个指标
a. TCP层的重传率: ΔRetransSegs / ΔOutSegs — 越小越好,如果超过20%(这个值根据实际情况而定)则应该引起注意
b. Reset发送频率: ΔOutRsts / ΔOutSegs — 越小越好,一般应该在1%以内
c. 错误包占比: ΔInErrs / ΔInSegs — 越小越好,一般应该在1%以内,同时由checksum导致的问题包应该更低
InSegs:
收到的数据包个数,包括有错误的包个数
OutSegs:
发送的数据包个数
RetransSegs:
重传的包个数
InErrs:
收到的有问题的包个数
OutRsts:
发送的带reset标记的包个数
InCsumErrors:
收到的checksum有问题的包个数,InErrs中应该只有*小部分*属于该类型
EmbryonicRsts:
在SYN-RECV状态收到带RST/SYN标记的包个数
syncookies功能
syncookies一般不会被触发,只有在tcp_max_syn_backlog队列被占满时才会被触发
因此SyncookiesSent和SyncookiesRecv一般应该是0。
但是SyncookiesFailed值即使syncookies机制没有被触发,也很可能不为0。
这是因为一个处于LISTEN状态的socket收到一个不带SYN标记的数据包时,就会调
用cookie_v4_check()尝试验证cookie信息。而如果验证失败,Failed次数就加1。
SyncookiesSent:
使用syncookie技术发送的syn/ack包个数
SyncookiesRecv
收到携带有效syncookie信息包个数
SyncookiesFailed
收到携带无效syncookie信息包个数
注: syncookies机制是为应对synflood攻击而被提出来的。
TIME-WAIT回收
TIME-WAIT状态是TCP协议状态机中的重要一环,服务器设备一般都有非常多处于TIME-WAIT状态的socket
如果是在主要提供HTTP服务的设备上,TW值应该接近TcpPassiveOpens值。
一般情况下,sysctl_tcp_tw_reuse和sysctl_tcp_tw_recycle都是不推荐开启的。这里解释了为什么。
所以TWKilled和TWRecycled都应该是0。
同时TCPTimeWaitOverflow也应该是0,否则就意味着内存使用方面出了大问题。
TW:
经过正常的TCP_TIMEWAIT_LEN(60s)结束TW状态的socket数量
TWKilled:
经过更短的时间结束TW状态的socket数量。
只有在net.ipv4.tcp_tw_recycle开启时,调度TW timer时才可能用更短的timeout值。
TWRecycled:
Port从TIMEWAIT socket中复用的次数。
只有在sysctl_tcp_tw_reuse开启时,才可能加1
郁闷的是上面两个counter的命名与sysctl的命名真是超级不一致啊。囧...
TCPTimeWaitOverflow:
如果没有内存分配TIME-WAIT结构体,则加1
RTO次数
RTO超时对TCP性能的影响是巨大的,因此关心RTO超时的次数也非常必要。
当然3.10中的TLP机制能够减少一定量的TCPTimeouts数,将其转换为快速重传。
TCPTimeouts:
RTO timer第一次超时的次数,仅包含直接超时的情况
TCPSpuriousRTOs:
通过F-RTO机制发现的虚假超时个数
TCPLossProbes:
Probe Timeout(PTO)导致发送Tail Loss Probe (TLP)包的次数
TCPLossProbeRecovery:
丢失包刚好被TLP探测包修复的次数
/* 由以下计数器可以看出,进入RTO被触发时,TCP是可能处于多种不同状态的 */
TCPRenoRecoveryFail: (也放到了Recovery类别)
先进入Recovery阶段,然后又RTO的次数,对端不支持SACK选项
TCPSackRecoveryFail:(也放到了Recovery类别)
先进入Recovery阶段,然后又RTO的次数,对端支持SACK选项
TCPRenoFailures:
先进TCP_CA_Disorder阶段,然后又RTO超时的次数,对端不支持SACK选项
TCPSackFailures:
先进TCP_CA_Disorder阶段,然后又RTO超时的次数,对端支持SACK选项
TCPLossFailures:
先进TCP_CA_Loss阶段,然后又RTO超时的次数
Retrans数量
这些计数器统计的重传包,都不是由于RTO超时导致进行的重传
如果结合RetransSegs统计来看,如果这些非RTO导致的重传占比较大的话,也算是不幸中的万幸。
另外LostRetransmit的数量应该偏低比较好,重传包如果都大量被丢弃,则真的要注意了。
TCPLostRetransmit:
丢失的重传SBK数量,没有TSO时,等于丢失的重传包数量
TCPFastRetrans:
成功快速重传的SKB数量
TCPForwardRetrans:
成功ForwardRetrans的SKB数量,Forward Retrans重传的序号高于retransmit_high的数据
TODO: retransmit_high目前的理解是被标记为lost的SKB中,最大的end_seq值
TCPSlowStartRetrans:
成功在Loss状态发送的重传SKB数量,而且这里仅记录非RTO超时进入Loss状态下的重传数量
目前找到的一种非RTO进入Loss状态的情况就是:tcp_check_sack_reneging()函数发现
接收端违反(renege)了之前的SACK信息时,会进入Loss状态
TCPRetransFail:
尝试FastRetrans、ForwardRetrans、SlowStartRetrans重传失败的次数
FastOpen
TCP FastOpen(TFO)技术是Google提出来减少三次握手开销的技术,
核心原理就是在第一次建连时server计算一个cookies发给client,之后client向
server再次发起建连请求时就可以携带cookies信息验明正身。如果cookies验证通过,
server可以不等三次握手的最后一个ACK包就将client放在SYN包里面的数据传递给application layer。
在3.10内核中,TFO由sysctl_tcp_fastopen开关控制,默认值为0(关闭)。
而且sysctl_tcp_fastopen目前也是推荐关闭的,因为网络中有些middlebox会丢弃那些带有不认识的option的SYN包.
所以正常情况下这些值也应该都是0,当然如果收到过某些不怀好意带TFO cookies信息的SYN包,
TCPFastOpenPassive计数器就可能不为0。
TCPFastOpenActive:
发送的带TFO cookie的SYN包个数
TCPFastOpenPassive:
收到的带TFO cookie的SYN包个数
TCPFastOpenPassiveFail:
使用TFO技术建连失败的次数
TCPFastOpenListenOverflow:
TFO请求数超过listener queue设置的上限则加1
TCPFastOpenCookieReqd:
收到一个请求TFO cookies的SYN包时加1
MD5
TCP MD5 Signature选项是为提高BGP Session的安全性而提出的,详见RFC 2385。
因此内核中是以编译选项,而不是sysctl接口来配置是否使用该功能的。
如果内核编译是的CONFIG_TCP_MD5SIG选项未配置,则不会支持TCPMD5Sig,下面两个计数器也就只能是0
TCPMD5NotFound:
希望收到带MD5选项的包,但是包里面没有MD5选项
TCPMD5Unexpected:
不希望收到带MD5选项的包,但是包里面有MD5选项
DelayedACK
DelayedACK是内核中默认支持的,但即使使用DelayedACKs,每收到两个数据包也
必须发送一个ACK。所以DelayedACKs可以估算为发送出去的ACK数量的一半。
同时DelayedACKLocked反应的是应用与内核争抢socket的次数,
如果占DelayedACKs比例过大可能就需要看看应用程序是否有问题了。
DelayedACKs:
尝试发送delayed ack的次数,包括未成功发送的次数
DelayedACKLocked:
由于usr锁住了sock,而无法发送delayed ack的次数
DelayedACKLost:
TODO 暂时不理解准确含义
TCPSchedulerFailed:
如果在delay ack处理函数中发现prequeue还有数据,就加1。
数据放到prequeue,就是想user能尽快处理。如果任由数据,
则可能user行为调度效果不好
这个值应该非常接近于零才正常
DSACK
该类型计数器统计的是收/发DSACK信息次数。
DSACKOldSent + DSACKOfoSent可以当做是发送出的DSACK信息的次数,而且概率上来讲
OldSent应该占比更大。
同理DSACKRecv的数量也应该远多于DSACKOfoRecv的数量。
另外DSACK信息的发送是需要sysctl_tcp_dsack开启的,如果发现sent两个计数器为零,则要检查一下了。
一般还是建议开启dsack选项
TCPDSACKOldSent:
如果收到的重复数据包序号比rcv_nxt(接收端想收到的下一个序号)小,则增加oldsent
TCPDSACKOfoSent:
如果收到的重复数据包序号比rcv_nxt大,则是一个乱序的重复数据包,增加ofosent
TCPDSACKRecv:
收到的old dsack信息次数,判断old的方法:dsack序号小于ACK号
TCPDSACKOfoRecv:
收到的Ofo dsack信息次数
TCPDSACKIgnoredOld:
当一个dsack block被判定为无效,且设置过undo_marker,则加1
TCPDSACKIgnoredNoUndo:
当一个dsack block被判定为无效,且未设置undo_marker,则加1
Reorder
当发现了需要更新某条TCP流的reordering值(乱序值)时,以下计数器可能被使用到。
不过下面四个计数器为互斥关系,最少见的应该是TCPRenoReorder,毕竟sack已经被
广泛部署使用了。
TODO: 什么情况下能准确的判断出要更新reorder值呢?
TCPTSReorder:
如果是被一个partial ack确认后需要更新reorder值,则加1
这个地方取个TS的名字,还真是费解。不知道是什么的缩写表示了partial ack的含义。
TCPRenoReorder:
如果被不支持SACK的dupack确认后,需要更新reorder值,则加1
TCPFACKReorder:
如果在需要更新时判断支持FACK,则加1
TCPSACKReorder:
如果仅支持SACK,则该计数器加1
关于partial ack的完整内容可参考RFC6582,这里摘要定义部分
In the case of multiple packets dropped from a single window of data,
the first new information available to the sender comes when the
sender receives an acknowledgment for the retransmitted packet (that
is, the packet retransmitted when fast retransmit was first entered).
If there is a single packet drop and no reordering, then the
acknowledgment for this packet will acknowledge all of the packets
transmitted before fast retransmit was entered. However, if there
are multiple packet drops, then the acknowledgment for the
retransmitted packet will acknowledge some but not all of the packets
transmitted before the fast retransmit. We call this acknowledgment
a partial acknowledgment.
Recovery
该类型计数器统计的进入快速重传阶段的总次数及失败次数,失败次数是指先进入了
recovery阶段,然后有RTO超时了。Fast Recovery没有成功。
首先由于SACK选项已经大面积使用,RenoRecovery的次数应该远小于SackRecovery的次数
另外fail的次数应该比例较小才比较理想
TCPRenoRecovery:
进入Recovery阶段的次数,对端不支持SACK选项
TCPSackRecovery:
进入Recovery阶段的次数,对端支持SACK选项
TCPRenoRecoveryFail: (也放到了RTO次数类别)
先进入Recovery阶段,然后又RTO的次数,对端不支持SACK选项
TCPSackRecoveryFail:(也放到了RTO次数类别)
先进入Recovery阶段,然后又RTO的次数,对端支持SACK选项
Abort
abort本身是一种很严重的问题,因此是否有必要关心这些计数器
后三个计数器如果不为0,则往往意味着系统发生了较为严重的问题,需要格外注意
TCPAbortOnClose:
如果调用tcp_close()关闭socket时,recv buffer中还有数据,则加1
此时会主动发送一个reset包给对端
TCPAbortOnData:
如果在FIN_WAIT_1和FIN_WAIT_2状态下收到后续数据,或TCP_LINGER2设置小于0,则计数器加1
TCPAbortOnTimeout:
因各种计时器(RTO/PTO/keepalive)的重传次数超过上限,而关闭连接时,计数器加1
TCPAbortOnMemory:
如果orphan socket数量或者tcp_memory_allocated超过上限,则加1
一般值为0
TCPAbortOnLinger:
tcp_close()中,因tp->linger2被设置小于0,导致FIN_WAIT_2立即切换到CLOSE状态的次数
一般值为0
TCPAbortFailed:
如果在准备发送reset时,分配SKB或者发送SKB失败,则加1
一般值为0
c. 当rcv_buf不足时可能需要prune ofo queue, 这种情况就会导致PruneCalled计数器增加;
当一般都应该通过collapse节省内存就可以了,并不需要真正的prune掉被SACK的数据。
所以OfoPruned和更严重的RcvPruned都应该计数为0。
netstat-st快速对照表附录:
TCP Basic
类别 |
名称 |
描述 |
Tcp |
ActiveOpens |
tcp_connect(),发送SYN时,加1 |
Tcp |
PassiveOpens |
tcp_create_openreq_child(), 被动三路握手完成,加1 |
Tcp |
AttemptFails |
|
Tcp |
CurrEstab |
tcp_set_state(),根据ESTABLISHED是新/旧状态,分别加减一。 |
Tcp |
EstabResets |
tcp_set_state(),新状态为TCP_CLOSE,如果旧状态是ESTABLISHED/TCP_CLOSE_WAIT就加1 |
Tcp |
ListenOverflows |
tcp_v4_syn_recv_sock():三路握手最后一步完全之后,Accept queue队列超过上限时加1 |
Tcp |
ListenDrops |
tcp_v4_syn_recv_sock():任何原因,包括Accept queue超限,创建新连接,继承端口失败等,加1 |
Tcp |
MaxConn |
0 |
Tcp |
InSegs |
tcp_v4_rcv(),收到一个skb,加1 |
Tcp |
InErrs |
|
Tcp |
OutSegs |
|
Tcp |
OutRsts |
tcp_v4_send_reset(), tcp_send_active_reset()加1 |
TCP Loss & Retrans
类别 |
名称 |
描述 |
Tcp |
TCPTimeouts |
|
Tcp |
RtoAlgorithm |
1,tcp_mib_init()初始化 |
Tcp |
RtoMax |
120000,tcp_mib_init()初始化:TCP_RTO_MAX*1000/HZ,TCP_RTO_MAX=120*HZ |
Tcp |
RtoMin |
200,tcp_mib_init()初始化:TCP_RTO_MIN*1000/HZ,TCP_RTO_MIN=HZ/5 |
以下计数器,统计的是调用tcp_retransmit_skb()的次数,由于sysctl_tcp_retrans_collapse/TSO的原因,一次tcp_transmit_skb()调用可能发送多个segs
类别 |
名称 |
描述 |
Tcp |
RetransSegs |
重传次数,包括RTO timer和常规重传,即tcp_retransmit_skb()中调用tcp_transmit_skb(),成功返回即+1。 |
TcpExt |
TCPForwardRetrans |
(非RTO timer)发送新数据的次数,即在tcp_fastretrans_alert()/tcp_simple_retransmit()->tcp_xmit_retransmit_queue()中, 如果发现skb->seq > tp->retransmit_high(一般为snd_una),如果当前状态为Recovery,启用了SACK,并且发送条件允许就在这个函数中发送新数据。 |
TcpExt |
TCPFastRetrans |
(非RTO timer)快速重传次数,即tcp_fastretrans_alert()/tcp_simple_retransmit()->tcp_xmit_retransmit_queue()中,如果不是LOSS状态,就加1 |
TcpExt |
TCPSlowStartRetrans |
(非RTO timer)重传次数:即tcp_fastretrans_alert()/tcp_simple_retransmit()->tcp_xmit_retransmit_queue()中,如果是LOSS状态,就加1 |
TcpExt |
TCPLostRetransmit |
根据SACK数据推测出的重段包丢失计数器:在tcp_sacktag_write_queue()->tcp_mark_lost_retrans(), 如果发现tcp_highest_sack_seq(tp)超过某skb在重传时的snd_nxt(TCB->ack_seq),就认为这个重传包 已经丢失了,加1(加的不是段数)。tcp_highest_sack_seq(tp)是被SACK过的具有最高SEQ号的skb的seq。 |
TcpExt |
TCPSpuriousRTOs |
tcp_process_frto(),如果frto_counter !=0 && frto_counter != 1加1 |
TCP ACK & SACK
类别 |
名称 |
描述 |
TcpExt |
DelayedACKLocked |
tcp_delack_timer(): delay ACK定时器因为user已经锁住而无法发送ACK的次数。 |
TcpExt |
DelayedACKLost |
|
TcpExt |
DelayedACKs |
tcp_delack_timer():调用tcp_send_ack()的次数,无论是否是成功。 |
TcpExt |
TCPHPAcks |
tcp_ack():接收到包,进入quick path时加1 |
TcpExt |
TCPPureAcks |
tcp_ack():接收慢速路径中的pure ACK数量 |
TcpExt |
TCPDSACKIgnoredNoUndo |
tcp_sacktag_write_queue(): undo_marker为0并且接收到非法D-SACK块时,加1,即SACK中的序号太旧。 |
TcpExt |
TCPDSACKIgnoredOld |
tcp_sacktag_write_queue(): undo_marker不为0,并且接收到非法D-SACK块时,加1,即SACK中的序号太旧。 |
TcpExt |
TCPSACKDiscard |
tcp_sacktag_write_queue(): 非法SACK块(不包括D-SACK)计数,即SACK中的序号太旧。 |
TcpExt |
TCPDSACKOldSent |
tcp_dsack_set():如果SACK块开始序号小于RCV.NXT,加1 |
TcpExt |
TCPDSACKOfoSent |
tcp_dsack_set():如果SACK块开始序号大于等于RCV.NXT,加1 |
TcpExt |
TCPSACKReneging |
tcp_clean_rtx_queue(): 如果snd_una(输入skb->ack)之后的具有最小开始序号skb(即sk_write_queue中的第一个skb)中有TCPCB_SACKED_ACKED标志,此时加1,这说明接收者已经丢掉了之前它已经SACK过的数据。 |
TcpExt |
TCPSackFailures |
tcp_retransmit_timer(): 在Reorder状态下,或者sacked_out不为0时,发生RTO,并且启用了SACK,加1 |
TcpExt |
TCPSackRecoveryFail |
tcp_retransmit_timer(): 在Reovery状态下发生RTO,并且启用了SACK,加1 |
TcpExt |
TCPDSACKRecv |
tcp_check_dsack(): 收到D-SACK,并且SACK0开始序号 < ACK号,加1 |
TcpExt |
TCPDSACKOfoRecv |
tcp_check_dsack(): 收到D-SACK,并且SACK0开始序号 >= ACK号,但SACK1包括SACK0。 |
TcpExt |
TCPSackRecovery |
tcp_fastretrans_alert(): SACK TCP进入Reovery状态的次数 |
TcpExt |
TCPSackShifted |
tcp_ack()->tcp_sacktag_write_queue()->tcp_sacktag_walk()->tcp_shift_skb_data()->tcp_shifted_data() 在tcp_sacktag_walk()时,一个SACK可能会导致切割某skb,新切出来的skb放到被切的skb之后。 |
TcpExt |
TCPSackShiftFallback |
tcp_ack()->tcp_sacktag_write_queue()->tcp_sacktag_walk()->tcp_shift_skb_data() 与上相反,如果不能shift,本计数器加1。原因可能如下:
|
TcpExt |
TCPSackMerged |
tcp_ack()->tcp_sacktag_write_queue()->tcp_sacktag_walk()->tcp_shift_skb_data()->tcp_shifted_data() 在上面介绍的shift过程中,如果发现分割之后的skb被它之前的skb完全“吃掉”,本计数器加1 |
TCP TIME_WAIT
类别 |
名称 |
描述 |
TcpExt |
TW |
inet_twdr_do_twkill_work(): TIME_WAIT超时的socket数量(timeout >= 4s) |
TcpExt |
TWKilled |
inet_twdr_twcal_tick(): TIME_WAIT超时的socket数量.(timeout < 4s), |
TcpExt |
TWRecycled |
tcp_v4_connect() -> __inet_check_established(): 在建立时,如果port是从TIME_WAIT socket中复用的,加1 |
TcpExt |
TCPTimeWaitOverflow |
tcp_time_wait(): 当系统无法分配新的tcp_timewait_socket,或者tw_count(scheduled timewait sockets)超过sysctl_max_tw_buckets时,加1 |
TCP Others
类别 |
名称 |
描述 |
TcpExt |
TCPRenoRecoveryFail |
tcp_retransmit_timer(): 在Reovery状态下发生RTO,并且没有启用SACK,加1 |
TcpExt |
TCPRenoFailures |
tcp_retransmit_timer(): 在Reorder状态下,或者sacked_out不为0时,发生RTO,并且没有启用SACK,加1 |
TcpExt |
TCPRenoRecovery |
tcp_fastretrans_alert(): 不使用SACK的TCP进入Reovery状态的次数 |
TCP Congestion Processing
类别 |
名称 |
描述 |
TcpExt |
TCPDSACKUndo |
tcp_ack() -> tcp_fastretrans_alert() -> tcp_try_undo_dsack() Disorder状态下,undo完成(undo_retrans == 0)的次数。 |
TcpExt |
TCPFullUndo |
tcp_ack() -> tcp_fastretrans_alert() -> tcp_try_undo_recovery() Recovery状态时,接收到到全部确认(snd_una >= high_seq)后且已经undo完成(undo_retrans == 0)的次数。 |
TcpExt |
TCPPartialUndo |
tcp_ack() -> tcp_fastretrans_alert() -> tcp_undo_partial() Recovery状态时,接收到到部分确认(snd_una < high_seq)时但已经undo完成(undo_retrans == 0)的次数。 |
TcpExt |
TCPLossUndo |
tcp_ack() -> tcp_fastretrans_alert() -> tcp_try_undo_loss() Loss状态时,接收到到全部确认(snd_una >= high_seq)后且已经undo完成(undo_retrans == 0)的次数。 |
TcpExt |
TCPRenoReorder |
在tcp_update_reordering()中更新,当metric > tp->reordering并且没有启用SACK,本计数器加1 综合来说,在sacked_out“不可靠”时,tp->reordering被更新为当前窗口中的“已用seg”个数,同时包括未确认(和已确认的?)数据,但不包括lost_out。 A. tcp_ack() -> tcp_fastretrans_alert() -> tcp_add_reno_sack() -> tcp_check_reno_reordering() -> tcp_update_reordering(): 注:
|
TcpExt |
TCPSACKReorder |
在tcp_update_reordering()中更新,当metric > tp->reordering并且启用SACK但关闭FACK时,本计数器加1 |
TcpExt |
TCPFACKReorder |
与TCPSACKReorder类似,如果同时启用了SACK和FACK,就增加本计数器。 |
TcpExt |
TCPTSReorder |
tcp_ack() -> tcp_fastretrans_alert() -> tcp_undo_partial() -> tcp_update_reordering() Recovery状态时,接收到到部分确认(snd_una < high_seq)时但已经undo完成(undo_retrans == 0)的次数。 数量上与TCPPartialUndo相等。 |
TCP Others
类别 |
名称 |
描述 |
TcpExt |
TCPRenoRecoveryFail |
tcp_retransmit_timer(): 在Reovery状态下发生RTO,并且没有启用SACK,加1 |
TcpExt |
TCPRenoFailures |
tcp_retransmit_timer(): 在Reorder状态下,或者sacked_out不为0时,发生RTO,并且没有启用SACK,加1 |
TcpExt |
TCPRenoRecovery |
tcp_fastretrans_alert(): 不使用SACK的TCP进入Reovery状态的次数 |
TcpExt |
ArpFilter |
arp_rcv() -> NETFILTER(ARP_IN) -> arp_process() 与TCP无关,接收到ARP packet时做一次输出路由查找(sip, tip),如果找到的路由项的device与输入device的不同,计数器加1 |
TcpExt |
EmbryonicRsts |
tcp_v4_do_rcv() -> tcp_v4_hnd_req() -> tcp_check_req(): 在三手握手时的SYN_RECV状态中接收到RST或者SYN的次数。 |
TcpExt |
LockDroppedIcmps |
tcp_v4_err(): 接收到ICMP错误报文,但tcp socket被user锁住 |
TcpEx |
OfoPruned |
tcp_data_queue() -> tcp_try_rmem_schedule() 慢速路径中,如果不能将数据直接复制到user space,需要加入到sk_receive_queue前,会检查receiver side memory是否允许,如果rcv_buf不足就可能prune ofo queue。此时计数器加1 |
TcpExt |
OutOfWindowIcmps |
tcp_v4_err(): 接收到的ICMP,但ICMP中的TCP头序号不在接收窗口之内的次数,有两个可能情况:(1)LISTEN状态时,序号不等待ISN;(2)其他状态时,序号不在SND_UNA .. SND_NXT之间 |
TcpExt |
PAWSActive |
tcp_rcv_synsent_state_process(): 在发送SYN后,接收到ACK,但PAWS检查失败的次数。 |
TcpExt |
PAWSEstab |
tcp_validate_incoming() tcp_timewait_state_process() |
TcpExt |
PAWSPassive |
tcp_v4_conn_request(): 三路握手最后一个ACK的PAWS检查失败次数。 |
TcpExt |
PruneCalled |
tcp_data_queue() -> tcp_try_rmem_schedule() 慢速路径中,如果不能将数据直接复制到user space,需要加入到sk_receive_queue前,会检查receiver side memory是否允许,如果rcv_buf不足就可能prune ofo queue。此时计数器加1 |
TcpExt |
RcvPruned |
tcp_data_queue() -> tcp_try_rmem_schedule() 慢速路径中,如果不能将数据直接复制到user space,需要加入到sk_receive_queue前,会检查receiver side memory是否允许,如果rcv_buf不足就可能prune receive queue,如果prune失败了,此计数器加1。 |
TcpExt |
SyncookiesFailed |
cookie_v4_check(): SYN cookie检查失败次数。 |
TcpExt |
SyncookiesRecv |
cookie_v4_check(): 接收SYN cookie次数。 |
TcpExt |
SyncookiesSent |
cookie_v4_init_sequence(): 生成SYN cookie次数。 |
TcpExt |
TCPAbortFailed |
tcp_send_active_reset(): alloc_skb()或者tcp_transmit_skb()失败。 |
TcpExt |
TCPAbortOnClose |
tcp_close(): sk_receive_queue中仍有数据的次数。 |
TcpExt |
TCPAbortOnData |
tcp_rcv_state_process(): 在FIN_WAIT_1/FIN_WAIT_2状态下接收到后续数据(序号>RCV_NXT);或者,TCP_LINGER2设置值<0,计数器加1 tcp_close(): 没有未读数据,但设置了SO_LINGER并且linger timeout=0, 计数器加1,此时TCP正常断开连接sk_prot->disconnect()。 |
TcpExt |
TCPAbortOnLinger |
tcp_close(): 因TCP_LINGER2设置值<0,FIN_WAIT_2立即切换到CLOSE的次数。 |
TcpExt |
TCPAbortOnMemory |
在执行tcp_close()/probe timer/keepalive timer时,orphan sockets数量和tcp_memory_allocated是否超过最大值的次数。 |
TcpExt |
TCPAbortOnSyn |
tcp_validate_incoming(): 出现SYN,并且序号大于RCV_NXT的次数。 |
TcpExt |
TCPAbortOnTimeout |
RTO/probe/keepalive timer到达最大重试次数或者最长重试时间的次数 |
TCP Others Others
类别 |
名称 |
描述 |
TcpExt |
TCPBacklogDrop |
tcp_v4_rcv() : 如果socket被user锁住,后退一步内核会把包加到sk_backlog_queue,但如果因为sk_rcv_buf不足的原因入队失败,计数器加1 |
TcpExt |
TCPDeferAcceptDrop |
tcp_check_req(): 如果启用TCP_DEFER_ACCEPT,这个计数器统计了被丢掉了“Pure ACK”个数。 TCP_DEFER_ACCEPT:允许listener只有在连接上有数据才创建新的socket,以抵御syn-flood攻击。 |
TcpExt |
TCPDirectCopyFromBacklog |
tcp_recvmsg(): 如果有数据在softirq里面从backlog queue中直接复制到userland memory上,计数器加1 |
TcpExt |
TCPDirectCopyFromPrequeue |
tcp_recvmsg(): 如果有数据在这个syscall里从prequeue中直接复制到userland memory上,计数器加1 |
TcpExt |
TCPHPHits |
tcp_rcv_established(): 如果有skb通过“快速路径”进入到sk_receive_queue上,计数器加1。 特别地,Pure ACK以及直接复制到user space上的都不算在这个计数器上。 |
TcpExt |
TCPHPHitsToUser |
tcp_rcv_established(): 如果有skb通过“快速路径”直接复制到user space上,计数器加1。 |
TcpExt |
TCPLossFailures |
tcp_retransmit_timer(): icsk_retransmit==0(第一次进入重传状态)并且处于Loss状态下,计数器加1 可能情况是:因为partial ACK中从Loss中undo了一些状态,但还有完全离开Loss |
TcpExt |
TCPMD5NotFound |
tcp_v4_do_rcv() -> tcp_v4_inbound_md5_hash() : 配置了md5检查,但在输入skb中没有找到对应TCP选项。 |
TcpExt |
TCPMD5Unexpected |
tcp_v4_do_rcv() -> tcp_v4_inbound_md5_hash() : 未配置md5检查,但在输入skb中找到了对应TCP选项。 |
TcpExt |
TCPMemoryPressures |
tcp_enter_memory_pressure()在从“非压力状态”切换到“有压力状态”时计数器加1,可能的触发点有:
|
TcpExt |
TCPMinTTLDrop |
tcp_v4_err() / tcp_v4_rcv(): 在接收到TCP报文或者TCP相关的ICMP报文时,检查IP TTL,如果小于socket option设置的一个阀值,就丢包。这个功能是RFC5082(The Generalized TTL Security Mechanism, GTSM)规定的,使用GTSM的通信双方,都将TTL设置成最大值255,双方假定了解之间的链路情况,这样可以通过检查最小TTL值隔离攻击。 |
TcpExt |
TCPPrequeueDropped |
tcp_v4_rcv() -> tcp_prequeue() : 如果因为内存不足(ucopy.memory < sk->rcv_buf)而加入到prequeue失败,重新由backlog处理,计数器加1 |
TcpExt |
TCPPrequeued |
tcp_recvmsg() -> tcp_prequeue_process() : tcp_recvmsg()发现可以从prequeue接收到报文,计数器加1(不是每个skb加1) |
TcpExt |
TCPRcvCollapsed |
tcp_prune_queue() -> tcp_collapse() -> tcp_collapse_one() tcp_prune_ofo_queue() -> tcp_collapse() |
TcpExt |
TCPReqQFullDoCookies |
tcp_rcv_state_process() -> tcp_v4_conn_request() -> tcp_syn_flood_action() syn_table过载,进行SYN cookie的次数(取决于是否打开sysctl_tcp_syncookies)。 |
TcpExt |
TCPReqQFullDrop |
tcp_rcv_state_process() -> tcp_v4_conn_request() -> tcp_syn_flood_action() syn_table过载,丢掉SYN的次数。 |
TcpExt |
TCPSchedulerFailed |
tcp_delack_timer(): 在delay ACK处理功能内,如果prequeue中仍有数据,计数器就加1 加入到prequeue,本来是期待着userspace(使用tcp_recvmsg()之类的系统调用)尽快处理之。其中仍有数据,可能隐含着userspace行为不佳。 |
TcpExt |
IPReversePathFilter |
ip_rcv_finish() -> ip_route_input_noref(): 反向路径过滤掉的IP分组数量:要么反向路由查找失败,要么是找到的输出接口与输入接口不同。 |
参考文献: