net-snmpとlinuxの64bitカウンタ実装
誤動作の調査で調べたのでついでに覚え書き。
snmpdで取得できるネットワークインターフェイスカウンタの値は
/proc/net/devを元にしている。
中身はこんなの。
# cat /proc/net/dev Inter-| Receive | Transmit ... face |bytes packets errs drop fifo frame compressed multicast|bytes ... lo: 268198 1760 0 0 0 0 0 0 268198 ... eth0:1438145878 2202918421 0 0 0 0 0 6 36330...
出力している箇所は以下。(@net/core/dev.c)
net_device_statsに格納されているカウンタ値がunsigned longなので32bitカーネルだと
32bitカウンタ値までしか取得できないが、64bitカーネルの場合はlongが64bitになるため
そのまま64bitカウンタが取得できる。(LP64等の場合)
static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev) { if (dev->get_stats) { struct net_device_stats *stats = dev->get_stats(dev); seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu " "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", dev->name, stats->rx_bytes, stats->rx_packets, stats->rx_errors, stats->rx_dropped + stats->rx_missed_errors, stats->rx_fifo_errors, stats->rx_length_errors + stats->rx_over_errors + stats->rx_crc_errors + stats->rx_frame_errors, stats->rx_compressed, stats->multicast, stats->tx_bytes, stats->tx_packets, stats->tx_errors, stats->tx_dropped, stats->tx_fifo_errors, stats->collisions, stats->tx_carrier_errors + stats->tx_aborted_errors + stats->tx_window_errors + stats->tx_heartbeat_errors, stats->tx_compressed); } else seq_printf(seq, "%6s: No statistics available.\n", dev->name); }
net_device_statsへ値を格納しているのはドライバ側で用意している関数で
bnx2(Broadcom NetXtreme II)のドライバを見てみると以下のような感じ。
32bitモードで動いてる限り上位がそのまま切り捨てられている。
(@drivers/net/bnx2.c)
#define GET_NET_STATS64(ctr) \ (unsigned long) ((unsigned long) (ctr##_hi) << 32) + \ (unsigned long) (ctr##_lo) #define GET_NET_STATS32(ctr) \ (ctr##_lo) #if (BITS_PER_LONG == 64) #define GET_NET_STATS GET_NET_STATS64 #else #define GET_NET_STATS GET_NET_STATS32 #endif ... static struct net_device_stats * bnx2_get_stats(struct net_device *dev) ... net_stats->rx_bytes = GET_NET_STATS(stats_blk->stat_IfHCInOctets); net_stats->tx_bytes = GET_NET_STATS(stats_blk->stat_IfHCOutOctets); ...
で、実際の所はsnmpdがクライアントから問い合わせが無い場合も定期的に
インターフェイスの情報をポーリングしており、32bitカーネルでも取りこぼしが
起きないようになっている。(内部的には上位、下位32bitでそれぞれ管理)
これにより32bitカーネルの場合でも64bitカウンタを擬似的に作り出せているが
当然のことながら、カーネルからは下位32bitしか取得できないのでsnmpdを落とすと
上位32bitはリセットされる。
64bitカーネルの場合はそのまま値が拾えるので何も問題なし。