天天看點

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)