netstat st的相关解析

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
云解析 DNS,旗舰版 1个月
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 写在前面,查netstat -st的相关信息时,意外获悉nstat这个命令,好使的狠,大家可以试试,常用的查看丢包的命令netstat -st | egrep -i "drop|reject|overflowed|listen|filter|reset" --------------------------快乐的分割线------------------当执行以下命令查看netstat统计信息来源时,发现一个重要的来源是/proc/net/snmp接口的输出信息分享给大家

写在前面,查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()函数中计数
相当于SYN包的发送次数(但不包含重传次数)

PassiveOpens

LISTEN => SYN-RECV次数
可理解为被动建联数

实现上则是在三次握手成功后,
建立tcp_sock结构体后才加1
在tcp_create_openreq_child()函数中调用

AttemptFails

SYN-SENT => CLOSE次数
加上SYN-RECV => CLOSE次数
加上SYN-RECV => LISTEN次数
建联失败的次数

回CLOSE部分在tcp_done()函数中计数,
回LISTEN部分在tcp_check_req()中计数

EstabResets

ESTABLISHED => CLOSE次数
加上CLOSE-WAIT => CLOSE次数
这些情况,基本都是reset导致的

在tcp_set_state()函数中,如果之前的状态是
TCP_CLOSE_WAIT或TCP_ESTABLISHED就加1

CurrEstab

ESTABLISHED和CLOSE-WAIT
状态的TCP流数

在tcp_set_state()中处理
实现体现的是进入ESTABLISHED之后
进入CLOSE之前的TCP流数

InSegs

所有收到的TCP包
即使是个错误包

在tcp_v4_rcv()和tcp_v6_rcv()中计数

OutSegs

所有发送出去的TCP包
包括新数据包、重传数据包
、syn包、synack包和reset包

tcp_v4_send_reset()中统计reset包
tcp_v4_send_ack()中统计SYN-RECV和TIME-WAIT状态下发送的ACK包
tcp_v6_send_response()中统计ipv6相应数据
tcp_make_synack()中统计发送的SYNACK包

tcp_transmit_skb()中统计所有的其他包

RetransSegs

所有重传出去的TCP包

tcp_v4_rtx_synack()和tcp_v6_rtx_synack()中
统计重传的SYNACK包,
tcp_retransmit_skb()中统计其他重传包

InErrs

所有收到的有问题的TCP包数量
比如checksum有问题

tcp_validate_incoming()中统计seq有问题的包
tcp_rcv_established()、tcp_v4_do_rcv()、tcp_v4_rcv()、
tcp_v6_do_rcv()、tcp_v6_rcv()中根据checksum来判断出错误包

OutRsts

发送的带RST标记的TCP包数量

在tcp_v4_send_reset()、tcp_send_active_reset()、
tcp_v6_send_response()中统计

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、
TCPRenoRecoveryFail、TCPSackRecoveryFail、
TCPRenoFailures、TCPSackFailures、
TCPLossFailures

Retrans数量

TCPFastRetrans、TCPForwardRetrans、
TCPSlowStartRetrans、TCPLostRetransmit、
TCPRetransFail

FastOpen

TCPFastOpenActive、TCPFastOpenPassive、
TCPFastOpenPassiveFail、TCPFastOpenListenOverflow、
TCPFastOpenCookieReqd

MD5

TCPMD5NotFound、TCPMD5Unexpected

DelayedACK

DelayedACKs、DelayedACKLocked、DelayedACKLost、
TCPSchedulerFailed

DSACK

TCPDSACKOldSent、TCPDSACKOfoSent、
TCPDSACKRecv、TCPDSACKOfoRecv、
TCPDSACKIgnoredOld、TCPDSACKIgnoredNoUndo

Reorder

TCPFACKReorder、TCPSACKReorder、
TCPRenoReorder、TCPTSReorder

Recovery

TCPRenoRecovery、TCPSackRecovery、
TCPRenoRecoveryFail、TCPSackRecoveryFail

Abort

