免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2084 | 回复: 2
打印 上一主题 下一主题

Linux内核TCP/IP网络部分代码日记(2004年1月5日) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2004-01-05 17:13 |只看该作者 |倒序浏览
刚开始读linux内核的代码,觉得无从入手,在开始的时候看的是起动部分的代码,因为对硬件、汇编等知识的贫瘠所以放弃了。好在有2年多的Linux应用开发经验,所以决定从网络部分开始,尽管如此,仍然发现网络部分和其它部分比如文件系统、内存管理等有着很多的联系。不过没有灰心,相信总会有一天能够对各个部分都有一个详细的理解,大家也一样不要被代码吓倒,一步步来,多参考一下其它的文章,一定会成功!

    以下代码全部摘自linux-2.4.20-8(Redhat9)

[/code]
第一章 套接字的初始化

    在讨论套接字的建立、读写前,先介绍一下内核中关于套接字的初始化的代码,这样才能更好的理解后面的代码。
    我们先来看看sock_init(net/socket.c)函数,该函数是在系统初始化的时候执行的,源程序如下:
void __init sock_init(void)
{
        int i;

        printk(KERN_INFO "Linux NET4.0 for Linux 2.4\n";
        printk(KERN_INFO "Based upon Swansea University Computer Society NET3.039\n";

        /*
         *      Initialize all address (protocol) families.
         */

           指针数组,每种family对应一个数组元素,第二章
       有详细说明

        for (i = 0; i < NPROTO; i++)
                net_families = NULL;

        /*
         *      Initialize sock SLAB cache.
         */
            通过slab分配sock缓存,关于slab请参考
        Linux内存管理部分

        sk_init();

#ifdef SLAB_SKB
        /*
         *      Initialize skbuff SLAB cache
         */

            分配skbuff,Linux网络层采用统一的缓冲区结构skbuff,被组织
        成双向链表,数据通过它在各层传递

        skb_init();
#endif

        /*
         *      Wan router layer.
         */

        路由模块的初始化
#ifdef CONFIG_WAN_ROUTER
        wanrouter_init();
#endif

        /*
         *      Initialize the protocols module.
         */

        注册网络文件系统并mount,Linux的虚拟文件系统使得网络、
     管道等等都可以是一个独立的文件系统,对于核心的开发和应用
     的开发都可以用一种统一的方式。可以cat /proc/filesystems查看
     当前的系统中安装了哪些文件系统。

      register_filesystem(&sock_fs_type);
        sock_mnt = kern_mount(&sock_fs_type);
        /* The real protocol initialization is performed when
         *  do_initcalls is run.
         */


        /*
         * The netlink device handler may be needed early.
         */

#ifdef CONFIG_NET
        rtnetlink_init();
#endif
#ifdef CONFIG_NETLINK_DEV
        init_netlink();
#endif
#ifdef CONFIG_NETFILTER
        netfilter_init();
#endif

#ifdef CONFIG_BLUEZ
        bluez_init();
#endif
}

第二章 建立套接字

        在发送接收数据之前,我们要通过系统调用(socket)建立套接字。关于用户进程通过系统调用申请内核服务请参考其它文章。
        系统调用socket通过0x80中断调用内核中相应的函数sys_socket(net/socket.c),源程序如下:
asmlinkage long sys_socket(int family, int type, int protocol)
{
        int retval;

        定义struct socket结构指针sock
        struct socket *sock;

        调用sock_create函数分配空间初始化一系列的结构成员等。
     retval = sock_create(family, type, protocol, &sock);
        if (retval < 0)
                       前几天在CU上看到了有人问内核中goto语句的问题
               当时大鹰给出了答案,在次说明一遍。
               goto语句在内核中很大的原因在于效率的问题,还有
              一部分的原因是使得错误处理更加简洁,还有极小部分
              的原因是为了代码风格的一致。

                goto out;

          为套接字分配一个可利用的文件描述字,
       使得在应用层可以向读写文件那样来读写套接字

        retval = sock_map_fd(sock);
        if (retval < 0)
                goto out_release;

out:
        /* It may be already another descriptor Not kernel problem. */
        return retval;

out_release:
        sock_release(sock);
        return retval;
}

sock_create(net/socket.c)函数源程序如下:
int sock_create(int family, int type, int protocol, struct socket **res)
{
        int i;
        struct socket *sock;

        /*
         *      Check protocol is in range
         */

            对family和type进行有效性的检查
        if (family < 0 || family >;= NPROTO)
                return -EAFNOSUPPORT;
        if (type < 0 || type >;= SOCK_MAX)
                return -EINVAL;

        /* Compatibility.
           This uglymoron is moved from INET layer to here to avoid
           deadlock in module load.
         */

        对参数family是PF_INET而type是SOCK_PACKET(这种类型不是标准的BSD套接字类型,它是Linux自身对套接字系统的扩展,它允许进程直接对设备层的数据包进行操作)的调用做一下兼容性的转换,对family重新赋值PF_PACKET
        if (family == PF_INET && type == SOCK_PACKET) {

        本人觉得warned赋初始值更为妥当,该小段代码是打印出
        警告信息,current是指向当前task的全局指针。

           static int warned;
                if (!warned) {
                        warned = 1;
                        printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", current->;comm);
                }
                family = PF_PACKET;
        }

如果在编译内核的时候把网络部分编译成模块
#if defined(CONFIG_KMOD) && defined(CONFIG_NET)
        /* Attempt to load a protocol module if the find failed.
         *
         * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user
         * requested real, full-featured networking support upon configuration.
         * Otherwise module support will break!
         */

指针数组,其中create成员(函数指针)保存了每种协议的create函数地址
对于PF_INET协议来说,这个数组是在inet_init函数(net/ipv4/af_inet.c)
中通过调用sock_register(net/socket.c)来赋值的,并把create指向了
inet_create函数。
以下程序说明如果该钟协议对应的数组元素为空,那么就加载相应的模块。

        if (net_families[family]==NULL)
        {
                char module_name[30];
                sprintf(module_name,"net-pf-%d",family);
                request_module(module_name);
        }
#endif

对于这里为什么要加锁我不能给出详细的答案,因为我也不知道,
但是想想,分配sock和创建sock的时候应该会访问到很多全局
的东西,并且net_families所指向的内存应该是系统的共享内存区域
所以上锁也是可以理解的。大家看看sock_register函数(net/socket.c)
可能会更好的理解,因为这个函数是对net_families做赋值的,在
这个函数中用到了net_family_write_lock函数。

        net_family_read_lock();
        if (net_families[family] == NULL) {
                i = -EAFNOSUPPORT;
                goto out;
        }

/*
*      Allocate the socket and allow the family to set things up. if
*      the protocol is 0, the family is instructed to select an appropriate
*      default.
*/

       分配socket,该函数实际上是在网络文件系统上生成新的inode
       然后做一些相应的设置工作。

        if (!(sock = sock_alloc()))
        {
                printk(KERN_WARNING "socket: no more sockets\n";
                i = -ENFILE;            /* Not exactly a match, but its the
                                           closest posix thing */
                goto out;
        }

        sock->;type  = type;

       创建socket,其实调用的是inet_create,因为net_families[PF_INET]
       在inet_init的时候被初始化,create函数指针指向的是inet_create函数

      if ((i = net_families[family]->;create(sock, protocol)) < 0)
        {
                sock_release(sock);
                goto out;
        }

        *res = sock;

out:
        net_family_read_unlock();
        return i;
}
[code][/code]

论坛徽章:
0
2 [报告]
发表于 2004-01-05 18:21 |只看该作者

Linux内核TCP/IP网络部分代码日记(2004年1月5日)

顶,但是看不懂

论坛徽章:
0
3 [报告]
发表于 2004-01-05 20:23 |只看该作者

Linux内核TCP/IP网络部分代码日记(2004年1月5日)

好`~~还在努力中~~
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP