ruger 发表于 2006-12-1 22:45:59

请教:sk_buff和sock的诞生~

sk_buff和sock是INET Socket层存储和管理数据包的结构,对sk_buff操作的函数也有很多函数:alloc_skb,kfree_skb,skb_clone,skb_copy,skb_push,skb_pull,skb_put等等,但是sock和sk_buff是怎么联系的?通过自身的什么函数?有的版本是sk_write_queue指向sk_buff的首地址,但是在2.6的内核源码sock结构中没有找到sk_write_queue,想知道到具体sock和sk_buff怎么联系的?一个sock是否能能带一串sk_buff?一个sk_buff能存几个网卡接受的数据包?一个还是很多?
单独申请一个sk_buff算什么?(struct sk_buff *q这种)它和哪个sock关联?数据接收和发送的时候是不是不同的流程?
望详解~谢谢~
可否2.4和2.6分开解释?(要求不过分吧,请不要跟我说看Linux Network Internals这本书,时间来不及了,谢谢~)

zyzii 发表于 2006-12-2 09:53:58

sock本身是一个基类,对于TCP而言,(UDP也类似的)在分配sock时的大小是tcp_sock.但从tcp_sock到sock还要过几层才行,具体的情况是:
   sock--->inet_sock-->inet_connection_sock-->tcp_sock.
   这个实现是内核中面向对象的理念的体现。一个sk_buff只能是一个网卡的接收包。
   sock和sk_buff的联系是这样的,以收包举例:
   当网卡收到一个包时,分配一个sk_buff,然后将数据放到sk_buff->data指针指向的数据区。下面进行两个很重要的变量的初始化:
   skb->dev = dev;
   skb->protocol = eth_type_trans(skb, dev);
   这两个变量在该sk_buff向上传的过程中起着重要的控制方向的作用。

zyzii 发表于 2006-12-2 10:10:32

在 tcp_v4_rcv()函数中,根据sk_buff的IP头中的地址等数据找到相应的sock结构:
sk = __inet_lookup(&tcp_hashinfo, skb->nh.iph->saddr, th->source,
                           skb->nh.iph->daddr, ntohs(th->dest),
                           inet_iif(skb));

然后 通过调用过程:
      tcp_v4_rcv()--》tcp_v4_do_rcv()--》tcp_rcv_established()
   在tcp_rcv_established()会作一个TCP有关的操作,会把sock结构强制转化为tcp_sock的,但若没有问题了,则有一行:
   __skb_queue_tail(&sk->sk_receive_queue, skb);

    于是sk_buff就挂到sock的sk_receive_queue队列了。两者的关系就建立了。

zyzii 发表于 2006-12-2 10:15:07

sk_buff可以挂到sock的几个队列之中,具体要看情况了 ,在tcp_v4_rcv()函数中:

       if (!sock_owned_by_user(sk)) {
                if (!tcp_prequeue(sk, skb))
                        ret = tcp_v4_do_rcv(sk, skb);
        } else
                sk_add_backlog(sk, skb);

这几行就是根据情况不同挂到的sock的不同队列中的。

zyzii 发表于 2006-12-2 10:24:01

研究协议栈最好的书,我认为是《LINUX 内核2.4版源代码分析大全》,李善平等老师出的,但目前已经绝版了,不出了 。我的这本是从淘宝上买的。该书讲的很好。是最好的应该。该书将mm的slab也相当到位。尤其讲slab的分配过程,相当经典啊,其他的书是没有的 。
第二好的书是:《The LINUX Network Architecture》,看完 李善平等老师出的《LINUX 内核2.4版源代码分析大全》后再看会收获很大,但若直接看则估计没有什么效果。
第三是: 《 Linux Network Internals 》
   呵呵,大致如此,希望你早日成为内核级hacker :-D

ruger 发表于 2006-12-2 13:12:47

sock本身是一个基类,对于TCP而言,(UDP也类似的)在分配sock时的大小是tcp_sock.但从tcp_sock到sock还要过几层才行,具体的情况是:
   sock--->inet_sock-->inet_connection_sock-->tcp_sock.
   这个实现是内核中面向对象的理念的体现。一个sk_buff只能是一个网卡的接收包。
   sock和sk_buff的联系是这样的,以收包举例:
   当网卡收到一个包时,分配一个sk_buff,然后将数据放到sk_buff->data指针指向的数据区。下面进行两个很重要的变量的初始化:
   skb->dev = dev;
   skb->protocol = eth_type_trans(skb, dev);
   这两个变量在该sk_buff向上传的过程中起着重要的控制方向的作用。

