-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsock.h
executable file
·2495 lines (2246 loc) · 89.2 KB
/
sock.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
*
* Definitions for the AF_INET socket handler.
*
* Version: @(#)sock.h 1.0.4 05/13/93
*
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Corey Minyard <wf-rch!minyard@relay.EU.net>
* Florian La Roche <flla@stud.uni-sb.de>
*
* Fixes:
* Alan Cox : Volatiles in skbuff pointers. See
* skbuff comments. May be overdone,
* better to prove they can be removed
* than the reverse.
* Alan Cox : Added a zapped field for tcp to note
* a socket is reset and must stay shut up
* Alan Cox : New fields for options
* Pauline Middelink : identd support
* Alan Cox : Eliminate low level recv/recvfrom
* David S. Miller : New socket lookup architecture.
* Steve Whitehouse: Default routines for sock_ops
* Arnaldo C. Melo : removed net_pinfo, tp_pinfo and made
* protinfo be just a void pointer, as the
* protocol specific parts were moved to
* respective headers and ipv4/v6, etc now
* use private slabcaches for its socks
* Pedro Hortas : New flags field for socket options
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#ifndef _SOCK_H
#define _SOCK_H
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/list_nulls.h>
#include <linux/timer.h>
#include <linux/cache.h>
#include <linux/module.h>
#include <linux/lockdep.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h> /* struct sk_buff */
#include <linux/mm.h>
#include <linux/security.h>
#include <linux/slab.h>
#include <linux/filter.h>
#include <linux/rculist_nulls.h>
#include <linux/poll.h>
#include <asm/atomic.h>
#include <net/dst.h>
#include <net/checksum.h>
/*
* This structure really needs to be cleaned up.
* Most of it is for TCP, and not used by any of
* the other protocols.
*/
/* Define this to get the SOCK_DBG debugging facility. */
#define SOCK_DEBUGGING
#ifdef SOCK_DEBUGGING
#define SOCK_DEBUG(sk, msg...) do { if ((sk) && sock_flag((sk), SOCK_DBG)) \
printk(KERN_DEBUG msg); } while (0)
#else
/* Validate arguments and do nothing */
static inline void __attribute__ ((format (printf, 2, 3)))
SOCK_DEBUG(struct sock *sk, const char *msg, ...)
{
}
#endif
/* This is the per-socket lock. The spinlock provides a synchronization
* between user contexts and software interrupt processing, whereas the
* mini-semaphore synchronizes multiple users amongst themselves.
*/
/*
* 实现控制用户进程和下半部 (例如应用程序发送数据的时候,然后进入系统调度到内核部分,这时候,内核又收到了对方来的数据,就好产生硬件中断,硬件中断上半部执行完后,执行下半部的时候就会用到刚才被抢走的发送数据的sock,从而会访问相同的数据空间,所以需要枷锁)
以及下半部之间(例如内核硬件中断接收数据后进入软中断处理过程中,又收到了对方来的数据产生中断。)
* 间同步锁都是由socket_lock_t结构描述的
*/
typedef struct {
/*
* 用来实现下半部间的同步锁,同时也用于保护owned的写操作
*/
spinlock_t slock;
/*
* 设置owned时需要通过自旋锁slock来保护,
* 为0表示未被用户进程锁定,为1表示
* 被用户进程确定
*/
int owned;
/*
* 等待队列。当进程调用lock_sock对传输控制块进行上锁时,
* 如果此时传输控制块已被软中断锁定,则此时进程只能
* 睡眠,并将进程信息添加到此队列中,当软中断解锁
* 传输控制块时,会唤醒此队列上的进程
*/
wait_queue_head_t wq;
/*
* We express the mutex-alike socket_lock semantics
* to the lock validator by explicitly managing
* the slock as a lock variant (in addition to
* the slock itself):
*/
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
} socket_lock_t;
struct sock;
struct proto;
struct net;
/**
* struct sock_common - minimal network layer representation of sockets
* @skc_node: main hash linkage for various protocol lookup tables
* @skc_nulls_node: main hash linkage for TCP/UDP/UDP-Lite protocol
* @skc_refcnt: reference count
* @skc_tx_queue_mapping: tx queue number for this connection
* @skc_hash: hash value used with various protocol lookup tables
* @skc_u16hashes: two u16 hash values used by UDP lookup tables
* @skc_family: network address family
* @skc_state: Connection state
* @skc_reuse: %SO_REUSEADDR 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
*
* This is the minimal network layer representation of sockets, the header
* for struct sock and struct inet_timewait_sock.
*/
/*套接字中本段和对端的相关信息都放在inet_sock中,可以保证和协议无关,各种协议都用该结构存储本地地址端口和对端地址端口已经连接状态等
以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)
struct sock里面包含struct sock_common
tcp_sock->inet_connection_sock->inet_sock->sock(socket里面的sk指向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 {
/*
* first fields are not copied in sock_copy()
*/
/*
* TCP维护一个所有TCP传输控制块的散列表tcp_hashinfo,
* 而skc_node用来将所属TCP传输控制块链接到该散列表,
udp的hashinfo为udp_table
*/
union { //udp没有加入到这里面任何一个list中 本段为服务器端的时候tcp和raw在listen的时候调用inet_csk_listen_start把struct sock添加到对应协议的struct proto对应的h成员(hashinfo)中
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
};
/*
* 引用计数,当引用计数为0时才能被释放
*/
atomic_t skc_refcnt;
/*
* 存储TCP状态为established时加入到散列表的关键字键值。
* 由于计算键值相对耗时,因此用一个成员来存储键值有利
* 于提高效率
*/
unsigned int skc_hash;
/*
* 所属协议族
*/
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;
/* 如果不为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中
*/
struct hlist_node skc_bind_node;
struct hlist_nulls_node skc_portaddr_node;//通过函数 ip4_datagram_connect中的udp_v4_rehash添加把udp协议的struct sock添加到udp_table,
/* 指向网络接口层的指针,如果是TCP套接字,为tcp_prot udp_prot。raw_prot */
struct proto *skc_prot;
#ifdef CONFIG_NET_NS
struct net *skc_net;
#endif
};
struct sock_common1 {
/*
* first fields are not copied in sock_copy()
*/
union {
struct hlist_node skc_node;
struct hlist_nulls_node skc_nulls_node;
};
atomic_t skc_refcnt;
int skc_tx_queue_mapping;
union {
unsigned int skc_hash;
__u16 skc_u16hashes[2];
};
unsigned short skc_family;
volatile unsigned char skc_state;
unsigned char skc_reuse;
int skc_bound_dev_if;
union {
struct hlist_node skc_bind_node;
struct hlist_nulls_node skc_portaddr_node;
};
struct proto *skc_prot;
#ifdef CONFIG_NET_NS
struct net *skc_net;
#endif
};
/**
* 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_dst_cache: destination cache
* @sk_dst_lock: destination cache lock
* @sk_policy: flow policy
* @sk_rmem_alloc: receive queue bytes committed
* @sk_receive_queue: incoming packets
* @sk_wmem_alloc: transmit queue bytes committed
* @sk_write_queue: Packet sending queue
* @sk_async_wait_queue: DMA copied packets
* @sk_omem_alloc: "o" is "option" or "other"
* @sk_wmem_queued: persistent queue size
* @sk_forward_alloc: space allocated forward
* @sk_allocation: allocation mode
* @sk_sndbuf: size of send buffer in bytes
* @sk_flags: %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE,
* %SO_OOBINLINE settings, %SO_TIMESTAMPING settings
* @sk_no_check: %SO_NO_CHECK setting, wether or not checkup 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_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_peercred: %SO_PEERCRED setting
* @sk_rcvlowat: %SO_RCVLOWAT setting
* @sk_rcvtimeo: %SO_RCVTIMEO setting
* @sk_sndtimeo: %SO_SNDTIMEO setting
* @sk_rxhash: flow hash received from netif layer
* @sk_filter: socket filtering instructions
* @sk_protinfo: private area, net family specific, when not using slab
* @sk_timer: sock cleanup timer
* @sk_stamp: time stamp of last packet received
* @sk_socket: Identd and reporting IO signals
* @sk_user_data: RPC layer private data
* @sk_sndmsg_page: cached page for sendmsg
* @sk_sndmsg_off: cached offset for sendmsg
* @sk_send_head: front of stuff to transmit
* @sk_security: used by security modules
* @sk_mark: generic packet mark
* @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
*/
/*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)*/
//sock_common是传输控制块信息最小集合 struct sock是比较通用的网络层描述块,与具体的协议族无关,他描述个各个不同协议族传输层的公共信息
//这个struct sock最后根据不同协议分别添加到raw_hashinfo tcp_hashinfo 做客户端的时候是在connect的时候,通过sk_bind_node成员加入,做服务器端的时候通过
//sk_node或者sk_nulls_node加入到
//inet = inet_sk(sk);tp = tcp_sk(sk);
struct sock { //TCP情况下的struct sock包括两种,一种称为"父",另一种为"子",当应用层调用sock函数的时候,内核创建的是父,当三次握手成功的第三步后会创建新的struct sock,accept的时候会取走这个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_copy_start __sk_common.skc_hash
#define sk_hash __sk_common.skc_hash
#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_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 //见inet_bind_hash struct sock被添加到inet_bind_bucket结构的owners链表中(inet_bind_hash),然后该inet_bind_bucket通过node节点加入到tcp_hashinfo中
/* 指向网络接口层的指针,如果是TCP套接字,为tcp_prot
* 如果是UDP套接字为udp_prot。raw_prot
* */
#define sk_prot __sk_common.skc_prot
#define sk_net __sk_common.skc_net
kmemcheck_bitfield_begin(flags);
/*
* 关闭套接口的标志,下列值之一:
* RCV_SHUTDOWN: 接收通道关闭,不允许继续接收数据 在接收到FIN并发送ACK的时候,接不能再接收数据了(一种是主动关闭端的第三步FIN和第四步ACK,另一种是被动接收到第一步FIN并发送ACK)。
* SEND_SHUTDOWN: 发送通道关闭,不允许继续发送数据 在发送FIN并接收到ACK的时候,就不能再发送数据了。(一种是主动关闭的一段发送第一步FIN并受到ACK,另一种是被动端发送第三步FIN并受到ACK)
* SHUTDOWN_MASK: 表示完全关闭
*/ //如果设置了RCV_SHUTDOWN,则不允许接收数据 如果设置了SEND_SHUTDOWN则不允许接收数据
//实际起作用的地方是决定是否能接收发送数据
unsigned int sk_shutdown : 2, //在四次挥手过程中可能会用到
/*
* 标识是否对RAW和UDP进行校验和,下列值之一:
* UDP_CSUM_NOXMIT: 不执行校验和
* UDP_CSUM_NORCV: 只用于SunRPC
* UDP_CSUM_DEFAULT: 默认执行校验和
*/
sk_no_check : 2, //在setsockops中设置为SO_NO_CHECK的时候生效
/*
* 标识传输层的一些状态,下列值之一:
* SOCK_SNDBUF_LOCK: 用户通过套接口选项设置了发送缓冲区大小
* SOCK_RCVBUF_LOCK: 用户通过套接口选项设置了接收缓冲区大小
* SOCK_BINDADDR_LOCK: 已经绑定了本地地址
* SOCK_BINDPORT_LOCK: 已经绑定了本地端口
*/
sk_userlocks : 4,
/*
* 当前域中套接字所属的协议 IPPROTO_TCP等
*/
sk_protocol : 8,
/*
* 所属的套接字类型,如SOCK_STREAM
*/
sk_type : 16;
kmemcheck_bitfield_end(flags);
/* 接收缓冲区大小的上限,默认值是sysctl_rmem_default(sock_init_data),即32767, 也就是IP首部16位长度(最大65535)的一半*/
//当sock接收到一个包的时候,会在sock_queue_rcv_skb中判断当前队列中已有的skb占用的buffer和这个新来的buff之后是否超过了sk_rcvbuf
int sk_rcvbuf; //sk_rcvqueues_full函数对接收的包会做一下检查 setsockops中设置 。并能通过tcp_rmem调整。
/*
* 同步锁,其中包括了两种锁:一是用于用户进程读取数据
* 和网络层向传输层传递数据之间的同步锁;二是控制Linux
* 下半部访问本传输控制块的同步锁,以免多个下半部同
* 时访问本传输控制块
*/
socket_lock_t sk_lock;//被lock_sock使用
/*
* 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.
*/
/*
* 后备接收队列,目前只用于TCP.传输控制块被上锁后(如应用层
* 读取数据时),当有新的报文传递到传输控制块时,只能把报文
* 放到后备接受队列中,之后有用户进程读取TCP数据时,再从
* 该队列中取出复制到用户空间中.
* 一旦用户进程解锁传输控制块,就会立即处理
* 后备队列,将TCP段处理之后添加到接收队列中。
*/
struct {
struct sk_buff *head;
struct sk_buff *tail;
} sk_backlog;
/*
* 进程等待队列。进程等待连接、等待输出缓冲区、等待
* 读数据时,都会将进程暂存到此队列中。这个成员最初
* 是在sk_clone()中初始化为NULL,该成员实际存储的socket结构
* 中的wait成员,这个操作在sock_init_data()中完成。 有的版本这里直接是wait, 唤醒该队列上的进程函数是sock_def_wakeup
*/
wait_queue_head_t *sk_sleep;
/*
* 目的路由项缓存,一般都是在创建传输控制块发送
* 数据报文时,发现未设置该字段才从路由表或路由
* 缓存中查询到相应的路由项来设置新字段,这样可以
* 加速数据的输出,后续数据的输出不必再查询目的
* 路由。某些情况下会刷新此目的路由缓存,比如断开
* 连接、重新进行了连接、TCP重传、重新绑定端口
* 等操作
*/
struct dst_entry *sk_dst_cache;
#ifdef CONFIG_XFRM
/* 与IPSee相关的传输策略 */
struct xfrm_policy *sk_policy[2];
#endif
/* 操作目的路由缓存的读写锁 */
rwlock_t sk_dst_lock;
/* 接收队列sk_receive_queue中所有报文数据的总长度 .该成员在skb_set_owner_r()函数中会更新*/ //实际在接收SKB开辟空间的时候,会把该值和sk_rcvbuf大小做比较
////这个只针对接收数据,发送数据对应的是sk_rmem_alloc,
//阅读函数__sk_mem_schedule可以了解proto的内存情况判断方法
atomic_t sk_rmem_alloc; //表示接收队列中所有skb的总长度,在sock_queue_rcv_skb函数的skb_set_owner_r中增加
/* 所在传输控制块中,为发送而分配的所有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, //阅读函数__sk_mem_schedule可以了解proto的内存情况判断方法
/*
* 分配辅助缓冲区的上限,辅助数据包括进行设置选项、
* 设置过滤时分配到的内存和组播设置等
*/
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; //setsockops中设置 这个是本sock发送缓存的最大值,整个tcp_prot或者udp_prot的内存情况比较,参考proto相关字段
/*
* 接收队列,等待用户进程读取。TCP比较特别,
* 当接收到的数据不能直接复制到用户空间时才会
* 缓存在此
*/
struct sk_buff_head sk_receive_queue;
/*
* 发送队列,在TCP中,此队列同时也是重传队列,
* 在sk_send_head之前为重传队列,之后为发送
* 队列,参见sk_send_head
*/ //这上面存的是发送SKB链表,即使调用了dev_queue_xmit后,该SKB海在该链表上面,知道收到对方ack。
//图形化理解参考樊东东下P866
struct sk_buff_head sk_write_queue;
#ifdef CONFIG_NET_DMA
/* 与网络设备的DMA相关 */
struct sk_buff_head sk_async_wait_queue;
#endif
/* 发送队列中所有报文数据的总长度,目前只用于TCP 。这里
* 统计的是发送队列中所有报文的长度,不包括因为发送而克隆
* 出来的SKB占用的内存。是真正的占用空间的发送队列数据长度。见skb_entail
* */
int sk_wmem_queued; //skb_entail中会赋值
/*
* 预分配缓存长度,这只是一个标识,目前 只用于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后,做加法,这时表示可用空间有多了
/*
* 内存分配方式,参见include\linux\gfp.h。值为__GFP_DMA等
*/
gfp_t sk_allocation;
/*
* 目的路由网络设备的特性,在sk_setup_caps()中根据
* net_device结构的features成员设置
*/ //参考//如果网口设备dev设置了dev->features |= NETIF_F_TSO,则支持TSO 参考e1000网卡的这里enic_ethtool_ops
int sk_route_caps;
/*
* 传输层支持的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;
/*
* 标识接收缓存下限值
*/
int sk_rcvlowat;
/*
* 标志位,可能的取值参见枚举类型sock_flags.
* 判断某个标志是否设置调用sock_flag函数来
* 判断,而不是直接使用位操作。
*/
unsigned long sk_flags; //////sk_flags取值为sock_flags, 状态装换图为前面的sk_state,取值为TCP_SYN_RECV等
/* 关闭套接字前发送剩余数据的时间*/
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;
atomic_t sk_drops;
/* 当前已建立的连接数 */ //表示套接口上可以排队等待连接的连接数门限值
//在三次握手成功的第三步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的参数。
unsigned short sk_ack_backlog; //建立连接的过程中加1,在reqsk_queue_add中赋值 减1在reqsk_queue_get_child
/* 连接队列长度的上限 ,其值是用户指定的连接
* 队列长度与/proc/sys/net/core/somaxconn(默认值是128)之间的较小值。表示该sock上面最多可以由多少个连接,见tcp_v4_conn_request中的sk_acceptq_is_full
* 用这个变量的sk应该是accept前的那个sk
*/
unsigned short sk_max_ack_backlog;//在inet_listen赋值,为listen的第三个参数向上取得的2次密reqsk_queue_alloc,这个值和半连接里面的listen_sock中的nr_table_entries相同
/* 用于设置由此套接字输出数据包的QoS类别 */
__u32 sk_priority; //SKB->priority就是用的该字段
/* 返回连接至该套接字的外部进程的身份验证,目前主要用于PF_UNIX协议族*/
struct ucred sk_peercred;
/*
* 套接字层接收超时,初始值为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;
/*
* 套接字过滤器。在传输层对输入的数据包通过BPF过滤代码进行过滤,
* 只对设置了套接字过滤器的进程有效。
*/
struct sk_filter *sk_filter;
/*
* 传输控制块存放私有数据的指针
*/
void *sk_protinfo;
/*
* 通过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;
/* 指向对应套接字的指针 */
struct socket *sk_socket;
/* RPC层存放私有数据的指针 ,IPv4中未使用 */
void *sk_user_data;
/*
* 指向为本传输控制块最近一次分配的页面,通常
* 是当前套接字发送队列中最后一个SKB的分片数据的
* 最后一页,但在某种特殊的状态下也有可能不是(
* 比如,在tcp_sendmsg中成功分配了页面,但复制数据失败了)。
* 同时还用于区分系统的页面和主动分配的页面,如果是系统
* 的页面,是不能在页面中做修改的,而如果是在发送过程
* 中主动分配的页面,则可以对页面中的数据进行修改或添加,
* 参见tcp_sendmsg.
*
* sk_sndmsg_page和sk_sndmsg_off主要起缓存的作用,可以直接找到
* 最后一个页面,然后尝试把数据追加到该页中,如果不行,则分配
* 新页面,然后向新页复制数据,并更新sk_sndmsg_page和sk_sndmsg_off
* 的值
*/////在tcp_sendmsg中开辟空间后,并复制,见里面的TCP_PAGE(sk) = page
struct page *sk_sndmsg_page;
/*
* 指向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;
__u32 sk_sndmsg_off;
/* 标识有数据即将写入套接口,
* 也就是有写数据的请求*/
int sk_write_pending;
#ifdef CONFIG_SECURITY
/* 指向sk_security_struct结构,安全模块使用*/
void *sk_security;
#endif
__u32 sk_mark;
/* XXX 4 bytes hole on 64 bit */
/*
* 当传输控制块的状态发生变化时,唤醒哪些等待本套接字的进程。
* 在创建套接字时初始化,IPv4中为sock_def_wakeup() 通常当传输 状态发生变化时调用
*/
void (*sk_state_change)(struct sock *sk);
/*
* 当有数据到达接收处理时,唤醒或发送信号通知准备读本套接字的
* 进程。在创建套接字时被初始化,IPv4中为sock_def_readable()。如果
* 是netlink套接字,则为netlink_data_ready()。 通常当传输控制块接收到数据包,存在可读的数据之后被调用
*/
void (*sk_data_ready)(struct sock *sk, int bytes); //内核创建netlink sock的时候,对应的是netlink_kernel_create->netlink_data_ready
/*
* 在发送缓存大小发生变化或套接字被释放时,唤醒因等待本套接字而
* 处于睡眠状态的进程,包括sk_sleep队列以及fasync_list队列上的
* 进程。创建套接字时初始化,IPv4中默认为sock_def_write_space(),
* TCP中为sk_stream_write_space(). 进程处于休眠状态的地方在sock_alloc_send_pskb里面的sock_wait_for_wmem
*/
void (*sk_write_space)(struct sock *sk); //该函数在释放SKB的时候执行,见sock_wfree sock_rfree
/*
* 报告错误的回调函数,如果等待该传输控制块的进程正在睡眠,
* 则将其唤醒(例如MSG_ERRQUEUE).在创建套接字时被初始化,
* IPv4中为sock_def_error_report(). 通常当传输控制块发生错误时被调用
*/
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);
/*
* 进行传输控制块的销毁,在释放传输控制块前释放一些其他资源,在
* sk_free()释放传输控制块时调用。当传输控制块的引用计数器为0时,
* 才真正释放。IPv4中为inet_sock_destruct().
*/
void (*sk_destruct)(struct sock *sk);
};
//*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)
tcp_sock->inet_connection_sock->inet_sock->sock(socket里面的sk指向sock)*/
struct sock1 {
/*
* 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
#define sk_nulls_node __sk_common.skc_nulls_node
#define sk_refcnt __sk_common.skc_refcnt
#define sk_tx_queue_mapping __sk_common.skc_tx_queue_mapping
#define sk_copy_start __sk_common.skc_hash
#define sk_hash __sk_common.skc_hash
#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_bind_node __sk_common.skc_bind_node
#define sk_prot __sk_common.skc_prot//tcp_prot、udp_prot或者netlink_proto等 inet_create中赋值
#define sk_net __sk_common.skc_net
kmemcheck_bitfield_begin(flags);
unsigned int sk_shutdown : 2,
sk_no_check : 2,
sk_userlocks : 4,
sk_protocol : 8,//也就是应用层sock函数的第三个参数,表示协议类型,如果为netlink,也就是最大为32
sk_type : 16;
kmemcheck_bitfield_end(flags);
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;
int len;
} sk_backlog;
struct socket_wq *sk_wq;
struct dst_entry *sk_dst_cache;
#ifdef CONFIG_XFRM
struct xfrm_policy *sk_policy[2];
#endif
spinlock_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;//应用层send的时候,会在内核开辟SKB空间,然后添加到该链表中
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_route_nocaps;
int sk_gso_type;
unsigned int sk_gso_max_size;
int sk_rcvlowat;
#ifdef CONFIG_RPS
__u32 sk_rxhash;
#endif
unsigned long sk_flags;
unsigned long sk_lingertime;
struct sk_buff_head sk_error_queue; //icmp差错信息会添加到该链表中 参考樊东东P229 P230
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;
u32 sk_classid;
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);
};
/*
* Hashed lists helper routines
*/
static inline struct sock *sk_entry(const struct hlist_node *node)
{
return hlist_entry(node, struct sock, sk_node);
}
static inline struct sock *__sk_head(const struct hlist_head *head)
{
return hlist_entry(head->first, struct sock, sk_node);
}
static inline struct sock *sk_head(const struct hlist_head *head)
{
return hlist_empty(head) ? NULL : __sk_head(head);
}
static inline struct sock *__sk_nulls_head(const struct hlist_nulls_head *head)
{
return hlist_nulls_entry(head->first, struct sock, sk_nulls_node);
}
static inline struct sock *sk_nulls_head(const struct hlist_nulls_head *head)
{
return hlist_nulls_empty(head) ? NULL : __sk_nulls_head(head);
}
static inline struct sock *sk_next(const struct sock *sk)
{
return sk->sk_node.next ?
hlist_entry(sk->sk_node.next, struct sock, sk_node) : NULL;
}
static inline struct sock *sk_nulls_next(const struct sock *sk)
{
return (!is_a_nulls(sk->sk_nulls_node.next)) ?
hlist_nulls_entry(sk->sk_nulls_node.next,
struct sock, sk_nulls_node) :
NULL;
}
static inline int sk_unhashed(const struct sock *sk)
{
return hlist_unhashed(&sk->sk_node);
}
static inline int sk_hashed(const struct sock *sk)
{
return !sk_unhashed(sk);
}
static __inline__ void sk_node_init(struct hlist_node *node)
{
node->pprev = NULL;
}
static __inline__ void sk_nulls_node_init(struct hlist_nulls_node *node)
{
node->pprev = NULL;
}
static __inline__ void __sk_del_node(struct sock *sk)
{
__hlist_del(&sk->sk_node);
}
/* NB: equivalent to hlist_del_init_rcu */
static __inline__ int __sk_del_node_init(struct sock *sk)
{
if (sk_hashed(sk)) {
__sk_del_node(sk);
sk_node_init(&sk->sk_node);
return 1;
}
return 0;
}
/* Grab socket reference count. This operation is valid only
when sk is ALREADY grabbed f.e. it is found in hash table
or a list and the lookup is made under lock preventing hash table
modifications.
*/
static inline void sock_hold(struct sock *sk)
{
atomic_inc(&sk->sk_refcnt);
}
/* Ungrab socket in the context, which assumes that socket refcnt
cannot hit zero, f.e. it is true in context of any socketcall.
*/
static inline void __sock_put(struct sock *sk)
{
atomic_dec(&sk->sk_refcnt);
}
static __inline__ int sk_del_node_init(struct sock *sk)
{
int rc = __sk_del_node_init(sk);
if (rc) {
/* paranoid for a while -acme */
WARN_ON(atomic_read(&sk->sk_refcnt) == 1);
__sock_put(sk);
}
return rc;
}
#define sk_del_node_init_rcu(sk) sk_del_node_init(sk)
static __inline__ int __sk_nulls_del_node_init_rcu(struct sock *sk)
{
if (sk_hashed(sk)) {
hlist_nulls_del_init_rcu(&sk->sk_nulls_node);
return 1;
}
return 0;
}
static __inline__ int sk_nulls_del_node_init_rcu(struct sock *sk)
{
int rc = __sk_nulls_del_node_init_rcu(sk);
if (rc) {
/* paranoid for a while -acme */
WARN_ON(atomic_read(&sk->sk_refcnt) == 1);
__sock_put(sk);
}
return rc;
}
static __inline__ void __sk_add_node(struct sock *sk, struct hlist_head *list)
{
hlist_add_head(&sk->sk_node, list);
}
static __inline__ void sk_add_node(struct sock *sk, struct hlist_head *list)
{
sock_hold(sk);
__sk_add_node(sk, list);
}
static __inline__ void sk_add_node_rcu(struct sock *sk, struct hlist_head *list)
{
sock_hold(sk);
hlist_add_head_rcu(&sk->sk_node, list);
}
static __inline__ void __sk_nulls_add_node_rcu(struct sock *sk, struct hlist_nulls_head *list)