linux核心沒有實作SNMP(SimpleNetwork Management Protocol,簡單網絡管理協定),隻是收集一些MIB(管理資訊基)并把它們輸出到/proc去。
[ include/uapi/linux/snmp.h ]
/* tcp mib definitions */
/*
* RFC 1213: MIB-II TCP group
* RFC 2012 (updates 1213): SNMPv2-MIB-TCP
*/
enum
{
TCP_MIB_NUM = 0,
TCP_MIB_RTOALGORITHM, /* RtoAlgorithm */
TCP_MIB_RTOMIN, /* RtoMin */
TCP_MIB_RTOMAX, /* RtoMax */
TCP_MIB_MAXCONN, /* MaxConn */
TCP_MIB_ACTIVEOPENS, /* ActiveOpens */
TCP_MIB_PASSIVEOPENS, /* PassiveOpens */
TCP_MIB_ATTEMPTFAILS, /* AttemptFails */
TCP_MIB_ESTABRESETS, /* EstabResets */
TCP_MIB_CURRESTAB, /* CurrEstab */
TCP_MIB_INSEGS, /* InSegs */
TCP_MIB_OUTSEGS, /* OutSegs */
TCP_MIB_RETRANSSEGS, /* RetransSegs */
TCP_MIB_INERRS, /* InErrs */
TCP_MIB_OUTRSTS, /* OutRsts */
TCP_MIB_CSUMERRORS, /* InCsumErrors */
__TCP_MIB_MAX
};
這個結構是要收集的和TCP有關的資訊類型。如:TCP_MIB_INSEGS表示接收到資料包。
[ include/net/snmp.h ]
/* TCP */
#define TCP_MIB_MAX __TCP_MIB_MAX
struct tcp_mib {
unsigned long mibs[TCP_MIB_MAX];
};
定義了一個結構,内含一個數組,用來對上面提到的資訊類型進行計數。
[ include/net/netns/mib.h ]
struct netns_mib {
DEFINE_SNMP_STAT(struct tcp_mib, tcp_statistics);
DEFINE_SNMP_STAT(struct ipstats_mib, ip_statistics);
DEFINE_SNMP_STAT(struct linux_mib, net_statistics);
DEFINE_SNMP_STAT(struct udp_mib, udp_statistics);
DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics);
DEFINE_SNMP_STAT(struct icmp_mib, icmp_statistics);
DEFINE_SNMP_STAT_ATOMIC(struct icmpmsg_mib, icmpmsg_statistics);
#if IS_ENABLED(CONFIG_IPV6)
struct proc_dir_entry *proc_net_devsnmp6;
DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6);
DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6);
DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics);
DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics);
DEFINE_SNMP_STAT_ATOMIC(struct icmpv6msg_mib, icmpv6msg_statistics);
#endif
#ifdef CONFIG_XFRM_STATISTICS
DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics);
#endif
};
這個結構定義了所有要統計的資訊,對TCP:DEFINE_SNMP_STAT(struct tcp_mib, tcp_statistics);這個宏展開如下:
[ include/net/snmp.h ]
#define SNMP_ARRAY_SZ 1
#define DEFINE_SNMP_STAT(type, name) \
__typeof__(type) __percpu *name[SNMP_ARRAY_SZ]
即:
__typeof__(struct tcp_mib) __percpu *tcp_statistics[ 1 ]
如果接收到了一個新的資料段,要增加計數:
[ net/ipv4/tcp_ipv4.c ]
int tcp_v4_rcv(struct sk_buff *skb)
{
...
struct net *net = dev_net(skb->dev); // 網絡名字空間
/* Count it even if it's bad */
TCP_INC_STATS_BH(net, TCP_MIB_INSEGS);
...
}
[ include/net/tcp.h ]
#define TCP_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.tcp_statistics, field)
[ include/net/snmp.h ]
#define SNMP_INC_STATS_BH(mib, field) \
__this_cpu_inc(mib[0]->mibs[field])
[ include/net/net_namespace.h ]
struct net {
...
struct netns_mib mib;
...
}
最後的展開如下:
__this_cpu_inc( net->mib.tcp_statistics[ 0 ]->mibs[ TCP_MIB_INSEGS ] )
對新接收的資料包進行了計數。