TCPAbortOnData、TCPAbortOnClose、
TCPAbortOnMemory、TCPAbortOnTimeout、
TCPAbortOnLingerTCPAbortFailed

reset相关

内存prune

PruneCalled、RcvPruned、OfoPruned、
TCPMemoryPressures

PAWS相关

PAWSPassive、PAWSActive、PAWSEstab

Listen相关

ListenOverflows、ListenDrops

undo相关

TCPFullUndo、TCPPartialUndo、
TCPDSACKUndo、TCPLossUndo

快速路径与慢速路径

TCPHPHits、TCPHPHitsToUser、
TCPPureAcks、TCPHPAcks

常量

这些常量是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

  1. tcp_done():如果在SYN_SENT/SYN_RECV状态下结束一个连接,加1
  2. tcp_check_req():被动三路握手最后一个阶段中的输入包中如果有RST|SYN标志,加1

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

  1. tcp_rcv_established()->tcp_validate_incoming():如果有SYN且seq >= rcv_nxt,加1
  2. 以下函数内,如果checksum错误或者包长度小于TCP header,加1:
    1. tcp_v4_do_rcv()
    2. tcp_rcv_established()
    3. tcp_v4_rcv()

Tcp

OutSegs

  1. tcp_v4_send_reset(), tcp_v4_send_ack(),加1
  2. tcp_transmit_skb(), tcp_make_synack(),加tcp_skb_pcount(skb)(见TCP_COOKIE_TRANSACTIONS)

Tcp

OutRsts

tcp_v4_send_reset(), tcp_send_active_reset()加1


TCP Loss & Retrans


类别

名称

描述

Tcp

TCPTimeouts

  1. 在RTO timer中,从CWR/Open状态下第一次超时的次数,其余状态不计入这个计数器。
  2. SYN-ACK的超时次数。

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

  1. tcp_validate_incoming()->tcp_send_dupack():当输入包不在接收窗口内,或者PAWS失败后,计数器加1
  2. tcp_data_queue(): 输入包的结束序列号< RCV_NXT时,加1

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之后。
根据SACK的观点,如果“旧的skb”(变小了)能够与它之前的skb合并,本计数器,就加1。
这个合并过程,叫作shift

TcpExt

TCPSackShiftFallback

tcp_ack()->tcp_sacktag_write_queue()->tcp_sacktag_walk()->tcp_shift_skb_data()

与上相反,如果不能shift,本计数器加1。原因可能如下:

  1. 不支持GSO
  2. prev skb不完全是paged的
  3. SACK的序号已经ACK过,等等

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)
之所以按超时分别对待timewait socket,可能是考虑到长超时的socket的timeout时间分布比较分散,需要使用不同的查找方法。

TcpExt

TWKilled

inet_twdr_twcal_tick(): TIME_WAIT超时的socket数量.(timeout < 4s),
仅在启用sysctl_tw_recycle,并且使用TCP timestamp option时才会有这种情况,这时使用3.5x RTO时作为timewait timeout,而默认timeout为60s

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():
在Open/Recovery/Disorder/CWR状态下接收到dupACK时:
如果sacked_out + lost_out > packets_out,
用metric( = packets_out)调用tcp_update_reordering()
B. tcp_ack() -> tcp_clean_rtx_queue() -> tcp_remove_reno_sacks() -> tcp_check_reno_reordering() -> tcp_update_reordering() :
在清理rtx queue时,会从packets_out, lost_out, sacked_out中减去确认了的seg数量,
如果sacked_out + lost_out > packets_out,
用metric( = packets_out + acked_pcount)调用tcp_update_reordering()

注:

  1. sacked_out : 接收到的dupACK数量
  2. lost_out : 限制最小值为1,最大值为packets_out
  3. tp->reordering: 创建socket时,被动建立连接时,进入Loss状态时,初始化为sysctl_tcp_reordering

TcpExt

TCPSACKReorder

