basic data structure of inet socket: inetsw

protocol链表数组

inet有些例外,因为inet支持的类型太过复杂(maybe), 所以引入了一个inetsw的链表数组。
就像注释里说的一样。inetsw是inet socket创建的基础,包含创建inet socket全部的所需要信息。

inetsw

1
2
3
4
5
125 /* The inetsw table contains everything that inet_create needs to
126 * build a new socket.
127 */
128 static struct list_head inetsw[SOCK_MAX];
129 static DEFINE_SPINLOCK(inetsw_lock);

inetsw是一个链表头的数据,每个链表是具有相同的type的, 具体见socket type.
每个节点是一个struct inet_protosw. 每个节点是通过net_register_protosw
插入到其type对应的链表里的。

struct inet_protosw

1
2
3
4
5
6
7
8
9
10
11
12
13
78 /* This is used to register socket interfaces for IP protocols.  */
79 struct inet_protosw {
80 struct list_head list;
81
82 /* These two fields form the lookup key. */
83 unsigned short type; /* This is the 2nd argument to socket(2). */
84 unsigned short protocol; /* This is the L4 protocol number. */
85
86 struct proto *prot;
87 const struct proto_ops *ops;
88
89 unsigned char flags; /* See INET_PROTOSW_* below. */
90 };
两个重要的指针

每种socket都有其对应的struct proto_ops *ops,该指针会存放在struct socket里。
inet的socket在创建的时候会指定两个函数指针:

  1. struct proto_ops *ops
    该指针被存放到struct socket里.
    一般socket这些函数就是真正的bind, connect,sendmsg函数。
    但是在inet里,这些函数其实是通用的或者基于某个type(如stream)的操作。
    inet_bind, inet_sendmsg inet_stream_connect等。
  2. struct proto *prot
    该指针被存放到struct sock里.
    各个协议自己的特殊处理,被抽象并整理到这里,如tcp_v4_connect.
    struct proto_ops *ops经常使用’sk->sk_prot->XXX调用响应的proto处理函数。 如:inet_stream_connect/__inet_stream_connect 调用`sk->sk_prot->connect
一个具体的例子

如tcp协议的struct proto_ops *opsinet_stream_ops, struct proto *prottcp_prot

1
2
3
4
5
6
7
8
 997         {
998 .type = SOCK_STREAM,
999 .protocol = IPPROTO_TCP,
1000 .prot = &tcp_prot,
1001 .ops = &inet_stream_ops,
1002 .flags = INET_PROTOSW_PERMANENT |
1003 INET_PROTOSW_ICSK,
1004 },
两个指针何时被初始化的

上述两个指针在sock创建时候就被确定下来了.
函数inet_create会根据socket系统调用指定的type,proto参数,去inetsw链表里查找。
并将找到的节点里的struct proto_ops *opsstruct proto *prot分别保存到该socket对应的socketsock里。

几点说明 struct inet_protosw
  1. permanent protocol
    因为struct inet_protosw有永久(permanent)和临时之分。

所为permanent节点就是其结构体的flag带有INET_PROTOSW_PERMANENT标志位。说明其对应的协议不允许被override.
而临时节点则相反,没有INET_PROTOSW_PERMANENT标志,新插入的协议override原有的。

所有永久的节点被放在了链表的头部,而新插入的临时节点
都会被放到permanent节点的后面。

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
1030
1031 #define INETSW_ARRAY_LEN ARRAY_SIZE(inetsw_array)
1032
1033 void inet_register_protosw(struct inet_protosw *p)
1034 {
1035 struct list_head *lh;
1036 struct inet_protosw *answer;
1037 int protocol = p->protocol;
1038 struct list_head *last_perm;
1039
1040 spin_lock_bh(&inetsw_lock);
1041
1042 if (p->type >= SOCK_MAX)
1043 goto out_illegal;
1044
1045 /* If we are trying to override a permanent protocol, bail. */
1046 last_perm = &inetsw[p->type];
1047 list_for_each(lh, &inetsw[p->type]) {
1048 answer = list_entry(lh, struct inet_protosw, list);
1049 /* Check only the non-wild match. */
1050 if ((INET_PROTOSW_PERMANENT & answer->flags) == 0)
1051 break;
1052 if (protocol == answer->protocol)
1053 goto out_permanent;
1054 last_perm = lh;
1055 }
1056
1057 /* Add the new entry after the last permanent entry if any, so that
1058 * the new entry does not override a permanent entry when matched with
1059 * a wild-card protocol. But it is allowed to override any existing
1060 * non-permanent entry. This means that when we remove this entry, the
1061 * system automatically returns to the old behavior.
1062 */
1063 list_add_rcu(&p->list, last_perm);
1064 out:
1065 spin_unlock_bh(&inetsw_lock);
1066
1067 return;
1068
1069 out_permanent:
1070 pr_err("Attempt to override permanent protocol %d\n", protocol);
1071 goto out;
1072
1073 out_illegal:
1074 pr_err("Ignoring attempt to register invalid socket type %d\n",
1075 p->type);
1076 goto out;
1077 }
1078 EXPORT_SYMBOL(inet_register_protosw);
##### `enum socket_type`
1
2
3
4
5
6
7
8
9
58 enum sock_type {
59 SOCK_STREAM = 1,
60 SOCK_DGRAM = 2,
61 SOCK_RAW = 3,
62 SOCK_RDM = 4,
63 SOCK_SEQPACKET = 5,
64 SOCK_DCCP = 6,
65 SOCK_PACKET = 10,
66 };