分享

Linux2.6.30内核的sock结构(3)-1/2 - TCP-IP结构体 - 978...

 jijo 2010-01-18
Linux2.6.30内核的sock结构(3)-1/2

Linux2.6.30内核的sock结构

978计划工作组 2009-11-18

1函数源码

struct sock {

       /*

        * Now struct inet_timewait_sock also uses sock_common, so please just

        * don't add nothing before this first member (__sk_common) --acme

        */

       struct sock_common     __sk_common;

#define sk_family          __sk_common.skc_family

#define sk_state            __sk_common.skc_state

#define sk_reuse           __sk_common.skc_reuse

#define sk_bound_dev_if              __sk_common.skc_bound_dev_if

#define sk_node                   __sk_common.skc_node

#define sk_nulls_node           __sk_common.skc_nulls_node

#define sk_bind_node           __sk_common.skc_bind_node

#define sk_refcnt          __sk_common.skc_refcnt

#define sk_hash                   __sk_common.skc_hash

#define sk_prot                    __sk_common.skc_prot

#define sk_net               __sk_common.skc_net

       unsigned char        sk_shutdown : 2,

                            sk_no_check : 2,

                            sk_userlocks : 4;

       unsigned char        sk_protocol;

       unsigned short              sk_type;

       int                  sk_rcvbuf;

       socket_lock_t        sk_lock;

       /*

        * The backlog queue is special, it is always used with

        * the per-socket spinlock held and requires low latency

        * access. Therefore we special case it's implementation.

        */

       struct {

              struct sk_buff *head;

              struct sk_buff *tail;

       } sk_backlog;

       wait_queue_head_t *sk_sleep;

       struct dst_entry      *sk_dst_cache;

#ifdef CONFIG_XFRM

       struct xfrm_policy  *sk_policy[2];

#endif

       rwlock_t        sk_dst_lock;

       atomic_t         sk_rmem_alloc;

       atomic_t         sk_wmem_alloc;

       atomic_t         sk_omem_alloc;

       int                  sk_sndbuf;

       struct sk_buff_head       sk_receive_queue;

       struct sk_buff_head       sk_write_queue;

#ifdef CONFIG_NET_DMA

       struct sk_buff_head       sk_async_wait_queue;

#endif

       int                  sk_wmem_queued;

       int                  sk_forward_alloc;

       gfp_t                     sk_allocation;

       int                  sk_route_caps;

       int                  sk_gso_type;

       unsigned int           sk_gso_max_size;

       int                  sk_rcvlowat;

       unsigned long               sk_flags;

       unsigned long          sk_lingertime;

       struct sk_buff_head       sk_error_queue;

       struct proto           *sk_prot_creator;

       rwlock_t        sk_callback_lock;

       int                  sk_err,

                            sk_err_soft;

       atomic_t         sk_drops;

       unsigned short              sk_ack_backlog;

       unsigned short              sk_max_ack_backlog;

       __u32                   sk_priority;

       struct ucred           sk_peercred;

       long               sk_rcvtimeo;

       long               sk_sndtimeo;

       struct sk_filter          *sk_filter;

       void               *sk_protinfo;

       struct timer_list      sk_timer;

       ktime_t                  sk_stamp;

       struct socket          *sk_socket;

       void               *sk_user_data;

       struct page            *sk_sndmsg_page;

       struct sk_buff        *sk_send_head;

       __u32                   sk_sndmsg_off;

       int                  sk_write_pending;

#ifdef CONFIG_SECURITY

       void               *sk_security;

#endif

       __u32                   sk_mark;

       /* XXX 4 bytes hole on 64 bit */

       void               (*sk_state_change)(struct sock *sk);

       void               (*sk_data_ready)(struct sock *sk, int bytes);

       void               (*sk_write_space)(struct sock *sk);

       void               (*sk_error_report)(struct sock *sk);

      int                  (*sk_backlog_rcv)(struct sock *sk,

                                            struct sk_buff *skb); 

       void                    (*sk_destruct)(struct sock *sk);

};

2结构用途

    sock结构是对socket结构的扩充,与文件系统相关的域放在socket结构中了,而与网络相关的域放在了sock结构中了,目的是在非网络数据结构中定义socket域时无需包括整个sock结构,而只分配一个sock结构的指针即可,这样可以大大的节约内存。

3语句注释

3.1 成员注释

struct sock_common      __sk_common

       网络层的最常用属性放在此结构中了,如地址族、连接状态等。详细信息参见sock_common结构。

unsigned char   sk_shutdown : 2

       标示了socket关闭的情况,关于关闭的情况有3种,如下所示:

    SHUTDOWN_MASK:宏值为3,表示完全关闭。

    RCV_SHUTDOWN:宏值为1 :接收通道被关闭(远端发送了FIN 数据包)。

SEND_SHUTDOWN:发送通道关闭(本地主动发送FIN 数据包)。

unsigned char   sk_no_check : 2

       打开或关闭校验和。

unsigned char   sk_userlocks : 4

       用户锁标志,有四种锁,共占四位,如下所示:

