一个简单的网络流量统计程序

  前面讲到,register_netdev首先为网络设备接口分配一个名称,然后将dev插入到一个叫做dev_base的网络设备全局链表中。由此我们不难想到,通过访问dev_base,就可以遍历到系统中的所有网络设备,而每一个网络设备接口都有一个net_device结构来表示。该结构中有一个成员函数指针:
    struct net_device_stats* (*get_stats)(struct net_device *dev);
它返回一个struct net_device_stats结构,该结构保存了所在网络设备接口的详细的流量统计信息:
    struct net_device_stats
    {
        unsigned long rx_packets; /* total packets received   */
        unsigned long tx_packets; /* total packets transmitted    */
        unsigned long rx_bytes; /* total bytes received     */
        unsigned long tx_bytes; /* total bytes transmitted  */
        unsigned long rx_errors; /* bad packets received     */
        unsigned long tx_errors; /* packet transmit problems */
        unsigned long rx_dropped; /* no space in linux buffers    */
        unsigned long tx_dropped;/* no space available in linux  */
        unsigned long multicast; /* multicast packets received   */
        unsigned long   collisions;

        /* detailed rx_errors: */
        unsigned long rx_length_errors;
        unsigned long rx_over_errors; /* receiver ring buff overflow  */
        unsigned long rx_crc_errors;/* recved pkt with crc error */
        unsigned long rx_frame_errors;/* recv’d frame alignment error */
        unsigned long rx_fifo_errors; /* recv’r fifo overrun      */
        unsigned long rx_missed_errors;/* receiver missed packet  */

    /* detailed tx_errors */
    unsigned long   tx_aborted_errors;
    unsigned long   tx_carrier_errors;
    unsigned long   tx_fifo_errors;
    unsigned long   tx_heartbeat_errors;
    unsigned long   tx_window_errors;

    /* for cslip etc */
    unsigned long   rx_compressed;
    unsigned long   tx_compressed;
};

    OK,有了这些基础知识,我们就可以写一个网络流量统计的内核模块了,这是一个最简单的程序,它每次被插入到内核中时,会在日志文件中打出当前系统上的所有网络设备接口的传输的和收到的字节数和包数。我们可以把它进一步改造,输出到/proc文件系统,再通过用户空间的一个程序计算单位时间的流量,就成为一个真正的网络流量统计程序了。
下面是代码:
/* netbase.c
 * helinqiang@hotmail.com
 * 2006-03-14
 */

#include <linux/init.h>
#include <linux/netdevice.h>

MODULE_AUTHOR(“Linqiang He, Hangzhou China”);
MODULE_LICENSE(“Dual BSD/GPL”);

static int __init netbase_init_module(void)
{
    struct net_device *dev = dev_base;
    struct net_device_stats *stats;
    while( dev != NULL ){
        printk(KERN_INFO ”dev name: %s
“, dev->name);

        stats = dev->get_stats(dev);
        printk(KERN_INFO ” transmitted bytes: %lu
“, stats->tx_bytes);

        printk(KERN_INFO ” received bytes: %lu
“, stats->rx_bytes);

        printk(KERN_INFO ” transmitted packets: %lu
“, stats->tx_packets);

        printk(KERN_INFO ” received packets: %lu
“, stats->rx_packets);

        dev = dev->next;
    }
    return 0;
}

static void __exit netbase_exit_module(void)
{
}

module_init(netbase_init_module);
module_exit(netbase_exit_module);

下面是在我的电脑上的某一时刻的输出结果:
Mar 14 21:22:34 localhost kernel: dev name: lo
Mar 14 21:22:34 localhost kernel:       transmitted bytes: 4660
Mar 14 21:22:34 localhost kernel:       received bytes: 4660
Mar 14 21:22:34 localhost kernel:       transmitted packets: 61
Mar 14 21:22:34 localhost kernel:       received packets: 61
Mar 14 21:22:34 localhost kernel: dev name: sit0
Mar 14 21:22:34 localhost kernel:       transmitted bytes: 0
Mar 14 21:22:34 localhost kernel:       received bytes: 0
Mar 14 21:22:34 localhost kernel:       transmitted packets: 0
Mar 14 21:22:34 localhost kernel:       received packets: 0
Mar 14 21:22:34 localhost kernel: dev name: eth0
Mar 14 21:22:34 localhost kernel:       transmitted bytes: 437071
Mar 14 21:22:34 localhost kernel:       received bytes: 4046403
Mar 14 21:22:34 localhost kernel:       transmitted packets: 2607
Mar 14 21:22:34 localhost kernel:       received packets: 17773

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>