谢谢如此精彩的回帖,节省了我很多查阅资料的时间啊!!!但是~~~
本人愚钝啊,还是没弄明白:是不是数据链路层存取数据包的结构也是sk_buff?网卡收到一个包的过程可否再说的详细一些(小声说句:“谢谢!”),比如从网卡产生中断(ei_interrupt,ei_receive,block_input)到netif_rx(netif_receive_skb)到ip_rcv到tcp_v4_rcv,是不是从中断开始就产生了sk_buff结构(什么函数产生的sk_buff,将数据包复制到data内的?),然后依次上传(记得内核中好像有个标记可以控制内核对网卡接收上来的数据包是否进行处理,也就是是否走mac—>ip->tcp这个流程,是否和raw_socket有关连?直接将原始数据传到上层?)这个时候sock还没产生?
“当网卡收到一个包时,分配一个sk_buff,然后将数据放到sk_buff->data指针指向的数据区”,这个过程是什么层上的什么函数完成的?是中断函数吗?(我对中断不熟)
   skb->dev = dev;
   skb->protocol = eth_type_trans(skb, dev);
dev是数据包经过的net_device,protocol是ethenet协议类型,这些和sock类型又是怎么关联起来的?
在 tcp_v4_rcv()函数中,根据sk_buff的IP头中的地址等数据找到相应的sock结构:
sk = __inet_lookup(&tcp_hashinfo, skb->nh.iph->saddr, th->source,
skb->nh.iph->daddr, ntohs(th->dest),
inet_iif(skb));

__inet_lookup又调用了__inet_lookup_established函数,然后又调用了一堆sk_for_each,不过在__inet_lookup_established自己声明了sock类型,是不是在这才是最先出现的sock类型?从参数( __inet_lookup)上看sock需要ip的源和目的地址,sk_buff到sock只是需要地址吗?不需要net_device等信息吗?sock只是管理两个IP地址直接从两个接口(网卡)的所有数据包吗?
sk_alloc和sock_alloc也能分配新的sock?但是没有关联sk_buff是这样的吗?这样只是分配了协议,而没有地址是吗?
sk_buff是只管接收数据包不管发送数据包是吗?
《LINUX 内核2.4版源代码分析大全》和《 Linux Network Internals 》 有电子版吗?可否给个下载链接?

稀里糊涂的又产生了这么多的问题,真是不好意思~~

zyzii 发表于 2006-12-2 13:40:37

“当网卡收到一个包时,分配一个sk_buff,然后将数据放到sk_buff->data指针指向的数据区”
这个是在中断函数中实现的。
数据链路层的工作是由网卡去完成的,内核这边只要根据具体的网卡硬件特性,将收到的数据放到skb->data里就行了。
   至于产生sk_buff的时间,要根据网卡的特性而定,有网卡要在收到中断后产生,例如8390的芯片;有的事先准备好sk_buff,例如marvell的芯片。
   sk_buff是用了管理数据的,当然也用于发送的过程了,它是服务于inet socket层以下的;inet socket层以上用的是msghdr{}。
    __inet_lookup()是个查找过程,假定在此之前的TCP已经建立好连接了。


呵呵,你的问题还真多阿 ,你可以去这个博客去看看,
http://hi.baidu.com/linux%5Fkernel
真正的过程实在是太复杂了,跟帖很难说的清楚。
至于电子版的《LINUX 内核2.4版源代码分析大全》和《 Linux Network Internals 》,我也没有的,我有的是书阿。我不喜欢看电子版的,费眼。

ruger 发表于 2006-12-2 13:48:33

“当网卡收到一个包时,分配一个sk_buff,然后将数据放到sk_buff->data指针指向的数据区”
这个是在中断函数中实现的。
数据链路层的工作是由网卡去完成的,内核这边只要根据具体的网卡硬件特性,将收到的数据放到skb->data里就行了。
   至于产生sk_buff的时间,要根据网卡的特性而定,有网卡要在收到中断后产生,例如8390的芯片;有的事先准备好sk_buff,例如marvell的芯片。
   sk_buff是用了管理数据的,当然也用于发送的过程了,它是服务于inet socket层以下的;inet socket层以上用的是msghdr{}。
    __inet_lookup()是个查找过程,假定在此之前的TCP已经建立好连接了。


呵呵,你的问题还真多阿 ,你可以去这个博客去看看,
http://hi.baidu.com/linux%5Fkernel
真正的过程实在是太复杂了,跟帖很难说的清楚。
至于电子版的《LINUX 内核2.4版源代码分析大全》和《 Linux Network Internals 》,我也没有的,我有的是书阿。我不喜欢看电子版的,费眼。

呵呵,这个博客是你的吗?我正在看这个blog啊~~~

zyzii 发表于 2006-12-2 14:19:12

不是的,我没有时间写博客的,不过我有时查东西会连到这个博客。博客的主人水平不错的。但要真正长知识,还是要自己去看书,自己多实践。还有毛德操的书是基础,推荐一下。 :-D

manioster 发表于 2006-12-2 14:41:24

关注
页: [1]
查看完整版本: 请教:sk_buff和sock的诞生~