2.3 Linux网络接口

1、网络系统调用

1.1、socket()

1.1.1、sys_socket()

1

1.1.2、socket fs

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.1.3、sock_create()

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
11
这里写图片描述
这里写图片描述
这里写图片描述

1.1.3.1、net_families的注册

这里写图片描述
这里写图片描述

1.1.3.2、net_proto_family->create()(AF_UNIX域的实现)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
21
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.1.3.3、net_proto_family->create()(AF_INET域的实现)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
31
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.1.3.4、net_proto_family->create()(AF_NETLINK域的实现)

这里写图片描述
这里写图片描述
这里写图片描述
41
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.1.3.5、net_proto_family->create()(AF_PACKET域的实现)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.1.4、sock_map_fd()

这里写图片描述
51
这里写图片描述

1.2、bind()

1.2.1、sys_ bind()

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.2.2、socket->ops->bind()(AF_UNIX域,SOCK_STREAM Type的实现)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
61
这里写图片描述

1.2.3、socket->ops->bind()(AF_UNIX域,SOCK_DGAM Type的实现)

这里写图片描述

1.2.4、socket->ops->bind()(AF_INET域,SOCK_STREAM Type,default protocol的实现)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.2.5、socket->ops->bind()(AF_INET域,SOCK_DGRAM Type,default protocol的实现)

这里写图片描述
这里写图片描述

1.2.6、socket->ops->bind()(AF_INET域,SOCK_RAW Type,default protocol的实现)

71
这里写图片描述

1.2.7、socket->ops->bind()(AF_NETLINK域的实现)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.2.8、socket->ops->bind()(AF_PACKET域,SOCK_DGRAM/SOCK_RAW Type的实现)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.2.9、socket->ops->bind()(AF_PACKET域,SOCK_PACKET Type的实现)

81
这里写图片描述

1.3、sendto()

1.3.1、sys_ sendto()

这里写图片描述
这里写图片描述
这里写图片描述

1.3.2、socket->ops->sendmsg()(AF_UNIX域,SOCK_STREAM Type的实现)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
91
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.3.3、socket->ops-> sendmsg()(AF_UNIX域,SOCK_DGAM Type的实现)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
101
这里写图片描述
这里写图片描述
这里写图片描述

1.3.4、socket->ops-> sendmsg()(AF_INET域,SOCK_STREAM Type,default protocol的实现)

这里写图片描述
这里写图片描述

1.3.4.1、sock->sk_prot-> sendmsg()(AF_INET域,SOCK_STREAM Type,default protocol的实现)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
111
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.3.4.2、tcp_write_xmit()

这里写图片描述
121
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.3.4.3、tcp_transmit_skb()

这里写图片描述
131
这里写图片描述
这里写图片描述

1.3.4.4、icsk->icsk_af_ops->queue_xmit()

tcp sock的icsk->icsk_af_ops指针在proto->init函数被调用时赋值。

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

可以看到tcp链接的icsk->icsk_af_ops->queue_xmit函数为ip_queue_xmit。

这里写图片描述
这里写图片描述
这里写图片描述

关于ip层往下的路由查找部分,代码实在是有点复杂,真的是有点看不清楚了。这里就略过不再详细分析了。

路由查找的基本原理就是根据ip数据包的目的ip地址,在系统的路由表中找到对应的发送网口net_device。在找到对应网口以后,在查找arp表项,找到目的ip对应的mac地址,再给数据包加上以太网链路层包头:源/目的mac地址和包类型。如果arp表中没有找到表项,还需要发送arp请求报文,进行arp解析。

进过上述的一番查找以后,skb中的各层次包头已经加上,发送的网络接口也已经确认。最终的skb->dst->output(skb)函数会调用dev_queue_xmit()。

1.3.4.5、dev_queue_xmit()

141
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.3.4.6、net_device->qdisc

从dev_queue_xmit ()中我们可以看到,如果网口驱动有队列的话会先吧skb数据包存放到队列,再出队列发送。

队列就存放在net_device-> qdisc,队列的作用是驱动对包实现排序和排优先级的功能。我们具体看看网口的队列是怎么实现的。