在tcp_update_reordering()中更新,当metric > tp->reordering并且启用SACK但关闭FACK时,本计数器加1
A. tcp_ack() -> tcp_sacktag_write_queue() -> tcp_update_reordering()
在tcp_sacktag_walk()中会计算fackets_out(通过累加state.fack_count),这个值即从snd_una开始到已经SACK的最高序号间的seg数量(包括没有被SACK覆盖的)。判断发生乱序的条件是: (1)发现针对重传报文的D-SACK;(2)当前接收到SACK序号比以前接收到的最大SACK序号小。state.reord是发生乱序时的最小fack_count,即在“snd_una + fack_count”处发生了乱序。
metric = tp->fackets_out - state.reord,即可能发生乱序的最多报文数。
B. tcp_ack() -> tcp_clean_rtx_queue() -> tcp_update_reordering()
与A.类似,tcp_clean_rtx_queue()计算rtx queue中被SACK过的数据(非重传)中空洞,reord保存“最小号”空洞的位置(在重传队列中的“座次”)。而prior_fackets - reord即可能发生乱序的TCP segments数量。如果没有SACK,reorder = prior_fackets = 0
metric = prior_fackets - reord

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()
tcp_check_req()
输入包PAWS失败次数。

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,可能的触发点有:

  • tcp_sendmsg()
  • tcp_sendpage()
  • tcp_fragment()
  • tso_fragment()
  • tcp_mtu_probe()
  • tcp_data_queue()

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()
每当合并sk_receive_queue(ofo_queue)中的连续报文时,计数器加1

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分组数量:要么反向路由查找失败,要么是找到的输出接口与输入接口不同。



参考文献:

TCP SNMP counters(一二三)

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
网络协议 Linux
LINUX netstat连接状态解析及TCP状态转换
LINUX netstat连接状态解析及TCP状态转换 水平有限如果有误请指出。 我们经常在netstat -anlp 中能够看到端口连接状态一项 gaopeng@bogon:~$ netstat -anlp|grep 10050 (Not all proce...
1210 0
|
6天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
21 2
|
1月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
67 0
|
1月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
54 0
|
1月前
|
存储 Java C++
Collection-PriorityQueue源码解析
Collection-PriorityQueue源码解析
60 0
|
1月前
|
安全 Java 程序员
Collection-Stack&Queue源码解析
Collection-Stack&Queue源码解析
80 0
|
7天前
|
存储 安全 Linux
Golang的GMP调度模型与源码解析
【11月更文挑战第11天】GMP 调度模型是 Go 语言运行时系统的核心部分,用于高效管理和调度大量协程(goroutine)。它通过少量的操作系统线程(M)和逻辑处理器(P)来调度大量的轻量级协程(G),从而实现高性能的并发处理。GMP 模型通过本地队列和全局队列来减少锁竞争,提高调度效率。在 Go 源码中,`runtime.h` 文件定义了关键数据结构,`schedule()` 和 `findrunnable()` 函数实现了核心调度逻辑。通过深入研究 GMP 模型,可以更好地理解 Go 语言的并发机制。
|
19天前
|
消息中间件 缓存 安全
Future与FutureTask源码解析,接口阻塞问题及解决方案
【11月更文挑战第5天】在Java开发中,多线程编程是提高系统并发性能和资源利用率的重要手段。然而,多线程编程也带来了诸如线程安全、死锁、接口阻塞等一系列复杂问题。本文将深度剖析多线程优化技巧、Future与FutureTask的源码、接口阻塞问题及解决方案,并通过具体业务场景和Java代码示例进行实战演示。
39 3
|
1月前
|
存储
让星星⭐月亮告诉你,HashMap的put方法源码解析及其中两种会触发扩容的场景(足够详尽,有问题欢迎指正~)
`HashMap`的`put`方法通过调用`putVal`实现,主要涉及两个场景下的扩容操作:1. 初始化时,链表数组的初始容量设为16,阈值设为12;2. 当存储的元素个数超过阈值时,链表数组的容量和阈值均翻倍。`putVal`方法处理键值对的插入,包括链表和红黑树的转换,确保高效的数据存取。
53 5
|
1月前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
111 5

推荐镜像

更多