/proc/net/dev由来

转载自:https://blog.csdn.net/zouchun2016/article/details/80743516,未经允许不得转载。

/proc/net/dev由来

       我们都知道可以从/proc/net/dev下去读取网络设备收发包时相关的数据,但之前从来没有关注这些文件的来源,直到前几天遇到一个wifi的tx和rx等数据都为0的问题不得不去探索原因,起初以为/proc/net/dev是按照文件操作的方式写进去的,结果在应用层和驱动中找了一遍没有发现相关的代码,于是到linux内核代码里一探究竟,果不其然。(我使用的linux版本为linux4.1.25)。
       进入linux-lsk-v4.1.25\net\core\net_procfs.c,看到这个名字是不是恍然大悟呢?对,这就是产生/proc/net/dev文件的入口,下面将逐一进行分析:

int __init dev_proc_init(void)
{
    int ret = register_pernet_subsys(&dev_proc_ops);
    if (!ret)
        return register_pernet_subsys(&dev_mc_net_ops);

    return ret;
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

       这里将dev_proc_ops进行了注册,驱动加载后,或将网络设备注册到linux内核,这时候linux内核就会调用这个接口,执行dev_proc_ops定义的函数,该函数如下:

static struct pernet_operations __net_initdata dev_proc_ops = {
    .init = dev_proc_net_init,
    .exit = dev_proc_net_exit,
 };
  
  
  • 1
  • 2
  • 3
  • 4

       不用我说吧,这里分别是开始和结束时执行的函数,我们只关注开始的dev_proc_net_init函数,结束时的函数有兴趣的可自己去看,具体如下:

static int __net_init dev_proc_net_init(struct net *net)
{
    int rc = -ENOMEM;

    if (!proc_create("dev", S_IRUGO, net->proc_net, &dev_seq_fops))
        goto out;
    if (!proc_create("softnet_stat", S_IRUGO, net->proc_net,&softnet_seq_fops))
        goto out_dev;
    if (!proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops))
        goto out_softnet;

    if (wext_proc_init(net))
        goto out_ptype;
    rc = 0;

out:
    return rc;

out_ptype:
    remove_proc_entry("ptype", net->proc_net);

out_softnet:
    remove_proc_entry("softnet_stat", net->proc_net);

out_dev:
    remove_proc_entry("dev", net->proc_net);

goto out;
} 
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

       想必大家都看到了,函数创建/proc/net/dev,/proc/net/softnet_stat,/proc/net/ptype文件,然后指定了文件的操作接口的函数指针,我们现在只关注/proc/net/dev的文件操作指针dev_seq_fops。具体如下:

static const struct file_operations dev_seq_fops = {
    .owner   = THIS_MODULE,
    .open    = dev_seq_open,
    .read    = seq_read,
    .llseek  = seq_lseek,
    .release = seq_release_net,
};
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

       我们知道实际上对/proc下的文件进行操作时,cat操作对应的是.open函数,echo操作对应的是.write函数,这里我们只关注open函数,对应的函数指针是dev_seq_open,如下:

static int dev_seq_open(struct inode *inode, struct file *file)
{
    return seq_open_net(inode, file, &dev_seq_ops,
        sizeof(struct seq_net_private));
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5

       这里又来了一个dev_seq_ops,经常看linux内核代码的都知道,实际上我们不需要注seq_open_net函数,直接进入dev_seq_ops即可,具体如下:

static const struct seq_operations dev_seq_ops = {
    .start = dev_seq_start,
    .next  = dev_seq_next,
    .stop  = dev_seq_stop,
    .show  = dev_seq_show,
};
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

       翻了这么多大山,这里终于看了了山顶,那就是这个dev_seq_show函数了,我想大家看到的时候应该都会第一时间去看这个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;
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

       上面的if分之就是用来打印/proc/net/dev头部的,你可以cat /proc/net/dev仔细对照看一下是不是酱紫。else分之是用来打印/proc/net/dev的身体的,为什么是对立的分支呢?因为linux起来后刚开始没有检测到网络设备,此时的v就是SEQ_START_TOKEN,管他有没有呢,先把头搞出来再说。下面看一下身体吧,这才是应该重点关注的。

static void dev_seq_printf_stats(struct seq_file *seq, structnet_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);
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

       这里总算看明白了吧?这个net_device就是驱动中注册网络设备时的结构体,至于里面的这些收发包的数据,当然是在驱动中产生的了,具体就不详细叙述了。

猜你喜欢

转载自blog.csdn.net/yunyou666666/article/details/80951269
Dev