Linux网络协议栈(一)-网络系统初始化

1.1 Overview

socket.c里面有:

core_initcall(sock_init);  /* early initcall */

因此在系统启动的时候,

do_basic_setup(main.c)---->do_initcalls(main.c)会调用sock_init

同理在af_init.c中的fs_initcall(inet_init)导致inet_init在启动的过程中也被调用,其他重要的的还有net_dev_init(dev.c)

1.2 sock_init

sock_init:没啥好说的,主要就是初始化了sk cacheskb cache

 

1.3 net_dev_init:

1.         1最重要就是启动了2softirq 

a)         open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL);

b)        open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL);

2softirq就是用来发送和接收网络数据包的,以后会详细说明。

2.         初始化2个包类型LIST

INIT_LIST_HEAD(&ptype_all);

for (i = 0; i < 16; i++)

INIT_LIST_HEAD(&ptype_base[i]);

2个包类型LIST很重要,包类型指的是第三层协议的类型,IPARP等等。这些协议会调用dev_add_pack(struct packet_type*)向数据链路层注册包类型,数据链路层在接收到包后,才可以根据包头的协议类型决定该把包传给那种第三层协议。packet_type结构中有一个函数指针func,链路层就是调用这个函数来向第三层传递数据的,以ARP为例子,dev_add_pack(&arp_packet_type);其中arp_packet_type被定义为,

static struct packet_type arp_packet_type = {

.type =    __constant_htons(ETH_P_ARP),

.func =    arp_rcv,

};

因此,当数据链路层检查出包是一个ARP包的时候,就会调用arp_rcv向上层传递该包。

实际上我们有2个包类型队列,一般情况下,都注册到ptype_base,但是如果dev_add_pack注册的包类型中typeETH_P_ALL时,包类型被注册到ptype_all,被注册到ptype_all的包类型,在每一个包被接收的时候它的func函数都会被调用。

3.         初始化包接收队列,讨论包接收的时候会谈到该队列:

for_each_possible_cpu(i) {

struct softnet_data *queue;

 

queue = &per_cpu(softnet_data, i);

skb_queue_head_init(&queue->input_pkt_queue);

queue->completion_queue = NULL;

INIT_LIST_HEAD(&queue->poll_list);

 

queue->backlog.poll = process_backlog;

queue->backlog.weight = weight_p;

}

 

1.4 inet_init

inet_init很长

1.         通过调用proto_register注册了tcp_prot,udp_prot, raw_prot

2.         通过调用sock_register注册了inet_family_ops

proto_register实际上就是把协议加到proto_list. 这些协议的定义是这样的:

struct proto udp_prot = {

.name            = "UDP",

.owner           = THIS_MODULE,

.close            = udp_lib_close,

.connect        = ip4_datagram_connect,

.disconnect    = udp_disconnect,

.ioctl              = udp_ioctl,

.destroy         = udp_destroy_sock,

.setsockopt    = udp_setsockopt,

.getsockopt    = udp_getsockopt,

.sendmsg       = udp_sendmsg,

.recvmsg       = udp_recvmsg,

.sendpage       = udp_sendpage,

.backlog_rcv         = udp_queue_rcv_skb,

.hash             = udp_lib_hash,

.unhash                 = udp_lib_unhash,

.get_port        = udp_v4_get_port,

.obj_size        = sizeof(struct udp_sock),

#ifdef CONFIG_COMPAT

.compat_setsockopt = compat_udp_setsockopt,

.compat_getsockopt = compat_udp_getsockopt,

#endif

REF_PROTO_INUSE(udp)

};

按照Linux对网络系统的架构,对于应用层来说,是统一的socket接口,而实际如何传递数据是由不同类型的sock决定的,如果按照面向对象的思想来看,sock结构就是基类,具体协议的sock结构就是子类,比如对于UDP来说就是udp_sock.我们察看UDP类型的socket操作,可以发现,创建socket的时候,会调用inet_family_ops里面的create函数inet_create,它会把UDP类型socketops指针设置为inet_dgram_ops,还有prot指针设置为udp_prot,当对socket进行操作的时候,比如当调用sock_sendmsg的时候,实际会调用到inet_dgram_ops里面的inet_sendmsg,而它会调用到udp_prot里面的udp_sendmsg.这里只是简单介绍了一下socket操作的流程,具体情况,以后再详细说明.还需要说明的是,这些函数指针不是必须的,这是AF_INET family中为了结构清晰,可扩展性好而使用的一种方式,实际上就好比加入了一新的inet.在其他family,比如AF_PACKET,你就会发现注册的协议里面是没有定义这些函数指针的.

static struct proto packet_proto = {

.name        = "PACKET",

.owner      = THIS_MODULE,

.obj_size = sizeof(struct packet_sock),

};

 

 

3.         通过调用inet_add_protocl注册了icmp_protocol,udp_protocol,tcp_protocol,igmp_protocol

inet_add_protocl实际上就是注册需要利用IP层进行传输的层4的协议,类似于dev_add_pack注册层3协议一样,注册层4协议的时候,也需要注册一个接收函数,这样IP层在决定数据传输给具体哪个层4协议的时候,就可以调用这个接收函数来把数据传递给它.比如对于udp_protocol:

static struct net_protocol udp_protocol = {

.handler =       udp_rcv,

.err_handler = udp_err,

.no_policy =   1,

};

如果IP层发现数据是一个UDP报文,就会调用udp_rcv向上传递数据.

 

4.         通过调用inet_register_protosw注册了inetsw_array

                         i.              inetsw_array就是为了AF_INET好管理而创造出来的一个结构,很简单,不详述.

5.         初始化ARP模块:arp_init

                         i.              初始化 neigbhour table

                       ii.              dev_add_pack(&arp_packet_type)向数据链路层注册一下,好接收ARP.

6.         初始化IP模块:ip_init用来初始化路由表,tcp_v4_init用来创建一个tcp control socket

7.         初始化TCP模块:tcp_init,没研究过TCP模块,以后有时间看看

8.         初始化UDP lite模块:udplite4_register,没用过这个协议

9.         初始化ICMP模块:icmp_init,创建ICMP control socket.

10.     初始化IP fragment:ipfrag_init

11.     通过调用dev_add_pack向数据链路层注册了ip_packet_type以接收IP.

      

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值