本文以Linux kernel3.10版本描述
上图是《Understanding LINUX NETWORK INTERNALS》一书中对socket的ioctl调用的整体flow,本文只对其中SIOCSIFADDR这一个command进行flow的梳理。
首先是socket的创建,这在上图中没有标识出来,大致flow如下图所示,这部分源码在 net/socket.c中
socket的create对ioctl的作用主要有两点:
1、如何在执行ioctl时,调用到sock_ioctl
在创建inode时,将socket_file_ops赋给inode→i_fop。这样在执行ioctl时,通过执行在inode的函数指针,最终调用的就是sock_ioctl函数。
如不理解上一句话,可参考如下解释:
socket_file_ops 是socket 文件中 file_operations结构体的实现的对象(全局变量)。在每次create socket时,均将该全局变量的指针赋给inode→i_fop.
每次执行ioctl时,是执行的inode→i_fop->(*unlocked_ioctl),而socket_file_ops→unlocked_ioctl 赋值是sock_ioctl函数的指针
所以每次在对socket执行ioctl时,最终执行的是sock_ioctl
该赋值在socket_alloc_file函数中实现,调用链是sock_map_fd →sock_alloc_file
2、如何根据SIOCSIFADDR,最终调用至inet_ioctl
在socket create时,会执行pf->create函数,该函数会将inet_ioctl函数指针赋值给sock->ops→ioctl
详细说明:
pf通过socket create时的family,找到对应pf,执行其中的create函数。
family为AF_INET时,调用的create为 net/af_inet.c中的inet_create函数.
在pf→create函数中,通过type找到对应ioctl函数,赋值给sock->ops
type为SOCK_DGRAM时,对应ioctl为inet_ioctl
根据以上两点大致可以理解在《Understanding LINUX NETWORK INTERNALS》一书中的socket 执行ioctl的flow
一开始,执行到sock_ioctl,该函数中根据cmd,执行sock→ops→ioctl
在上面2点可知,执行sock→ops→ioctl即执行inet_ioctl
inet_ioctl根据cmd,执行devinet_ioctl
所以最终执行的是devinet_ioctl函数
devinet_ioctl的实现在net/devinet.c中
devinet_ioctl函数的执行flow大致如下图所示:
根据ifr.ifr_name的名称,找到对应的in_device结构体,并找到对应的ifa结构体
将ifa重置ifaddr为设置ip,最后在重新添加至in_device结构体中。
SIOCGIFADDR 的flow便是将在找到ifa结构体后,将ifa中的addr set回sin_addr返回
上部分主要写了ioctl的执行flow和做了哪些事,可以看出,其中in_device与
in_device如下:
kernel network中比较重要的两个结构体net_device和in_device,net_device主要用于内核自身(驱动以及上层协议等)对网络设备的操作;
而in_device用于保存用户态对此设备的配置,比如ip地址的配置等,保存在in_device。两个结构体通过指针互指联系在一起。