在注册网口驱动register_netdevice()->dev_init_scheduler(),会给网口队列一个初始空值。

这里写图片描述
这里写图片描述
151

而在ifconfig eth0 up启动网卡时,会给队列重新赋值。ioctl()->sock_ioctl()->dev_ioctl()->SIOCSIFFLAGS-> dev_ifsioc()->dev_change_flags()->IFF_UP->dev_open()->dev_activate():

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.3.5、socket->ops->sendmsg()(AF_INET域,SOCK_DGRAM Type,default protocol的实现)

这里写图片描述
这里写图片描述

1.3.5.1、sock->sk_prot->sendmsg()(AF_INET域,SOCK_DGRAM Type,default protocol的实现)

这里写图片描述
这里写图片描述
这里写图片描述
161
这里写图片描述
这里写图片描述
这里写图片描述

1.3.5.2、udp_push_pending_frames()

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

往下的分析是网卡驱动的发送数据过程,请参考tcp发送中的dev_queue_xmit ()一节。

1.3.6、socket->ops->sendmsg()(AF_INET域,SOCK_RAW Type,default protocol的实现)

这里写图片描述
171

1.3.6.1、sock->sk_prot->sendmsg((AF_INET域,SOCK_RAW Type,default protocol的实现)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.3.7、socket->ops->sendmsg()(AF_NETLINK域的实现)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
181
这里写图片描述
这里写图片描述

在注册netlink驱动时,会把驱动注册成一个内核pid=0的netlink sock。

这里写图片描述
这里写图片描述
这里写图片描述

用户态的netlink sokcet向内核netlink驱动收发数据,其实是两个netlink sock之间的数据通讯:一个是用户态的netlink sock它的pid是bind()函数指定的,一个是内核态通过netlink_kernel_create创建的pid=0的netlink sock。

1.3.7.2、netlink驱动的发送

用户态netlink sock需要发送数据给内核态netlink驱动,只需要将目的pid=0,即可通过sendmsg()函数发送数据到netlink驱动sock的接收函数。

这里写图片描述

1.3.7.3、netlink驱动的接收

netlink驱动在接受数据时,需要发送数据给用户态的netlink驱动。直接调用netlink_unicast发送给用户态sock,相当于netlink sock(pid=0,内核驱动sock)发送数据给netlink sock(pid=xxx,用户态sock)。

这里写图片描述

1.3.8、socket->ops->sendmsg()(AF_PACKET域,SOCK_DGRAM/SOCK_RAW Type的实现)

这里写图片描述
这里写图片描述
191
这里写图片描述

1.3.9、socket->ops->sendmsg()(AF_PACKET域,SOCK_PACKET Type的实现)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.4、write()

1.4.1、sys_write()

这里写图片描述
这里写图片描述
这里写图片描述

1.4.2、file->f_op->aio_write()(sock文件的实现)

在创建socket时,sock_map_fd()函数会给sock的file->f_op赋值为socket_file_ops。

这里写图片描述
201
这里写图片描述

__sock_sendmsg()函数以后的分析,请参考sendto一节。

1.5、send ()

1.5.1、sys_send()

这里写图片描述

Sys_send实际上就是调用sys_sendto实现的,请参考sys_sendto函数的分析。

1.6、sendmsg()

1.6.1、sys_sendmsg()

这里写图片描述
这里写图片描述
这里写图片描述

Sock_sendmsg函数的分析,请参考sendto()一节。

1.7、recvfrom()

1.7.1、sys_ recvfrom()

这里写图片描述
这里写图片描述
这里写图片描述

1.7.2、socket->ops->recvmsg()(AF_UNIX域,SOCK_STREAM Type的实现)

这里写图片描述
211
这里写图片描述
这里写图片描述
这里写图片描述

1.7.2.1、接收数据来源

AF_UNIX域的socket是用作进程间通讯的,recv数据的来至于对端socket的发送。在AF_UNIX域socket的发送函数sendto实现里面可以看到,发送sock根据目的地址找到目的sock,再把skb直接放入接收sock的接收队列sock->sk_receive_queue。

1.7.3、socket->ops->recvmsg()(AF_UNIX域,SOCK_DGAM Type的实现)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.7.3.1、接收数据来源

AF_UNIX域的socket是用作进程间通讯的,recv数据的来至于对端socket的发送。在AF_UNIX域socket的发送函数sendto实现里面可以看到,发送sock根据目的地址找到目的sock,再把skb直接放入接收sock的接收队列sock->sk_receive_queue。

1.7.4、socket->ops->recvmsg()(AF_INET域,SOCK_STREAM Type,default protocol的实现)

这里写图片描述
221

1.7.4.1、sock->sk_prot->recvmsg()(AF_INET域,SOCK_STREAM Type,default protocol的实现)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.7.4.2、接收数据来源

AF_INET域的socket接收数据来源于网卡驱动的接收数据,网卡驱动通过netif_receive_skb()函数提交原始数据给系统以后,系统的网络处理会根据数据包的ip地址、协议类型、端口找到对应的接收socket,并剥去下层的包头将实际数据送给socket的接收队列。

1.7.5、socket->ops->recvmsg()(AF_INET域,SOCK_DGRAM Type,default protocol的实现)

231
这里写图片描述

1.7.5.1、sock->sk_prot->recvmsg()(AF_INET域,SOCK_DGRAM Type,default protocol的实现)

这里写图片描述
这里写图片描述
这里写图片描述

1.7.5.2、接收数据来源

AF_INET域的socket接收数据来源于网卡驱动的接收数据,网卡驱动通过netif_receive_skb()函数提交原始数据给系统以后,系统的网络处理会根据数据包的ip地址、协议类型、端口找到对应的接收socket,并剥去下层的包头将实际数据送给socket的接收队列。

Udp socket和tcp socket的区别是,udp不用组包一次只会传送一个数据包,而tcp会组包而且一次返回用户期望的数据长度。

1.7.6、socket->ops->recvmsg()(AF_INET域,SOCK_RAW Type,default protocol的实现)

这里写图片描述
这里写图片描述

1.7.6.1、sock->sk_prot- recvmsg((AF_INET域,SOCK_RAW Type,default protocol的实现)

这里写图片描述
这里写图片描述
这里写图片描述

1.7.6.2、接收数据来源

AF_INET域的socket接收数据来源于网卡驱动的接收数据,网卡驱动通过netif_receive_skb()函数提交原始数据给系统以后,系统的网络处理会根据数据包的ip地址、协议类型、端口找到对应的接收socket,并剥去下层的包头将实际数据送给socket的接收队列。
Raw socket的区别是,raw收到的是ip层之上的数据,所谓的tcp、udp的头需要自己解析和组装,也是无连接的类似于udp。

1.7.7、socket->ops->recvmsg()(AF_NETLINK域的实现)

这里写图片描述
这里写图片描述
241

1.7.7.1、接收数据来源

AF_NETLINK域的socket接收数据来源其他netlink socket的发送,netlink socket数据在发送时会根据目的地址中的pid,查找到对端的netlink socket,直接把发送数据挂接到对端socket的接收队列。

1.7.8、socket->ops->recvmsg()(AF_PACKET域,SOCK_DGRAM/SOCK_RAW Type的实现)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.7.9、socket->ops->recvmsg()(AF_PACKET域,SOCK_PACKET Type的实现)

这里写图片描述

1.8、read()

1.8.1、sys_ read()

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.8.2、file->f_op->aio_read()(sock文件的实现)

在创建socket时,sock_map_fd()函数会给sock的file->f_op赋值为socket_file_ops。

251
这里写图片描述
这里写图片描述
这里写图片描述

最终和recvfrom函数一样调到了sock->ops->recvmsg函数,再往下具体的分析可以参考recvfrom函数。

1.9、recv()

1.9.1、sys_ recv()

这里写图片描述

1.10、recvmsg()

1.10.1、sys_ recvmsg()

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

最终和recvfrom函数一样调到了sock->ops->recvmsg函数,再往下具体的分析可以参考recvfrom函数。

1.11、ioctl()

ioctl关注的是对网口的操作。而getsockopt和setsockopt关注对某个协议域的各个层次参数的配置。

1.11.1、sys_ioctl()

261
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.11.2、file->f_op->unlocked_ioctl()(sock文件的实现)

这里写图片描述
这里写图片描述
这里写图片描述

1.11.3、socket->ops->ioctl()(AF_UNIX域的实现)

这里写图片描述
这里写图片描述
271

1.11.4、socket->ops->ioctl()(AF_INET域的实现)

这里写图片描述
这里写图片描述

1.11.4.1、sock->sk_prot->ioctl()(AF_INET域,SOCK_STREAM Type,default protocol的实现)

这里写图片描述
这里写图片描述

1.11.4.2、sock->sk_prot->ioctl()(AF_INET域,SOCK_DGRAM Type,default protocol的实现)

这里写图片描述
这里写图片描述

1.11.4.3、sock->sk_prot->ioctl((AF_INET域,SOCK_RAW Type,default protocol的实现)

这里写图片描述
这里写图片描述

1.11.5、socket->ops->ioctl()(AF_NETLINK域的实现)

这里写图片描述
这里写图片描述

1.11.6、dev_ioctl()

这里写图片描述
这里写图片描述
281
这里写图片描述
这里写图片描述

1.11.6.1、dev_ethtool()

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.11.6.2、dev_ifsioc()

这里写图片描述
291
这里写图片描述
这里写图片描述

1.11.6.3、ifconfig ethxxx up

“ifconfig ethxxx up”up端口命令的实现是这样的:

这里写图片描述
这里写图片描述

可以看到是调用“SIOSIFFLAGS”ioctl命令重新配置网口的flag,“SIOSIFFLAGS”命令的解析就再dev_ifsioc()函数中,我们看到是调用了dev_change_flags()。

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.11.6.4、ifconfig ethxxx down

“ifconfig ethxxx down”up端口命令的实现是这样的:

这里写图片描述
301

由up端口的实现分析可以知道,down端口调用过程是dev_ifsioc()->dev_change_flags()->dev_close()

这里写图片描述
这里写图片描述

1.11.7、阻塞/非阻塞模式设置

这里写图片描述

以recv数据包为例,说明阻塞和非阻塞的实现。

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

1.12、setsockopt()

ioctl关注的是对网口的操作。而getsockopt和setsockopt关注对某个协议域的各个层次参数的配置。

1.12.1、sys_setsockopt()

这里写图片描述

1.12.2、socket->ops->setsockopt()(AF_UNIX域的实现)

这里写图片描述
这里写图片描述

1.12.3、socket->ops->setsockopt()(AF_INET域的实现)

311
这里写图片描述

1.12.3.1、sock->sk_prot->setsockopt()(AF_INET域,SOCK_STREAM Type,default protocol的实现)

这里写图片描述
这里写图片描述
这里写图片描述

1.12.3.2、sock->sk_prot->setsockopt()(AF_INET域,SOCK_DGRAM Type,default protocol的实现)

这里写图片描述
这里写图片描述

1.12.3.3、sock->sk_prot->setsockopt((AF_INET域,SOCK_RAW Type,default protocol的实现)

这里写图片描述
这里写图片描述

1.12.3.4、ip_setsockopt((AF_INET域,IP层命令和用户自定义命令的实现)

这里写图片描述
这里写图片描述

1.12.4、socket->ops-> setsockopt()(AF_NETLINK域的实现)

321
这里写图片描述
这里写图片描述

1.12.5、nf_register_sockopt()

nf_register_sockopt函数用来注册某个域自定义的setopt和getopt的函数操作集。

这里写图片描述

1.12.6、nf_setsockopt()

nf_setsockopt()函数调用nf_register_sockopt注册的自定义的setopt函数操作集

这里写图片描述
这里写图片描述
这里写图片描述

1.12.7、nf_getsockopt()

这里写图片描述

1.13、getsockopt()

ioctl关注的是对网口的操作。而getsockopt和setsockopt关注对某个协议域的各个层次参数的配置。

1.13.1、sys_ getsockopt()

这里写图片描述

Getsockopt函数和setsockopt函数完全类似,这里就不再具体分析了。

2、网络驱动

2.1、驱动函数

2.1.1、网口结构体分配函数alloc_netdev()

这里写图片描述
331

Ldd3实例驱动注册的setup函数snull_init():

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

2.1.2、网口驱动注册函数register_netdev()

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
341
这里写图片描述

2.1.3、网口数据发送函数net_device->hard_start_xmit()

以ldd3的实例代码为例。

这里写图片描述

2.1.4、网口数据接收函数netif_rx ()(中断方式)

以ldd3的实例代码为例。

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

“NET_RX_SOFTIRQ”在初始化net_dev_init()中注册为net_rx_action。

这里写图片描述
这里写图片描述
这里写图片描述
351

继续看看中断模式dev->poll函数process_backlog()的实现。

这里写图片描述
这里写图片描述

netif_receive_skb()就会进一步根据数据包的内容(协议、地址、端口)对数据包进行处理,后面的处理比较复杂,就不再进一步分析。

2.1.5、网口数据接收函数net_device–>poll ()(NAPI轮询方式)

以ldd3的实例代码为例。NAPI方式在有数据包来到时,并不会像中断方式那样讲数据拷贝进skb再启动netif_rx,而是直接使用本身的网口设备调用netif_rx_schedule(),启动“NET_RX_SOFTIRQ”软中断。

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

NAPI轮询模式dev->poll函数调用的是网络驱动注册的net_device->poll函数。

这里写图片描述

2.1.6、网口启动函数net_device–>open()

以ldd3的实例代码为例。核心是调用netif_start_queue()函数。

361

2.1.7、网口停工函数net_device–>stop()

以ldd3的实例代码为例。核心是调用netif_stop_queue()函数。

这里写图片描述

2.1.8、网口ioctl函数net_device->do_ioctl()

2.1.9、网口ethtool_ops函数net_device->ethtool_ops()

3、网络工具程序

3.1、ifconfig

ifconfig工具由net-tools-1.60.tar.bz2软件包提供。Ifconfig命令是最常用的网络接口命令,可以查看端口的状态,配置端口ip、mac地址,up/down端口等等功能。下面看看ifconfig具体的代码实现是怎么样的。

3.1.1、查看端口状态

这里写图片描述
这里写图片描述
这里写图片描述

接下来我们分析ifconfig查看网口状态的具体代码实现

3.1.1.1、main()

这里写图片描述
这里写图片描述
这里写图片描述

3.1.1.2、if_print()

这里写图片描述
这里写图片描述
371
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

“/proc/net/dev”文件中包含的网口信息格式:

这里写图片描述

在“/sys/class/net”目录中也包含同样的网口信息:

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
381
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

3.1.2、配置端口IP

“ifconfig ethxxx 192.168.1.1 netmask 255.255.255.0”

这里写图片描述
这里写图片描述
这里写图片描述

3.1.3、up端口

“ifconfig ethxxx up”

这里写图片描述
391

3.1.4、down端口

“ifconfig ethxxx down”

这里写图片描述
这里写图片描述

3.2、ethtool

ethtool工具由ethtool_3.0.orig.tar.bz2软件包提供。Ethtool配置网口更底层的参数,例如phy的自协商、速度、pause支持等等。
配置命令是通过ioctl的“SIOCETHTOOL”配置下去,ifr->ifr_data再带下去具体的ethtool命令。Ethtool需要网口驱动net_device-> ethtool_ops函数的支持。

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

3.3、service network start/stop

网络相关的命令还有“service network start/stop/restart”启动/停止网络,service xxx启动的命令是对应“/etc/init.d/”路径下的xxx脚本,所以其实network就是“/etc/init.d/network”脚本,大家可以自己去看看其实现细节。

3.4、xinetd

xinetd是常见的网络服务后台监控进程,xinetd并不提供具体的服务,在检测到有对应服务接入时,再启动具体的网络服务程序。
这里就不具体解析了。

4、参考资料

猜你喜欢

转载自blog.csdn.net/pwl999/article/details/78238454
2.3