Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2244639
  • 博文数量: 230
  • 博客积分: 9346
  • 博客等级: 中将
  • 技术积分: 3418
  • 用 户 组: 普通用户
  • 注册时间: 2006-01-26 01:58
文章分类

全部博文(230)

文章存档

2015年(30)

2014年(7)

2013年(12)

2012年(2)

2011年(3)

2010年(42)

2009年(9)

2008年(15)

2007年(74)

2006年(36)

分类: LINUX

2015-04-09 12:17:49

原文地址:TCP SNMP counters (一) 作者:raise_sail


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

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

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

TCP Basic

类别
名称
描述
TcpActiveOpenstcp_connect(),发送SYN时,加1
TcpPassiveOpenstcp_create_openreq_child(), 被动三路握手完成,加1
TcpAttemptFails
  1. tcp_done():如果在SYN_SENT/SYN_RECV状态下结束一个连接,加1
  2. tcp_check_req():被动三路握手最后一个阶段中的输入包中如果有RST|SYN标志,加1
TcpCurrEstabtcp_set_state(),根据ESTABLISHED是新/旧状态,分别加减一。
TcpEstabResetstcp_set_state(),新状态为TCP_CLOSE,如果旧状态是ESTABLISHED/TCP_CLOSE_WAIT就加1
TcpListenOverflowstcp_v4_syn_recv_sock():三路握手最后一步完全之后,Accept queue队列超过上限时加1
TcpListenDropstcp_v4_syn_recv_sock():任何原因,包括Accept queue超限,创建新连接,继承端口失败等,加1
TcpMaxConn0
TcpInSegstcp_v4_rcv(),收到一个skb,加1
TcpInErrs
  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()
TcpOutSegs
  1. tcp_v4_send_reset(), tcp_v4_send_ack(),加1
  2. tcp_transmit_skb(), tcp_make_synack(),加tcp_skb_pcount(skb)(见TCP_COOKIE_TRANSACTIONS)
TcpOutRststcp_v4_send_reset(), tcp_send_active_reset()加1

TCP Loss & Retrans

类别
名称
描述
TcpTCPTimeouts
  1. 在RTO timer中,从CWR/Open状态下第一次超时的次数,其余状态不计入这个计数器。
  2. SYN-ACK的超时次数。
TcpRtoAlgorithm1,tcp_mib_init()初始化
TcpRtoMax120000,tcp_mib_init()初始化:TCP_RTO_MAX*1000/HZ,TCP_RTO_MAX=120*HZ
TcpRtoMin200,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

类别
名称
描述
TcpRetransSegs重传次数,包括RTO timer和常规重传,即tcp_retransmit_skb()中调用tcp_transmit_skb(),成功返回即+1。
TcpExtTCPForwardRetrans(非RTO timer)发送新数据的次数,即在tcp_fastretrans_alert()/tcp_simple_retransmit()->tcp_xmit_retransmit_queue()中,

如果发现skb->seq > tp->retransmit_high(一般为snd_una),如果当前状态为Recovery,启用了SACK,并且发送条件允许就在这个函数中发送新数据。

TcpExtTCPFastRetrans

(非RTO timer)快速重传次数,即tcp_fastretrans_alert()/tcp_simple_retransmit()->tcp_xmit_retransmit_queue()中,如果不是LOSS状态,就加1

TcpExtTCPSlowStartRetrans(非RTO timer)重传次数:即tcp_fastretrans_alert()/tcp_simple_retransmit()->tcp_xmit_retransmit_queue()中,如果是LOSS状态,就加1
TcpExtTCPLostRetransmit

根据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。

TcpExtTCPSpuriousRTOstcp_process_frto(),如果frto_counter !=0 && frto_counter != 1加1

TCP ACK & SACK


类别
名称
描述
TcpExtDelayedACKLockedtcp_delack_timer(): delay ACK定时器因为user已经锁住而无法发送ACK的次数。
TcpExtDelayedACKLost
  1. tcp_validate_incoming()->tcp_send_dupack():当输入包不在接收窗口内,或者PAWS失败后,计数器加1
  2. tcp_data_queue(): 输入包的结束序列号< RCV_NXT时,加1
