获取 Linux 内核中的网络设备列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4494307/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 00:47:10  来源:igfitidea点击:

Getting list of network devices inside the Linux kernel

linuxnetwork-programminglinux-kernelkernel-module

提问by Peter Murfitt

I've been looking through net/core/dev.c and other files to try to find out how to get the list of network devices that are currently configured and it's proving to be a little difficult to find.

我一直在浏览 net/core/dev.c 和其他文件,试图找出如何获取当前配置的网络设备列表,但事实证明它有点难以找到。

The end goal is to be able to get network device statistics using dev_get_stats in dev.c, but I need to know the current interfaces so I can grab the net_device struct to pass in. I'm having to do this inside the kernel as I'm writing a module which adds in a new /proc/ entry which relates to some statistics from the current network devices so from what I can gather this must be done inside the kernel.

最终目标是能够在 dev.c 中使用 dev_get_stats 获取网络设备统计信息,但我需要知道当前的接口,以便我可以获取 net_device 结构来传入。我必须在内核中执行此操作,因为我正在编写一个模块,该模块添加了一个新的 /proc/ 条目,该条目与当前网络设备的一些统计信息相关,因此从我收集到的信息来看,这必须在内核中完成。

If someone could point me to how to get the interfaces it would be much appreciated.

如果有人能指出我如何获得接口,我将不胜感激。

采纳答案by eater

This ought to do the trick:

这应该可以解决问题:

#include <linux/netdevice.h>

struct net_device *dev;

read_lock(&dev_base_lock);

dev = first_net_device(&init_net);
while (dev) {
    printk(KERN_INFO "found [%s]\n", dev->name);
    dev = next_net_device(dev);
}

read_unlock(&dev_base_lock);

回答by caf

Given a struct net *netidentifying the net namespace that you are interested in, you should grab the dev_base_lockand use for_each_netdev():

给定struct net *net您感兴趣的网络命名空间,您应该获取dev_base_lock并使用for_each_netdev()

read_lock(&dev_base_lock);
for_each_netdev(net, dev) {
   /* Inspect dev */
}
read_unlock(&dev_base_lock);

(In newer kernels, you can use RCU instead, but that is probably an overcomplication in this case).

(在较新的内核中,您可以改用 RCU,但在这种情况下这可能过于复杂)。



To obtain the netnamespace to use, you should be registering your procfile with register_pernet_subsys():

要获取net要使用的命名空间,您应该使用以下命令注册您的proc文件register_pernet_subsys()

static const struct file_operations foostats_seq_fops = {
    .owner   = THIS_MODULE,
    .open    = foostats_seq_open,
    .read    = seq_read,
    .llseek  = seq_lseek,
    .release = foostats_seq_release,
};

static int foo_proc_init_net(struct net *net)
{
    if (!proc_net_fops_create(net, "foostats", S_IRUGO,
            &foostats_seq_fops))
        return -ENOMEM;
    return 0;
}

static void foo_proc_exit_net(struct net *net)
{
    proc_net_remove(net, "foostats");
}


static struct pernet_operations foo_proc_ops = {
    .init = foo_proc_init_net,
    .exit = foo_proc_exit_net,
};

register_pernet_subsys(&foo_proc_ops)

In your foostats_seq_open()function, you take a reference on the netnamespace, and drop it in the release function:

在你的foostats_seq_open()函数中,你引用了net命名空间,并将它放到了 release 函数中:

static int foostats_seq_open(struct inode *inode, struct file *file)
{
    int err;
    struct net *net;

    err = -ENXIO;
    net = get_proc_net(inode);
    if (net == NULL)
        goto err_net;

    err = single_open(file, foostats_seq_show, net);
    if (err < 0)
        goto err_open;

    return 0;

err_open:
    put_net(net);
err_net:
    return err;
}

static int foostats_seq_release(struct inode *inode, struct file *file)
{
    struct net *net = ((struct seq_file *)file->private_data)->private;

    put_net(net);
    return single_release(inode, file);
}

The foostats_seq_show()function can then obtain the net, walk the devices, gather the statistics and produce the output:

foostats_seq_show()然后net,该函数可以获取、遍历设备、收集统计信息并生成输出:

static int sockstat6_seq_show(struct seq_file *seq, void *v)
{
    struct net *net = seq->private;
    struct net_device *dev;

    int foostat, barstat;

    read_lock(&dev_base_lock);
    for_each_netdev(net, dev) {
       /* Inspect dev */
    }
    read_unlock(&dev_base_lock);

    seq_printf(seq, "Foo: %d\n", foostat);
    seq_printf(seq, "Bar: %d\n", barstat);

    return 0;
}