Socket 结构体

 

 

proto socket 关联结构:node

 { .type = SOCK_STREAM, .protocol = IPPROTO_TCP, .prot =       &tcp_prot, .ops =        &inet_stream_ops, .flags =      INET_PROTOSW_PERMANENT | INET_PROTOSW_ICSK, }, { .type = SOCK_DGRAM, .protocol = IPPROTO_UDP, .prot =       &udp_prot, .ops =        &inet_dgram_ops, .flags = INET_PROTOSW_PERMANENT, }, {
const struct proto_ops inet_stream_ops = { .family = PF_INET, .owner = THIS_MODULE, .release = inet_release, .bind = inet_bind, .connect = inet_stream_connect, .socketpair = sock_no_socketpair, .accept = inet_accept, .getname = inet_getname, .poll = tcp_poll, .ioctl = inet_ioctl, .listen = inet_listen, .shutdown = inet_shutdown, .setsockopt = sock_common_setsockopt, .getsockopt = sock_common_getsockopt, .sendmsg = inet_sendmsg, .recvmsg = inet_recvmsg, .mmap = sock_no_mmap, .sendpage = inet_sendpage, .splice_read = tcp_splice_read, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_sock_common_setsockopt, .compat_getsockopt = compat_sock_common_getsockopt, .compat_ioctl = inet_compat_ioctl, #endif }; struct proto tcp_prot = { .name = "TCP", .owner = THIS_MODULE, .close = tcp_close, .connect = tcp_v4_connect, .disconnect = tcp_disconnect, .accept = inet_csk_accept, .ioctl = tcp_ioctl, .init = tcp_v4_init_sock, .destroy = tcp_v4_destroy_sock, .shutdown = tcp_shutdown, .setsockopt = tcp_setsockopt, .getsockopt = tcp_getsockopt, .recvmsg = tcp_recvmsg, .sendmsg = tcp_sendmsg, .sendpage = tcp_sendpage, .backlog_rcv = tcp_v4_do_rcv, .release_cb = tcp_release_cb, .hash = inet_hash, .unhash = inet_unhash, .get_port = inet_csk_get_port, .enter_memory_pressure = tcp_enter_memory_pressure, .stream_memory_free = tcp_stream_memory_free, .sockets_allocated = &tcp_sockets_allocated, .orphan_count = &tcp_orphan_count, .memory_allocated = &tcp_memory_allocated, .memory_pressure = &tcp_memory_pressure, .sysctl_mem = sysctl_tcp_mem, .sysctl_wmem = sysctl_tcp_wmem, .sysctl_rmem = sysctl_tcp_rmem, .max_header = MAX_TCP_HEADER, .obj_size = sizeof(struct tcp_sock), .slab_flags = SLAB_DESTROY_BY_RCU, .twsk_prot = &tcp_timewait_sock_ops, .rsk_prot = &tcp_request_sock_ops, .h.hashinfo = &tcp_hashinfo, .no_autobind = true, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_tcp_setsockopt, .compat_getsockopt = compat_tcp_getsockopt, #endif .diag_destroy = tcp_abort, };

 

SOCKT 结构:linux

/** * struct sock_common - minimal network layer representation of sockets * @skc_daddr: Foreign IPv4 addr * @skc_rcv_saddr: Bound local IPv4 addr * @skc_hash: hash value used with various protocol lookup tables * @skc_u16hashes: two u16 hash values used by UDP lookup tables * @skc_dport: placeholder for inet_dport/tw_dport * @skc_num: placeholder for inet_num/tw_num * @skc_family: network address family * @skc_state: Connection state * @skc_reuse: %SO_REUSEADDR setting * @skc_reuseport: %SO_REUSEPORT setting * @skc_bound_dev_if: bound device index if != 0 * @skc_bind_node: bind hash linkage for various protocol lookup tables * @skc_portaddr_node: second hash linkage for UDP/UDP-Lite protocol * @skc_prot: protocol handlers inside a network family * @skc_net: reference to the network namespace of this socket * @skc_node: main hash linkage for various protocol lookup tables * @skc_nulls_node: main hash linkage for TCP/UDP/UDP-Lite protocol * @skc_tx_queue_mapping: tx queue number for this connection * @skc_flags: place holder for sk_flags * %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE, * %SO_OOBINLINE settings, %SO_TIMESTAMPING settings * @skc_incoming_cpu: record/match cpu processing incoming packets * @skc_refcnt: reference count * * This is the minimal network layer representation of sockets, the header * for struct sock and struct inet_timewait_sock. */
 /* * 该结构是传输控制块信息的最小集合,由sock和inet_timewait_sock结构 * 前面相同部分单独构成,所以只用来构成这两种结构 */
 //tcp_timewait_sock包含inet_timewait_sock,inet_timewait_sock包含sock_common /* struct sock里面包含struct sock_common 以tcp为例,struct tcp_sock包含struct inet_connection_sock,inet_connection_sock包含 struct inet_sock,struct inet_sock包含struct sock, struct sock后面是 struct sock_common。因此在struct socket里面的sk指向的开辟空间大小是sizeof(struct tcp_sock) 以udp为例,struct udp_sock包含struct inet_connection_sock inet_connection_sock包含struct inet_sock,struct inet_sock包含struct sock, struct sock后面是 struct sock_common。。因此在struct socket里面的sk指向的开辟空间大小是sizeof(struct udp_sock) 以raw为例,struct raw_sock包含struct inet_connection_sock inet_connection_sock包含struct inet_sock,struct inet_sock包含struct sock, struct sock后面是 struct sock_common。。因此在struct socket里面的sk指向的开辟空间大小是sizeof(struct raw_sock) //tcp_timewait_sock包含inet_timewait_sock,inet_timewait_sock包含sock_common tcp_request_sock包含inet_request_sock,inet_request_sock包含request_sock*/
//sock_common是传输控制块信息最小集合 struct sock是比较通用的网络层描述块,与具体的协议族无关,他描述个各个不一样协议族传输层的公共信息
struct sock_common { /* skc_daddr and skc_rcv_saddr must be grouped on a 8 bytes aligned * address on 64bit arches : cf INET_MATCH() */
    /* @skc_daddr: Foreign IPv4 addr @skc_rcv_saddr: Bound local IPv4 addr */ union { __addrpair skc_addrpair; struct { __be32 skc_daddr; __be32 skc_rcv_saddr; }; }; union { unsigned int skc_hash; __u16 skc_u16hashes[2]; }; /* skc_dport && skc_num must be grouped as well */ union { __portpair skc_portpair; struct { __be16 skc_dport; __u16 skc_num; }; }; unsigned short skc_family; /** 等同于TCP的状态 见TCPF_ESTABLISHED*/
    volatile unsigned char skc_state; /* * 是否能够重用地址和端口 在SO_REUSEADDR中设置,linxu系统中设置地址可重用,端口也能够重用 端口复用是有条件的,就是sk若是传输控制块容许复用而且不是监听状态sk->sk_state != TCP_LISTEN,见inet_csk_get_port */ unsigned char        skc_reuse:4; unsigned char        skc_reuseport:1; unsigned char        skc_ipv6only:1; unsigned char        skc_net_refcnt:1; /* 若是不为0,即为输出报文的网络设备索引号 */
    int            skc_bound_dev_if;//经过应用程序的setsockopt里面的选项设置
    /* * 已绑定端口的传输控制模块利用该字段插入到与之绑定 * 端口信息结构为头结点的链表中。释放端口时,会从中 * 删除。仅用于基于链接的传输控制块,如TCP *inet_bind_bucket加入到的sk->sk_bind_node中,见inet_bind_hash struct sock被添加到inet_bind_bucket结构的owners链表中(inet_bind_hash),而后该inet_bind_bucket经过node节点加入到tcp_hashinfo中 */ union { struct hlist_node skc_bind_node; struct hlist_node    skc_portaddr_node;//经过函数 ip4_datagram_connect中的udp_v4_rehash添加把udp协议的struct sock添加到udp_table,
 }; /* Networking protocol blocks we attach to sockets. * socket layer -> transport layer interface */
    struct proto        *skc_prot; possible_net_t skc_net; #if IS_ENABLED(CONFIG_IPV6)
    struct in6_addr skc_v6_daddr; struct in6_addr skc_v6_rcv_saddr; #endif atomic64_t skc_cookie; /* following fields are padding to force * offset(struct sock, sk_refcnt) == 128 on 64bit arches * assuming IPV6 is enabled. We use this padding differently * for different kind of 'sockets' */ union { unsigned long skc_flags; struct sock    *skc_listener; /* request_sock */
        struct inet_timewait_death_row *skc_tw_dr; /* inet_timewait_sock */ }; /* * fields between dontcopy_begin/dontcopy_end * are not copied in sock_copy() */
    /* private: */
    int            skc_dontcopy_begin[0]; /* public: */
    /* * TCP维护一个全部TCP传输控制块的散列表tcp_hashinfo, * 而skc_node用来将所属TCP传输控制块连接到该散列表, udp的hashinfo为udp_table */
     //udp没有加入到这里面任何一个list中 本段为服务器端的时候tcp和raw在listen的时候 //调用inet_csk_listen_start把struct sock添加到对应协议的struct proto对应的h成员(hashinfo)中
 union { struct hlist_node    skc_node;//raw经过raw_hash_sk把sk加入到raw_hashinfo的ht
        struct hlist_nulls_node skc_nulls_node;//tcp经过inet_hash把sk->skc_nulls_node加入到tcp_hashinfo结构中的listening_hash
 }; int skc_tx_queue_mapping; union { int skc_incoming_cpu; u32 skc_rcv_wnd; u32 skc_tw_rcv_nxt; /* struct tcp_timewait_sock */ }; /* * 引用计数,当引用计数为0时才能被释放 */ atomic_t skc_refcnt; /* private: */
    int                     skc_dontcopy_end[0]; union { u32 skc_rxhash; u32 skc_window_clamp; u32 skc_tw_snd_nxt; /* struct tcp_timewait_sock */ }; /* public: */ }; /** * struct sock - network layer representation of sockets * @__sk_common: shared layout with inet_timewait_sock * @sk_shutdown: mask of %SEND_SHUTDOWN and/or %RCV_SHUTDOWN * @sk_userlocks: %SO_SNDBUF and %SO_RCVBUF settings * @sk_lock: synchronizer * @sk_rcvbuf: size of receive buffer in bytes * @sk_wq: sock wait queue and async head * @sk_rx_dst: receive input route used by early demux * @sk_dst_cache: destination cache * @sk_policy: flow policy * @sk_receive_queue: incoming packets * @sk_wmem_alloc: transmit queue bytes committed * @sk_write_queue: Packet sending queue * @sk_omem_alloc: "o" is "option" or "other" * @sk_wmem_queued: persistent queue size * @sk_forward_alloc: space allocated forward * @sk_napi_id: id of the last napi context to receive data for sk * @sk_ll_usec: usecs to busypoll when there is no data * @sk_allocation: allocation mode * @sk_pacing_rate: Pacing rate (if supported by transport/packet scheduler) * @sk_max_pacing_rate: Maximum pacing rate (%SO_MAX_PACING_RATE) * @sk_sndbuf: size of send buffer in bytes * @sk_no_check_tx: %SO_NO_CHECK setting, set checksum in TX packets * @sk_no_check_rx: allow zero checksum in RX packets * @sk_route_caps: route capabilities (e.g. %NETIF_F_TSO) * @sk_route_nocaps: forbidden route capabilities (e.g NETIF_F_GSO_MASK) * @sk_gso_type: GSO type (e.g. %SKB_GSO_TCPV4) * @sk_gso_max_size: Maximum GSO segment size to build * @sk_gso_max_segs: Maximum number of GSO segments * @sk_lingertime: %SO_LINGER l_linger setting * @sk_backlog: always used with the per-socket spinlock held * @sk_callback_lock: used with the callbacks in the end of this struct * @sk_error_queue: rarely used * @sk_prot_creator: sk_prot of original sock creator (see ipv6_setsockopt, * IPV6_ADDRFORM for instance) * @sk_err: last error * @sk_err_soft: errors that don't cause failure but are the cause of a * persistent failure not just 'timed out' * @sk_drops: raw/udp drops counter * @sk_ack_backlog: current listen backlog * @sk_max_ack_backlog: listen backlog set in listen() * @sk_priority: %SO_PRIORITY setting * @sk_type: socket type (%SOCK_STREAM, etc) * @sk_protocol: which protocol this socket belongs in this network family * @sk_peer_pid: &struct pid for this socket's peer * @sk_peer_cred: %SO_PEERCRED setting * @sk_rcvlowat: %SO_RCVLOWAT setting * @sk_rcvtimeo: %SO_RCVTIMEO setting * @sk_sndtimeo: %SO_SNDTIMEO setting * @sk_txhash: computed flow hash for use on transmit * @sk_filter: socket filtering instructions * @sk_timer: sock cleanup timer * @sk_stamp: time stamp of last packet received * @sk_tsflags: SO_TIMESTAMPING socket options * @sk_tskey: counter to disambiguate concurrent tstamp requests * @sk_socket: Identd and reporting IO signals * @sk_user_data: RPC layer private data * @sk_frag: cached page frag * @sk_peek_off: current peek_offset value * @sk_send_head: front of stuff to transmit * @sk_security: used by security modules * @sk_mark: generic packet mark * @sk_cgrp_data: cgroup data for this cgroup * @sk_memcg: this socket's memory cgroup association * @sk_write_pending: a write to stream socket waits to start * @sk_state_change: callback to indicate change in the state of the sock * @sk_data_ready: callback to indicate there is data to be processed * @sk_write_space: callback to indicate there is bf sending space available * @sk_error_report: callback to indicate errors (e.g. %MSG_ERRQUEUE) * @sk_backlog_rcv: callback to process the backlog * @sk_destruct: called at sock freeing time, i.e. when all refcnt == 0 * @sk_reuseport_cb: reuseport group container */
  /*struct sock是与具体传输层协议相关的套接字,全部内核的操做都基于这个套接字。 //传输控制块 struct socket里面的struct sock指向了这里 //在inet_create中为该结构体分配空间并赋初值。 /*套接字中本段和对端的相关信息都放在inet_sock中,能够保证和协议无关,各类协议都用该结构存储本地地址端口和对端地址端口已经链接状态等 以tcp为例,struct tcp_sock包含struct inet_connection_sock,inet_connection_sock包含 struct inet_sock,struct inet_sock包含struct sock。 因此在struct socket里面的sk指向的开辟空间大小是sizeof(struct tcp_sock) 以udp为例,struct udp_sock包含struct inet_connection_sock inet_connection_sock包含struct inet_sock,struct inet_sock包含struct sock。 因此在struct socket里面的sk指向的开辟空间大小是sizeof(struct udp_sock) 以raw为例,struct raw_sock包含struct inet_connection_sock inet_connection_sock包含struct inet_sock,struct inet_sock包含struct sock。 因此在struct socket里面的sk指向的开辟空间大小是sizeof(struct raw_sock) struct sock里面包含struct sock_common /*以tcp为例,struct tcp_sock包含struct inet_connection_sock,inet_connection_sock包含 struct inet_sock,struct inet_sock包含struct sock, struct sock后面是 struct sock_common。因此在struct socket里面的sk指向的开辟空间大小是sizeof(struct tcp_sock) 以udp为例,struct udp_sock包含struct inet_connection_sock inet_connection_sock包含struct inet_sock,struct inet_sock包含struct sock, struct sock后面是 struct sock_common。。因此在struct socket里面的sk指向的开辟空间大小是sizeof(struct udp_sock) 以raw为例,struct raw_sock包含struct inet_connection_sock inet_connection_sock包含struct inet_sock,struct inet_sock包含struct sock, struct sock后面是 struct sock_common。。因此在struct socket里面的sk指向的开辟空间大小是sizeof(struct raw_sock) //tcp_timewait_sock包含inet_timewait_sock,inet_timewait_sock包含sock_common tcp_request_sock包含inet_request_sock,inet_request_sock包含request_sock tcp_sock->inet_connection_sock->inet_sock->sock(socket里面的sk指向sock)*/
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_node            __sk_common.skc_node//raw经过raw_hash_sk sk->sk_node加入到raw_hashinfo的ht,至关于struct sock链接到了raw_hashinfo中
#define sk_nulls_node        __sk_common.skc_nulls_node//tcp经过inet_hash把sk->skc_nulls_node加入到tcp_hashinfo结构中的listening_hash。见__sk_nulls_add_node_rcu
#define sk_refcnt        __sk_common.skc_refcnt
#define sk_tx_queue_mapping    __sk_common.skc_tx_queue_mapping

#define sk_dontcopy_begin    __sk_common.skc_dontcopy_begin
#define sk_dontcopy_end        __sk_common.skc_dontcopy_end
#define sk_hash            __sk_common.skc_hash
#define sk_portpair        __sk_common.skc_portpair
#define sk_num            __sk_common.skc_num
#define sk_dport        __sk_common.skc_dport
#define sk_addrpair        __sk_common.skc_addrpair
#define sk_daddr        __sk_common.skc_daddr
#define sk_rcv_saddr        __sk_common.skc_rcv_saddr
#define sk_family        __sk_common.skc_family
//////sk_flags取值为sock_flags, 状态装换图为前面的sk_state,取值为TCP_SYN_RECV等 sk_state在tcp_set_state中赋值
#define sk_state        __sk_common.skc_state //建立sk的时候,默认为TCP_CLOSE sock_init_data
#define sk_reuse        __sk_common.skc_reuse
#define sk_reuseport        __sk_common.skc_reuseport
#define sk_ipv6only        __sk_common.skc_ipv6only
#define sk_net_refcnt        __sk_common.skc_net_refcnt
#define sk_bound_dev_if        __sk_common.skc_bound_dev_if
//客户端tcp在conncet的时候把sk经过inet_bind_bucket加入到tcp_hashinfo中 inet_bind_bucket也被添加到inet_connection_sock中的icsk_bind_hash //参考 sk_add_bind_node
#define sk_bind_node        __sk_common.skc_bind_node
/* 指向网络接口层的指针,若是是TCP套接字,为tcp_prot * 若是是UDP套接字为udp_prot。raw_prot * */
#define sk_prot            __sk_common.skc_prot
#define sk_net            __sk_common.skc_net
#define sk_v6_daddr        __sk_common.skc_v6_daddr
#define sk_v6_rcv_saddr    __sk_common.skc_v6_rcv_saddr
#define sk_cookie        __sk_common.skc_cookie
#define sk_incoming_cpu        __sk_common.skc_incoming_cpu
  /* * 标志位,可能的取值参见枚举类型sock_flags. * 判断某个标志是否设置调用sock_flag函数来 * 判断,而不是直接使用位操做。 */
#define sk_flags        __sk_common.skc_flags
#define sk_rxhash        __sk_common.skc_rxhash
 /* * 同步锁,其中包括了两种锁:一是用于用户进程读取数据 * 和网络层向传输层传递数据之间的同步锁;二是控制Linux * 下半部访问本传输控制块的同步锁,以避免多个下半部同 * 时访问本传输控制块 */ socket_lock_t sk_lock; /* * 接收队列,等待用户进程读取。TCP比较特别, * 当接收到的数据不能直接复制到用户空间时才会 * 缓存在此 */
    struct sk_buff_head sk_receive_queue; /* * 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. * Note : rmem_alloc is in this structure to fill a hole * on 64bit arches, not because its logically part of * backlog. */
      /* * 后备接收队列,目前只用于TCP.传输控制块被上锁后(如应用层 * 读取数据时),当有新的报文传递到传输控制块时,只能把报文 * 放到后备接受队列中,以后有用户进程读取TCP数据时,再从 * 该队列中取出复制到用户空间中. * 一旦用户进程解锁传输控制块,就会当即处理 * 后备队列,将TCP段处理以后添加到接收队列中。 */
    struct { atomic_t rmem_alloc; int len; struct sk_buff    *head; struct sk_buff    *tail; } sk_backlog; ////这个只针对接收数据,发送数据对应的是sk_rmem_alloc, 
    //阅读函数__sk_mem_schedule能够了解proto的内存状况判断方法 //表示接收队列中全部skb的总长度,在sock_queue_rcv_skb函数的skb_set_owner_r中增长
#define sk_rmem_alloc sk_backlog.rmem_alloc 
  /* * 预分配缓存长度,这只是一个标识,目前 只用于TCP。 * 当分配的缓存小于该值时,分配必然成功,不然须要 * 从新确认分配的缓存是否有效。参见__sk_mem_schedule(). * 在sk_clone()中,sk_forward_alloc被初始化为0. * * update:sk_forward_alloc表示预分配长度。当咱们第一次要为 * 发送缓冲队列分配一个struct sk_buff时,咱们并非直接 * 分配须要的内存大小,而是会之内存页为单位进行 * 预分配(此时并非真的分配内存)。当把这个新分配 * 成功的struct sk_buff放入缓冲队列sk_write_queue后,从sk_forward_alloc * 中减去该sk_buff的truesize值。第二次分配struct sk_buff时,只要再 * 从sk_forward_alloc中减去新的sk_buff的truesize便可,若是sk_forward_alloc * 已经小于当前的truesize,则将其再加上一个页的整数倍值, * 并累加如tcp_memory_allocated。 * 也就是说,经过sk_forward_alloc使全局变量tcp_memory_allocated保存 * 当前tcp协议总的缓冲区分配内存的大小,而且该大小是 * 页边界对齐的。 */ //这是本sock的缓存大小,若是要看整个tcp sock的缓存大小,要参考tcp_prot中的memory_allocated成员
     ////阅读函数__sk_mem_schedule能够了解proto的内存状况判断方法 。 注意和上面的sk_wmem_alloc的区别
    int sk_forward_alloc; //skb_entail中的sk_mem_charge里面会对新分配的SKB空间作一次减法,表示预分配缓存空间少了 在真正分配空间以前须要比较这个值,看内存空间释放使用达到限度 //在应用层send_msg的时候,会在函数__sk_mem_schedule中开辟空间,为sk_forward_alloc增长amt * SK_MEM_QUANTUM;若是发送的数据长度小于该值,确定超过,若果大于该值 //则会增长sk_forward_alloc拥有的内存空间,见sk_wmem_schedule //该变量表示的是当前sk的可用空间,预分配后的可用空间。例如应用层send,在内核分配ksb的时候空间作减法,表示可用空间少了这部分长度,当发送出去释放skb后,作加法,这时表示可用空间有多了
 __u32 sk_txhash; #ifdef CONFIG_NET_RX_BUSY_POLL unsigned int sk_napi_id; unsigned int sk_ll_usec; #endif atomic_t sk_drops; /* 接收缓冲区大小的上限,默认值是sysctl_rmem_default(sock_init_data),即32767, 也就是IP首部16位长度(最大65535)的一半*/
    //当sock接收到一个包的时候,会在sock_queue_rcv_skb中判断当前队列中已有的skb占用的buffer和这个新来的buff以后是否超过了sk_rcvbuf
    int sk_rcvbuf; /* * 套接字过滤器。在传输层对输入的数据包经过BPF过滤代码进行过滤, * 只对设置了套接字过滤器的进程有效。 */
    struct sk_filter __rcu    *sk_filter; /* * 进程等待队列。进程等待链接、等待输出缓冲区、等待 * 读数据时,都会将进程暂存到此队列中。这个成员最初 * 是在sk_clone()中初始化为NULL,该成员实际存储的socket结构 * 中的wait成员,这个操做在sock_init_data()中完成。 有的版本这里直接是wait, 唤醒该队列上的进程函数是sock_def_wakeup */ union { struct socket_wq __rcu    *sk_wq; struct socket_wq    *sk_wq_raw; }; #ifdef CONFIG_XFRM struct xfrm_policy __rcu *sk_policy[2]; #endif
    struct dst_entry    *sk_rx_dst; /* * 目的路由项缓存,通常都是在建立传输控制块发送 * 数据报文时,发现未设置该字段才从路由表或路由 * 缓存中查询到相应的路由项来设置新字段,这样能够 * 加速数据的输出,后续数据的输出没必要再查询目的 * 路由。某些状况下会刷新此目的路由缓存,好比断开 * 链接、从新进行了链接、TCP重传、从新绑定端口 * 等操做 */
    struct dst_entry __rcu    *sk_dst_cache; /* Note: 32bit hole on 64bit arches */
     /* 所在传输控制块中,为发送而分配的全部SKB数据区的总长度。这个成员和 * sk_wmem_queued不一样,全部由于发送而分配的SKB数据区的内存都会统计到 * sk_wmem_alloc成员中。例如,在tcp_transmit_skb()中会克隆发送队列中的 * SKB,克隆出来的SKB所占的内存会统计到sk_wmem_alloc,而不是sk_wmem_queued中。 * * 释放sock结构时,会先将sk_wmem_alloc成员减1,若是为0,说明没有待 * 发送的数据,才会真正释放。因此这里要先将其初始化为1 ,参见 * sk_alloc()。 * 该成员在skb_set_owner_w()中会更新。 *///经过阅读函数sock_alloc_send_pskb能够理解改变量的做用 每开辟一个SKB的时候当应用程序经过套接口传数据的时候,最终会把数据传输到SKB中,而后把数据长度+header长度的值赋值给该变量中,表示当前该套接字中未发送的数据为多少 // 见sock_alloc_send_pskb中的skb_set_owner_w 在开辟空间前要和sk_sndbuf作比较 //在sk_alloc的时候初始化设置为1,而后在skb_set_owner_w加上SKB长度,当SKB发送出去后,在减去该SKB的长度,因此这个值当数据发送后其值始终是1,不会执行sock_wfree //这个为发送队列(包括克隆的)分配的实际空间,sk_forward_alloc是提早预分配的,实际上并无分片空间,只是说先肯定下来能够用这么多空间,就是后面分片空间的时候最多能够分片这么多空间。
    atomic_t        sk_wmem_alloc;//这个只针对发送数据,接收数据对应的是sk_rmem_alloc, 
 /* * 分配辅助缓冲区的上限,辅助数据包括进行设置选项、 * 设置过滤时分配到的内存和组播设置等 */ atomic_t sk_omem_alloc; /* * 发送缓冲区长度的上限,发送队列中报文数据总长度不能 * 超过该值.默认值是sysctl_wmem_default,即32767。在经过setsockops设置时,其值最大为sysctl_wmem_max的两倍 */ //发送缓冲区会根据该proto使用的内存状况,进行调整,见__sk_mem_schedule中的sk_stream_moderate_sndbuf 并能经过tcp_rmem调整。 
    int sk_sndbuf; /* * 发送队列,在TCP中,此队列同时也是重传队列, * 在sk_send_head以前为重传队列,以后为发送 * 队列,参见sk_send_head */ //这上面存的是发送SKB链表,即便调用了dev_queue_xmit后,该SKB海在该链表上面,知道收到对方ack。
    struct sk_buff_head sk_write_queue; /* * Because of non atomicity rules, all * changes are protected by socket lock. */ kmemcheck_bitfield_begin(flags); unsigned int        sk_padding : 2, sk_no_check_tx : 1, sk_no_check_rx : 1, sk_userlocks : 4, sk_protocol : 8, sk_type : 16; #define SK_PROTOCOL_MAX U8_MAX kmemcheck_bitfield_end(flags); /* 发送队列中全部报文数据的总长度,目前只用于TCP 。这里 * 统计的是发送队列中全部报文的长度,不包括由于发送而克隆 * 出来的SKB占用的内存。是真正的占用空间的发送队列数据长度。见skb_entail * */
    int            sk_wmem_queued;//skb_entail中会赋值
    gfp_t            sk_allocation; /* * 内存分配方式,参见include\linux\gfp.h。值为__GFP_DMA等 */ u32 sk_pacing_rate; /* bytes per second */ u32 sk_max_pacing_rate; /* * 目的路由网络设备的特性,在sk_setup_caps()中根据 * net_device结构的features成员设置 */ //参考//若是网口设备dev设置了dev->features |= NETIF_F_TSO,则支持TSO 参考e1000网卡的这里enic_ethtool_ops
 netdev_features_t sk_route_caps; netdev_features_t sk_route_nocaps; /* * 传输层支持的GSO类型,如SKB_GSO_TCPV4等 默认该值为SKB_GSO_TCPV4 */
    int            sk_gso_type;//tcp_v4_connect
     /* * 这个成员在sk_setup_caps()中初始化,表示最大TCP分段的大小。 * 注意,这个大小包括IP首部长度长度、IP选项长度及TCP首部和选项, * 另外还要减1(这个减1不知道是为何。。。。) */ unsigned int sk_gso_max_size; u16 sk_gso_max_segs; /* * 标识接收缓存下限值 */
    int sk_rcvlowat; /* 关闭套接字前发送剩余数据的时间*/ unsigned long            sk_lingertime;//setsockops中设置 SO_LINGER
     /* * 错误链表,存放详细的出错信息。应用程序经过setsockopt * 系统调用设置IP_RECVERR选项,即需获取详细出错信息。当 * 有错误发生时,可经过recvmsg(),参数flags为MSG_ERRQUEUE * 来获取详细的出错信息 * update: * sk_error_queue用于保存错误消息,当ICMP接收到差错消息或者 * UDP套接字和RAW套接字输出报文出错时,会产生描述错误信息的 * SKB添加到该队列上。应用程序为能经过系统调用获取详细的 * 错误消息,须要设置IP_RECVERR套接字选项,以后可经过参数 * flags为MSG_ERRQUEUE的recvmsg系统调用来获取详细的出错 * 信息。 * UDP套接字和RAW套接字在调用recvmsg接收数据时,能够设置 * MSG_ERRQUEUE标志,只从套接字的错误队列上接收错误而不 * 接收其余数据。实现这个功能是经过ip_recv_error()来完成的。 * 在基于链接的套接字上,IP_RECVERR意义则会有所不一样。并不 * 保存错误信息到错误队列中,而是当即传递全部收到的错误信息 * 给用户进程。这对于基于短链接的TCP应用是颇有用的,由于 * TCP要求快速的错误处理。须要注意的是,TCP没有错误队列, * MSG_ERRQUEUE对于基于链接的套接字是无效的。 * 错误信息传递给用户进程时,并不将错误信息做为报文的内容传递 * 给用户进程,而是以错误信息块的形式保存在SKB控制块中, * 一般经过SKB_EXT_ERR来访问SKB控制块中的错误信息块。 * 参见sock_exterr_skb结构。 */
    struct sk_buff_head sk_error_queue; /* * 原始网络协议块指针。由于传输控制块中的另外一个网络 * 协议块指针sk_prot在IPv6的IPV6_ADDRFORM套接字选项 * 设置时被修改 */
    struct proto        *sk_prot_creator; /* * 确保传输控制块中一些成员同步访问的锁。由于有些成员在软 * 中断中被访问,存在异步访问的问题 * */ rwlock_t sk_callback_lock; /* * 记录当前传输层中发生的最后一次致命错误的错误码,但 * 应用层读取后会自动恢复为初始正常状态. * 错误码的设置是由tcp_v4_err()函数完成的。 */
    int sk_err, /* * 用于记录非致命性错误,或者用做在传输控制块被 * 锁定时记录错误的后备成员 */ sk_err_soft; /* 当前已创建的链接数 */  //表示套接口上能够排队等待链接的链接数门限值 //在三次握手成功的第三步ACK成功后,会从listen_sock里面的syn_table hash中取出,让后加入到request_sock_queue的rskq_accept_head中, //同时增长已链接成功值,当应用程序调用accept的时候,会从里面取出这个已链接信息,而后再减少改制,同时释放这个request_sock //这个是从半链接队列取出request_sock后加入到已链接队列中的request_sock个数,sk_ack_backlog是已经完成了三次握手,可是尚未被accept系统调用处理的链接请求数量;sk_max_ack_backlog就是咱们常常熟悉的listen的参数。 //创建链接的过程当中加1,在reqsk_queue_add中赋值 减1在reqsk_queue_get_child
 u32 sk_ack_backlog; //在inet_listen赋值,为listen的第三个参数向上取得的2次密reqsk_queue_alloc,这个值和半链接里面的listen_sock中的nr_table_entries相
 u32 sk_max_ack_backlog; __u32 sk_priority;//SKB->priority就是用的该字段
 __u32 sk_mark; struct pid        *sk_peer_pid; const struct cred    *sk_peer_cred;/* 返回链接至该套接字的外部进程的身份验证,目前主要用于PF_UNIX协议族*/
 /* * 套接字层接收超时,初始值为MAX_SCHEDULE_TIMEOUT。 * 能够经过套接字选项SO_RCVTIMEO来设置接收的超时时间。 sock_init_data设置为无限大,也就是accept的时候默认是无限阻塞的,见inet_csk_accept * 若是想设置为非阻塞,能够经过SO_RCVTIMEO参数设置 */
    long sk_rcvtimeo; /* * 套接字层发送超时,初始值为MAX_SCHEDULE_TIMEOUT。 * 能够经过套接字选项SO_SNDTIMEO来设置发送的超时时间。 connect的时候判断是否connect超时用的就是这个值 使用该值的地方在sock_sndtimeo */
    long sk_sndtimeo; /* * 经过TCP的不一样状态,来实现链接定时器、FIN_WAIT_2定时器(该定时器在TCP四次挥手过程当中结束,见tcp_rcv_state_process)以及 * TCP保活定时器,在tcp_keepalive_timer中实现 * 定时器处理函数为tcp_keepalive_timer(),参见tcp_v4_init_sock() * 和tcp_init_xmit_timers()。 */
    struct timer_list    sk_timer;//inet_csk_init_xmit_timers sock_init_data
     /* * 在未启用SOCK_RCVTSTAMP套接字选项时,记录报文接收数据到 * 应用层的时间戳。在启用SOCK_RCVTSTAMP套接字选项时,接收 * 数据到应用层的时间戳记录在SKB的tstamp中 */ ktime_t sk_stamp; u16 sk_tsflags; u8 sk_shutdown; u32 sk_tskey; struct socket        *sk_socket;  /* 指向对应套接字的指针 */
    void            *sk_user_data; struct page_frag sk_frag; /* * 指向sk_write_queue队列中第一个未发送的结点,若是sk_send_head * 为空则表示发送队列是空的,发送队列上的报文已所有发送。 */
        struct sk_buff      *sk_send_head; //表示sk_write_queue队列中还未调用dev_queue_xmit的最前面一个SKB的地方
        /* * 表示数据尾端在最后一页分片内的页内偏移, * 新的数据能够直接从这个位置复制到该分片中 */ //在tcp_sendmsg中开辟空间后,并复制,见里面的TCP_OFF(sk) = off + copy;
 __s32 sk_peek_off; /* 标识有数据即将写入套接口, * 也就是有写数据的请求*/
    int sk_write_pending; #ifdef CONFIG_SECURITY void            *sk_security; #endif
    struct sock_cgroup_data sk_cgrp_data; struct mem_cgroup    *sk_memcg; /* * 当传输控制块的状态发生变化时,唤醒哪些等待本套接字的进程。 * 在建立套接字时初始化,IPv4中为sock_def_wakeup() 一般当传输 状态发生变化时调用 */
    void            (*sk_state_change)(struct sock *sk); /* * 当有数据到达接收处理时,唤醒或发送信号通知准备读本套接字的 * 进程。在建立套接字时被初始化,IPv4中为sock_def_readable()。若是 * 是netlink套接字,则为netlink_data_ready()。 一般当传输控制块接收到数据包,存在可读的数据以后被调用 *///内核建立netlink sock的时候,对应的是netlink_kernel_create->netlink_data_ready
    void            (*sk_data_ready)(struct sock *sk); void            (*sk_write_space)(struct sock *sk); void            (*sk_error_report)(struct sock *sk); /* * 用于TCP和PPPoE中。在TCP中,用于接收预备队列和后备队列中的 * TCP段,TCP的sk_backlog_rcv接口为tcp_v4_do_rcv()。若是预备 * 队列中还存在TCP段,则调用tcp_prequeue_process()预处理,在 * 该函数中会回调sk_backlog_rcv()。若是后备队列中还存在TCP段, * 则调用release_sock()处理,也会回调sk_backlog_rcv()。该函数 * 指针在建立套接字的传输控制块时由传输层backlog_rcv接口初始化 */
    int            (*sk_backlog_rcv)(struct sock *sk, struct sk_buff *skb); void                    (*sk_destruct)(struct sock *sk); struct sock_reuseport __rcu    *sk_reuseport_cb; struct rcu_head sk_rcu; }; #define __sk_user_data(sk) ((*((void __rcu **)&(sk)->sk_user_data)))

#define rcu_dereference_sk_user_data(sk)    rcu_dereference(__sk_user_data((sk)))
#define rcu_assign_sk_user_data(sk, ptr)    rcu_assign_pointer(__sk_user_data((sk)), ptr)
相关文章
相关标签/搜索