天天看點

TCP SNMP counters netstat -s 各項參數意義

轉自 roveryu.blog.chinaunix.net

最近在總結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:  

#! /usr/bin/python

proc_files = ("/proc/net/netstat", "/proc/net/snmp")

def parse_proc_files(fn):
    stats = {}
    lines = file(fn).readlines()
    n_lines = len(lines)
    n = 0
    while n < n_lines:
        titles = lines[n].split(" ") # TcpExt: TcpXX SackXX
        values = lines[n+1].split(" ") # TcpExt: 11 23213
        kind = titles[0]
        del titles[0]
        del values[0]
        sub_stats = stats.get(kind, {})
        n_cols = len(titles)
        for i in range(n_cols):
            sub_stats[titles[i].strip()] = values[i].strip()
        stats[kind] = sub_stats
        n += 2
    return stats


def show_parsed(stats):
    kind_list = stats.keys()
    kind_list.sort()
    for kind in kind_list:
        title_list = stats[kind].keys()
        title_list.sort()
        for title in title_list:
            print "%-10s%-25s\t%20s" % (kind, title, stats[kind][title])

s = {}
for fn in proc_files:
    new_s = parse_proc_files(fn)
    for new_kind in new_s:
        if new_kind not in s: # unlikely
            s[new_kind] = new_s[new_kind]
        else:
            s[new_kind].update(new_s[new_kind])

show_parsed(s)      

      繼續講述/proc/net/netstat, /proc/net/snmp中TCP的故事。   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分組數量:要麼反向路由查找失敗,要麼是找到的輸出接口與輸入接口不同。

  全劇終,如有錯誤,敬請指正。      

轉載于:https://www.cnblogs.com/lovemyspring/articles/5087895.html