SOCK_SNDBUF_LOCK  :宏值为1sk_userlocks的第0位(最低位为0位)为1时不可以修改sk_sndbuf的值,即如果锁了就不可以修改此值。

SOCK_RCVBUF_LOCK :宏值为2sk_userlocks的第1位(最低位为0位)为1时不可以修改sk_rcvbuf的值,即如果锁了就不可以修改此值。

SOCK_BINDADDR_LOCK  :宏值为4sk_userlocks域在inet_bind函数中将第2位(最低位为0位)置位1,此位被置位后不可再调用inet_reset_saddr函数重新设置地址。

SOCK_BINDPORT_LOCK :宏值为8sk_userlocks域在inet_bind函数中将第3位(最低位为0位)置位1,该位被置位后不可调用inet_put_port函数。

unsigned char   sk_protocol

       标示使用哪种协议,此域在inet_create中被初始化。

unsigned short sk_type

       socket的类型,有7种类型,如下所示:

SOCK_STREAM:值为1,流套接字,提供双向连续且可信赖的数据流,TCP协议用此种类型。SOCK_DGRAM:值为2,数据报套接字,使用不连续不可信赖的数据包连接,UDP协议用此种类

型。

SOCK_RAW:值为3,原始套接字,一般的套接字是通过TCP才能和IP底层进行数据交换的,原始套接字可以直接穿过TCP层操作IP数据包,也就是说原始套接字是上层应用程序和IP层之间的通道。

SOCK_RDM:值为4提供可信赖的数据包连接

SOCK_SEQPACKET:值为5,顺序包套接字, 提供连续可信赖的数据包连接

SOCK_DCCP:值为6,数据报阻塞控制协议套接字。

SOCK_PACKET:值为10提供和网络驱动程序直接通信,Linux特有的方式

还有一个特殊的宏,标示socket类型的上限值的宏SOCK_MAX,被定义为 (SOCK_PACKET + 1)

Int   sk_rcvbuf

       以字节为单位的接收缓冲区的大小。

socket_lock_t    sk_lock

       sock的同步锁。

struct {

              struct sk_buff *head;

              struct sk_buff *tail;

} sk_backlog

       sk_backlog链表中数据的处理的函数调用关系是:

tcp_recvmsg调用release_sockrelease_sock调用__release_sock__release_sock调用sk_backlog_rcv,而sk_backlog_rcv函数指针指向了tcp_v4_do_rcv,详情参见下面对sk_backlog_rcv的介绍,tcp_v4_do_rcv函数在TCP_ESTABLISHED状态时通过调用tcp_rcv_established函数实现数据处理并释放了节点。在TCP_LISTEN状态时会调用tcp_child_process

sk_backlog链表中的数据被增加的函数调用关系是:

ip层接到数据包处理完后是通过ip_local_deliver函数把ip包递送到上层进行处理的(具体的Ip层及以下层是如何处理的在其他文档中讨论),ip_local_deliver函数调用ip_local_deliver_finish函数,ip_local_deliver_finish函数中通过全局的struct net_protocol的实例inet_protos[hash]取得struct net_protocol的指针。

inet_protos[hash]handler域是一个函数指针指向了tcp_v4_rcv函数;系统中存在一个全局静态struct net_protocol结构的实例tcp_protocol,此实例的handler域被tcp_v4_rcv初始化,在inet_init函数中将此静态实例tcp_protocol通过inet_add_protocol付给了hash表结构的数组inet_protos,这样inet_protos[hash]->handler域就指向了tcp_v4_rcv

tcp_v4_rcv函数在需要将数据放到sk_backlog对列时通过直接调用sk_add_backlog函数实现了将收到的数据增加到sk_backlog链表中,或者通过调用tcp_v4_do_rcv函数,tcp_v4_do_rcvTCP_LISTEN状态时可能会调用tcp_child_process ,而tcp_child_process 再调用sk_add_backlog函数间接实现将收到的数据添加到sk_backlog链表中。

wait_queue_head_t *sk_sleep

       等待队列,主要应用在客户端发起连接后等待连接完成、服务器端的accept函数等待新连接建立的完成,等待数据到达等方面。涉及的函数如rfcomm_sock_acceptsco_sock_acceptinet_wait_for_connect等。

       现以inet_wait_for_connect为例讲述一下sk_sleep的应用,以及线程是如何被睡眠和唤醒的;函数首先用DEFINE_WAIT宏初始化一个wait_queue_t类型的睡眠队列节点,调用prepare_to_wait函数把当前进程添加到sk_sleep睡眠队列(通过调用__add_wait_queue函数实现),然后函数进入一个while循环等待系统连接完成,while循环中调用schedule_timeout函数,schedule_timeout函数会调用setup_timer_on_stack把当前线程放入一个计时器队列并将process_timeout函数作为时间到后的执行函数,然后调用schedule函数让调度函数重新选择一个就绪的线程去执行,当计时器到期后会执行process_timeout函数,而process_timeout函数会调用wake_up_process函数把刚才睡眠的线程唤醒,inet_wait_for_connect函数继续执行,调用signal_pending函数查看信号是否到达,到达后执行finish_wait函数将当前线程从sk_sleep睡眠队列中删除,至此连接完成。

