zoukankan      html  css  js  c++  java
  • 深入理解Linux网络技术内幕——用户空间与内核空间交互

    概述:

        内核空间与用户空间经常需要进行交互。举个例子:当用户空间使用一些配置命令如ifconfig或route时,内核处理程序就要响应这些处理请求。
        用户空间与内核有多种交互方式,最常用的有以下四种:通过/proc虚拟文件系统,通过/sys虚拟文件系统,通过ioctl系统调用,通过Netlink socket。 其中编写程序时最常使用ioctl,这四种方式中有两种是通过虚拟文件系统。

     procfs 与 sysctl

        procfs挂载/proc  sysctl挂载在/proc/sys(与后面介绍的/sys不同)。(注意,《Understanding Linux Network Internal》一书中使用的Linux内核已经比较陈旧,procfs与sysfs等内核交互机制已经有较大变化,本文虽然给出了一些新内核的代码,但主要功能介绍仍是来源于《Understanding Linux Network Internal》关于旧内核的说明。)

    procfs    

        procfs是一个虚拟文件系统,挂载在/proc目录下,编译内核时,可以通过配置内核选项make menuconfig->Filesystems  Pseudo filesystems  /proc file system support 来启用/关闭它。它不能以模块形式加载。 procfs是一个虚拟文件系统,在磁盘上并没有真实存在。但是我们却可以对它进行读、写、重定向甚至改变访问权限(procfs大部分是只读的内容,可写数据主要是存在于/proc/sys中,具体看sysctl介绍)。
        网络功能模块在注册初始化的时候,会在procfs下注册一些文件(网络相关的注册在/proc/net),用来进行内核与用户空间的数据交互。
        /proc下的目录通过proc_mkdir创建,/proc/net下的文件通过proc_net_fops_create 和 proc_net_remove进行创建和删除。这两个函数被封装成create_proc_entry和remove_proc_entry。(书中是使用的似乎是Linux2.x版本的Linux内核,在新版本<我用的Linux3.12.32>已经找不到这几个函数了)。书中还给出了arp的例子,新内核中也做了改动,下面给出新内核的Linux在/proc创建arp文件的实现:
    static const struct file_operations arp_seq_fops = {                            
        .owner      = THIS_MODULE,
        .open           = arp_seq_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
        .release    = seq_release_net,
    };

    static int __net_init arp_net_init(struct net *net)
    {
        if (!proc_create("arp", S_IRUGO, net->proc_net, &arp_seq_fops))
            return -ENOMEM;
        return 0;
    } 

    static inline struct proc_dir_entry *proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct file_operations *proc_fops)
    {
        return proc_create_data(name, mode, parent, proc_fops, NULL);
    }


        proc_create三个参数表示要创建的文件名为arp,权限为S_IRUGO(只读),父目录接口为net,文件操作句柄集合为arp_seq_fops。 arp_seq_fop 在初始化是会做另一个初始化arp_seq_open 其定义了一个结构体arp_seq_ops,该结构体使得当用户请求数据时,能只返回一条路径,就把多个例程的数据返回给用户。
    static int arp_seq_open(struct inode *inode, struct file *file)
    {
        return seq_open_net(inode, file, &arp_seq_ops, sizeof(struct neigh_seq_state));
    }

    static const struct seq_operations arp_seq_ops = {
        .start  = arp_seq_start,
        .next   = neigh_seq_next,
        .stop   = neigh_seq_stop,
        .show   = arp_seq_show,
    };



     sysctl:/proc/sys目录

        /proc/sys包含一些内核变量。这些变量可读、可写。对于这里面任何一个变量,内核可以决定在/proc/sys的那个目录下存放变量、变量名字、变量权限。
        存放在/proc/sys中的文件和目录都由 ctl_table结构体进行创建。ctl_table实例通过register_sysctl_table和unregister_sysctl_table进行注册和删除。
    struct ctl_table 
    {
        const char *procname;       /* Text ID for /proc/sys, or zero */
        void *data;
        int maxlen;
        umode_t mode;
        struct ctl_table *child;    /* Deprecated */
        proc_handler *proc_handler; /* Callback for text formatting */
        struct ctl_table_poll *poll;
        void *extra1;
        void *extra2;
    };


    sysfs

        由于/proc目录和/proc/sys目录的滥用,出现了用于替代其文件功能的sysfs。
        具体另作介绍。

    ioctl

        ioctl一般通过socket与内核进行通信。以ifconfig eth0 mtu 1250为例
    struct ifreq data;
    fd = socket(PF_INET, SOCK_DGRAM, 0);
    < ... initialize "data" ...>
    err = ioctl(fd, SIOCSIFMTU, &data);


    ifconfig先在本地初始化要传入内核的数据,然后通过ioctl与内核进行交互。
        网络中ioctl普遍使用sock_ioctl来搜索正确的内核 处理程序处理传入内核的数据。
        与ioctl有关的例子见我的另一篇博文http://blog.csdn.net/windeal3203/article/details/39320605


    Netlink


        Netlink使用标准socket与内核进行通信
    int socket(int domain, int type, int protocol)
        其中Netlink使用新的协议族PF_NETLINK(domain),并且type只能为SOCK_DGRAM。使用多种protocol,每个protocol代表一种或多种TCP/IP协议栈的组件。比如NETLINK_ROUTE表示网络协议栈的路由功能和邻居发现协议功能。NETLINK_FIREWALL用于firewall (Netfilter)。
    #define NETLINK_ROUTE       0   /* Routing/device hook              */          
    #define NETLINK_UNUSED      1   /* Unused number                */
    #define NETLINK_USERSOCK    2   /* Reserved for user mode socket protocols  */
    #define NETLINK_FIREWALL    3   /* Unused number, formerly ip_queue     */
    .....

        Netlink相对于其他(ioctl等)用户空间与内核交互方式的优点在于,使用Netlink,内核可以主动传输内核数据给用户,而不仅仅是作为用户请求的一种应答。

  • 相关阅读:
    面向对象课程第三次博客总结
    面向对象课程多线程总结
    23种设计模式整理
    java中synchronized与lock的理解与应用
    关于MySQL查询优化
    mysql操作规范建议
    Linux中实体链接与符号链接详解
    获取本地ipv4地址方法(go语言)
    分库分表与负载均衡的一致性hash算法
    golang闭包的一个经典例子
  • 原文地址:https://www.cnblogs.com/Windeal/p/4284598.html
Copyright © 2011-2022 走看看