ifconfig如何获得网卡的统计信息

        1)ifconfig 是通过解析 /proc/net/dev 文件来获得网卡的统计信息的,如下所示:

$ cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
enp3s0: 9666434  145598    0    0    0     0          0        20 28796033  143998    0    0    0     0       0          0
enp0s3f0: 89753829 1339304    0    0    0     0          0         0 220083622 1303148    0    0    0     0       0          0
    lo: 8551535   24076    0    0    0     0          0         0  8551535   24076    0    0    0     0       0          0
virbr0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
virbr0-nic:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0

        2)/proc/net/dev 里面的内容是如何产生的?

        /proc/net/dev 是由内核 dev_seq_show() 函数输出的,它的实现如下所示:

static int dev_seq_show(struct seq_file *seq, void *v) 
{
    if (v == SEQ_START_TOKEN)
        seq_puts(seq, "Inter-|   Receive                            "
                  "                    |  Transmit\n"
                  " face |bytes    packets errs drop fifo frame "
                  "compressed multicast|bytes    packets errs "
                  "drop fifo colls carrier compressed\n");
    else
        dev_seq_printf_stats(seq, v); 
    return 0;
}

        其中,dev_seq_printf_stats() 函数完成了最终的输出,它的实现如下所示:

static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
{  
    struct rtnl_link_stats64 temp;
    const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
   
    seq_printf(seq, "%6s: %7llu %7llu %4llu %4llu %4llu %5llu %10llu %9llu "
           "%8llu %7llu %4llu %4llu %4llu %5llu %7llu %10llu\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);
} 

        其中,dev_get_stats() 函数是用来获取网卡统计信息的,它的实现如下所示:

struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
                    struct rtnl_link_stats64 *storage)
{   
    const struct net_device_ops *ops = dev->netdev_ops;
    
    if (ops->ndo_get_stats64) {
        memset(storage, 0, sizeof(*storage));
        ops->ndo_get_stats64(dev, storage);
    } else if (ops->ndo_get_stats) {
        netdev_stats_to_stats64(storage, ops->ndo_get_stats(dev));
    } else {
        netdev_stats_to_stats64(storage, &dev->stats);
    }   
    storage->rx_dropped += (unsigned long)atomic_long_read(&dev->rx_dropped);
    storage->tx_dropped += (unsigned long)atomic_long_read(&dev->tx_dropped);
    storage->rx_nohandler += (unsigned long)atomic_long_read(&dev->rx_nohandler);
    return storage;
} 

        从上面可以看到,dev_get_stats() 函数首先判断网卡驱动是否实现了 dev->netdev_ops->ndo_get_stats64()、dev->netdev_ops->ndo_get_stats() 这两个接口,如果实现了,则通过这两个接口来获取网卡的统计信息,如果没有实现,则使用 netdev_stats_to_stats64() 函数来获取网卡的统计信息,该函数的实现如下所示:

void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64,
                 const struct net_device_stats *netdev_stats)
{   
#if BITS_PER_LONG == 64
    BUILD_BUG_ON(sizeof(*stats64) < sizeof(*netdev_stats));
    memcpy(stats64, netdev_stats, sizeof(*netdev_stats));
    /* zero out counters that only exist in rtnl_link_stats64 */
    memset((char *)stats64 + sizeof(*netdev_stats), 0,
           sizeof(*stats64) - sizeof(*netdev_stats));
#else
    size_t i, n = sizeof(*netdev_stats) / sizeof(unsigned long);
    const unsigned long *src = (const unsigned long *)netdev_stats;
    u64 *dst = (u64 *)stats64;
    
    BUILD_BUG_ON(n > sizeof(*stats64) / sizeof(u64));
    for (i = 0; i < n; i++)
        dst[i] = src[i];
    /* zero out counters that only exist in rtnl_link_stats64 */
    memset((char *)stats64 + n * sizeof(u64), 0,
           sizeof(*stats64) - n * sizeof(u64));
#endif
}

        可以看到,netdev_stats_to_stats64() 函数只是做了一个数据拷贝,其数据源来自于是网卡对应的 struct net_device 结构体中的 stats 成员,它的类型是 struct net_device_stats。以 Gmac 为例,它是在处理单个包的过程中,顺便更新了该结构体里的各个成员。例如,在驱动的发包函数 stmmac_xmit() 中更新发送字节数:

static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
{
...
    dev->stats.tx_bytes += skb->len;
...
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值