struct dst_entry       *sk_dst_cache

       目的入口,最终生成的IP数据报的路由称为目的入口(dst_entry),目的入口反映了相邻的外部主机在主机内部的一种映像     

rwlock_t      sk_dst_lock

       读写锁,针对目的入口结构(dst_entry)的读写锁。

atomic_t      sk_rmem_alloc

       接收缓冲队列中已经分配的字节数,用于跟踪缓冲区的使用情况。

atomic_t      sk_wmem_alloc

       发送缓冲队列中已经分配的字节数,用于跟踪缓冲区的使用情况。

atomic_t      sk_omem_alloc

       当前申请的sock选项的空间大小

int   sk_sndbuf

       socket所允许的最大发送缓冲区。最小值用宏SOCK_MIN_SNDBUF表示,宏值为2048。它的值在系统初始化的时候设为变量sysctl_tcp_wmem[1]的值,在tcp_init函数中sysctl_tcp_wmem[1] 被初始化为16*1024,可以通过系统调用进行修改。

struct sk_buff_head       sk_receive_queue

接收队列,与sk_backlog域关系密切,ip层接到数据包处理完后是通过ip_local_deliver函数把ip包递送到上层进行处理的,ip_local_deliver函数调用ip_local_deliver_finish函数,ip_local_deliver_finish函数最终会调用tcp_v4_rcv函数

       tcp_v4_rcv函数会先判断进程空间是否有进程使用sock及是否在等待数据到来,如sock空闲且在等待数据到来则直接放到sk_receive_queue对列中,如sock空闲但未在等待则加数据到prequeue对列,如进程在使用sock则将数据放到sk_backlog对列。

struct sk_buff_head       sk_write_queue

       发送数据队列,在函数sock_init_data中被初始化,在函数ip_append_dataip_append_page中被增加节点,在函数ip_flush_pending_framesip_push_pending_frames中被减少节点。

int   sk_wmem_queued

       记录了当前在发送缓存队列sk_write_queue中总的字节数。当收到对应的ack包后此值才会被相应的减少。

int   sk_forward_alloc

       sock分配的缓存的总合,在__sk_mem_schedule函数中分配读、写缓冲区,分配成功则此值增加,在函数__sk_mem_reclaim中释放分配的读、写缓冲区,释放成功则此值相应的减少,注意一次分配和减少的缓冲区的大小是宏PAGE_SIZE的整数倍,此值是0X10004k大小。

gfp_t     sk_allocation

       用于标示内存分配的一种模式。在sock_init_data函数中被初始化为GFP_KERNEL,此宏值为0GFP_KERNEL表示在内存分配时如果内存不够可以睡眠等待,也可以是其它宏,如:GFP_ATOMIC(内存的分配不可睡眠)、GFP_USER(为用户空间页来分配内存; 可能睡眠)等。

此处的GFPGet Free Pages的缩写。

int   sk_route_caps

       标示网络驱动的特征,可以是如下值的组合:NETIF_F_SGNETIF_F_IP_CSUMNETIF_F_NO_CSUMNETIF_F_HW_CSUM 等,具体的参见net_device结构。

int   sk_gso_type

       gsoGeneric Segmentation Offload的缩写,中文为“普通段卸载”,此域表示GSO的类型。在tcp_v4_connecttcp_v6_connect函数中分别被赋值为SKB_GSO_TCPV4(针对v4IP分片)和SKB_GSO_TCPV6(针对v6IP分片)。sk_gso_type每位代表的含义为SKB_GSO_TCPV4(第0位) SKB_GSO_UDP(第1位)、SKB_GSO_DODGY(第2位)、SKB_GSO_TCP_ECN(第3位)、SKB_GSO_TCPV6(第4位)、SKB_GSO_FCOE(第5位)。

       sock的选项标志,可以被设置为SO_LINGERSO_BROADCASTSO_KEEPALIVESO_OOBINLINESO_TIMESTAMPING

unsigned int             sk_gso_max_size

       最大的gso(普通段卸载)尺寸。

int   sk_rcvlowat

       接收缓冲区的最小字节数,此值在Linux中是固定值1在函数sock_init_data中被初始化。

unsigned long   sk_flags

       sock的选项标志,可以被设置为SO_LINGERSO_BROADCASTSO_KEEPALIVESO_OOBINLINESO_TIMESTAMPING

unsigned long   sk_lingertime

       如果sk_flags标志的SO_LINGER位为1,那么当执行关闭(closeshutdown)动作时将等到所有套接字里排队的消息成功发送或延时sk_lingertime时间后才会返回,否则调用将立即返回。

struct sk_buff_head       sk_error_queue

       错误队列,是一个sk_buff结构的链表。          

struct proto       *sk_prot_creator

       指向一组协议处理函数集。inet_create函数调用sk_alloc函数,sk_prot_creator在函数sk_alloc中被初始化,可能的取值为tcp_protocoludp_protocolicmp_protocol

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多