内核源码-/include/net/inet_sock.h

1. 网络序与字节序:

inet_sock.h比较值得关注的内容是inet_sock:

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
/** struct inet_sock - representation of INET sockets
*
* @sk - ancestor class
* @pinet6 - pointer to IPv6 control block
* @inet_daddr - Foreign IPv4 addr
* @inet_rcv_saddr - Bound local IPv4 addr
* @inet_dport - Destination port
* @inet_num - Local port
* @inet_saddr - Sending source
* @uc_ttl - Unicast TTL
* @inet_sport - Source port
* @inet_id - ID counter for DF pkts
* @tos - TOS
* @mc_ttl - Multicasting TTL
* @is_icsk - is this an inet_connection_sock?
* @uc_index - Unicast outgoing device index
* @mc_index - Multicast device index
* @mc_list - Group array
* @cork - info to build ip hdr on each ip frag while socket is corked
*/
struct inet_sock {
/* sk and pinet6 has to be the first two members of inet_sock */
struct sock sk;
#if IS_ENABLED(CONFIG_IPV6)
struct ipv6_pinfo *pinet6;
#endif
/* Socket demultiplex comparisons on incoming packets. */
#define inet_daddr sk.__sk_common.skc_daddr
#define inet_rcv_saddr sk.__sk_common.skc_rcv_saddr
#define inet_dport sk.__sk_common.skc_dport
#define inet_num sk.__sk_common.skc_num

__be32 inet_saddr;
__s16 uc_ttl;
__u16 cmsg_flags;
__be16 inet_sport;
__u16 inet_id;

struct ip_options_rcu __rcu *inet_opt;
int rx_dst_ifindex;
__u8 tos;
__u8 min_ttl;
__u8 mc_ttl;
__u8 pmtudisc;
__u8 recverr:1,
is_icsk:1,
freebind:1,
hdrincl:1,
mc_loop:1,
transparent:1,
mc_all:1,
nodefrag:1;
__u8 bind_address_no_port:1,
defer_connect:1; /* Indicates that fastopen_connect is set
* and cookie exists so we defer connect
* until first data frame is written
*/
__u8 rcv_tos;
__u8 convert_csum;
int uc_index;
int mc_index;
__be32 mc_addr;
struct ip_mc_socklist __rcu *mc_list;
struct inet_cork_full cork;
};

  首先我们注意到有inet_numinet_sport两个字段,并且前者表示Local Port,后者表示Source Port。那二者有何区别?这里StackOverflow上有一个相关回答:https://stackoverflow.com/questions/55313362/what-is-the-difference-between-local-port-and-source-port-in-inet-sock-h-in

其大意是:inet_numLocal port in host byte-order / protocol type,而inet_sportThe source port in network byte-order. This is the port you see in packet.

这就又涉及到一个网络字节序和主机字节序问题的讨论。这里有一篇相关博客:https://blog.csdn.net/lxj434368832/article/details/78499937

1.1 网络字节序(Network Byte Order, NBO)和主机字节序(Host Byte Order, HBO)

  Linux man page中提到,arpa/inet.h中定义了四个函数:

1
2
3
4
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
函数作用
htonluint32_t 类型的HBO地址转为NBO地址
htonsuint16_t 类型的HBO地址转为NBO地址
ntohluint32_t 类型的NBO地址转为HBO地址
ntohsuint16_t 类型的NBO地址转为HBO地址

  Linux提供了相关的转换函数,了解NBO和HBO区别之前,我们再明确一下大端/小端的基本概念。沿着内存增大的方向,如果一个数据的的开始字节(一般也叫做Least Significant Byte, LSB最低有效字节)放在低地址,而结束字节(一般也叫做Most Significant Byte, MSB最高有效字节)放在高地址,则称这种数据存放方式为小端(little-endian)字节序,反之则称为大端(big-endian)字节序。简而言之:数据的初始字节放在低地址就是小端,放在高地址就是大端。具体如下图所述:

注意:字节序只是字节的排列顺序不同,但对应的字节内部的8位二进制数顺序都是一样的~

字节序

   UDP/TCP/IP协议规定:把接收到的第一个字节当作高位字节看待。因此网络字节序统一都是大端字节序。而不同主机的字节序各有不同,为了保证网络通信时数据传输的一致性,就需要有NBO和HBO之间的相互转化。


内核源码-/include/net/inet_sock.h
https://www.torch-fan.site/2023/04/26/内核源码-include-net-inet-sock-h/
作者
Torch-Fan
发布于
2023年4月26日
更新于
2023年5月2日
许可协议