TcpExtDelayedACKstcp_delack_timer():调用tcp_send_ack()的次数,无论是否是成功。
TcpExtTCPHPAckstcp_ack():接收到包,进入quick path时加1
TcpExtTCPPureAckstcp_ack():接收慢速路径中的pure ACK数量
TcpExtTCPDSACKIgnoredNoUndotcp_sacktag_write_queue(): undo_marker为0并且接收到非法D-SACK块时,加1,即SACK中的序号太旧。
TcpExtTCPDSACKIgnoredOldtcp_sacktag_write_queue(): undo_marker不为0,并且接收到非法D-SACK块时,加1,即SACK中的序号太旧。
TcpExtTCPSACKDiscardtcp_sacktag_write_queue(): 非法SACK块(不包括D-SACK)计数,即SACK中的序号太旧。
TcpExtTCPDSACKOldSenttcp_dsack_set():如果SACK块开始序号小于RCV.NXT,加1
TcpExtTCPDSACKOfoSenttcp_dsack_set():如果SACK块开始序号大于等于RCV.NXT,加1
TcpExtTCPSACKRenegingtcp_clean_rtx_queue(): 如果snd_una(输入skb->ack)之后的具有最小开始序号skb(即sk_write_queue中的第一个skb)中有TCPCB_SACKED_ACKED标志,此时加1,这说明接收者已经丢掉了之前它已经SACK过的数据。
TcpExtTCPSackFailurestcp_retransmit_timer(): 在Reorder状态下,或者sacked_out不为0时,发生RTO,并且启用了SACK,加1
TcpExtTCPSackRecoveryFailtcp_retransmit_timer(): 在Reovery状态下发生RTO,并且启用了SACK,加1
TcpExtTCPDSACKRecvtcp_check_dsack(): 收到D-SACK,并且SACK0开始序号 < ACK号,加1
TcpExtTCPDSACKOfoRecvtcp_check_dsack(): 收到D-SACK,并且SACK0开始序号 >= ACK号,但SACK1包括SACK0。
TcpExtTCPSackRecoverytcp_fastretrans_alert(): SACK TCP进入Reovery状态的次数
TcpExtTCPSackShiftedtcp_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

TcpExtTCPSackShiftFallbacktcp_ack()->tcp_sacktag_write_queue()->tcp_sacktag_walk()->tcp_shift_skb_data()

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

  1. 不支持GSO
  2. prev skb不完全是paged的
  3. SACK的序号已经ACK过,等等
TcpExtTCPSackMergedtcp_ack()->tcp_sacktag_write_queue()->tcp_sacktag_walk()->tcp_shift_skb_data()->tcp_shifted_data()

在上面介绍的shift过程中,如果发现分割之后的skb被它之前的skb完全“吃掉”,本计数器加1


TCP TIME_WAIT

类别
名称
描述
TcpExtTWinet_twdr_do_twkill_work(): TIME_WAIT超时的socket数量(timeout >= 4s)
之所以按超时分别对待timewait socket,可能是考虑到长超时的socket的timeout时间分布比较分散,需要使用不同的查找方法。
TcpExtTWKilledinet_twdr_twcal_tick(): TIME_WAIT超时的socket数量.(timeout < 4s),
仅在启用sysctl_tw_recycle,并且使用TCP timestamp option时才会有这种情况,这时使用3.5x RTO时作为timewait timeout,而默认timeout为60s
TcpExtTWRecycledtcp_v4_connect() -> __inet_check_established(): 在建立时,如果port是从TIME_WAIT socket中复用的,加1
TcpExtTCPTimeWaitOverflowtcp_time_wait(): 当系统无法分配新的tcp_timewait_socket,或者tw_count(scheduled timewait sockets)超过sysctl_max_tw_buckets时,加1

TCP Others

类别
名称
描述
TcpExtTCPRenoRecoveryFailtcp_retransmit_timer(): 在Reovery状态下发生RTO,并且没有启用SACK,加1
TcpExtTCPRenoFailurestcp_retransmit_timer(): 在Reorder状态下,或者sacked_out不为0时,发生RTO,并且没有启用SACK,加1
TcpExtTCPRenoRecoverytcp_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)
阅读(1621) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~