天天看點

tcp-ip : snmp

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 ] )

對新接收的資料包進行了計數。

tcp