天天看点

TCP netstat -az含义

http://blog.chinaunix.net/uid-20043340-id-2984198.html

最近在总结2.6.32与2.6.18的差异,我特别有兴趣的是网络部分,但猛然发现其实SNMP counters我也并不能准确解释它们的含义,于是就有了以下总结,还不完整,持续总结中:

加粗的项代表TODO,还有一些counters没有列出来。

难免有错误,请大家指正吧,我的codebase是linux2.6.git~

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
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状态的次数

此外,可以用这个脚本收集这些counters:

  1. #! /usr/bin/python
  2. proc_files = ("/proc/net/netstat", "/proc/net/snmp")
  3. def parse_proc_files(fn):
  4.     stats = {}
  5.     lines = file(fn).readlines()
  6.     n_lines = len(lines)
  7.     n = 0
  8.     while n < n_lines:
  9.         titles = lines[n].split(" ") # TcpExt: TcpXX SackXX
  10.         values = lines[n+1].split(" ") # TcpExt: 11 23213
  11.         kind = titles[0]
  12.         del titles[0]
  13.         del values[0]
  14.         sub_stats = stats.get(kind, {})
  15.         n_cols = len(titles)
  16.         for i in range(n_cols):
  17.             sub_stats[titles[i].strip()] = values[i].strip()
  18.         stats[kind] = sub_stats
  19.         n += 2
  20.     return stats
  21. def show_parsed(stats):
  22.     kind_list = stats.keys()
  23.     kind_list.sort()
  24.     for kind in kind_list:
  25.         title_list = stats[kind].keys()
  26.         title_list.sort()
  27.         for title in title_list:
  28.             print "%-10s%-25s\t%20s" % (kind, title, stats[kind][title])
  29. s = {}
  30. for fn in proc_files:
  31.     new_s = parse_proc_files(fn)
  32.     for new_kind in new_s:
  33.         if new_kind not in s: # unlikely
  34.             s[new_kind] = new_s[new_kind]
  35.         else:
  36.             s[new_kind].update(new_s[new_kind])
  37. show_parsed(s)