Linux协议栈代码阅读笔记(二)网络接口的配置

Linux协议栈代码阅读笔记(二)网络接口的配置
(基于linux-2.6.11)

(一)用户态通过C库函数ioctl进行网络接口的配置

例如,知名的ifconfig程序,就是通过C库函数sys_ioctl实现网络接口的配置的。
具体方法大致如下,即建立一个socket,得到一个fd,然后在此fd上执行ioctl即可完成各种操作(例如,查询/配置mac、ip、mtu,启动/停止网络接口)。
int fd = socket(AF_INET, SOCK_DGRAM, 0);
ioctl(fd, SIOCGIFFLAGS, (caddr_t)&ifr);

(二)上述C库函数如何与内核交互
C库代码准备好相应的工作后(例如,设置系统调用号啦、参数构造啦、栈啦、寄存器设置啦),通过系统调用指令,进入内核态。从内核返回后,C库函数再做相应的善后工作,然后将结果返回给用户程序。

这部分代码,不同架构的处理器,有不同的实现。


(三)内核态如何处理用户的网络通讯请求
上一步,C库发起了系统调用,根据系统调用号,进入系统调用表的相应表目。ioctl对应的是54号系统调用,即sys_ioctl函数。
此函数的代码如下(源码文件:fs\Ioctl.c),最终通过vfs_ioctl完成操作。
asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
 struct file * filp;
 int error = -EBADF;
 int fput_needed;

 filp = fget_light(fd, &fput_needed);
 if (!filp)
  goto out;

 error = security_file_ioctl(filp, cmd, arg);
 if (error)
  goto out_fput;

 error = vfs_ioctl(filp, fd, cmd, arg);
 out_fput:
 fput_light(filp, fput_needed);
 out:
 return error;
}

(四)vfs_ioctl内部的执行路径
由于我们的fd对应的是一个socket,并且我们的操作是配置网络接口。因此,进入vfs_ioctl后的函数执行路径如下:
do_ioctl
filp->f_op->ioctl(即socket_file_ops.unlocked_ioctl,也就是sock_ioctl)
sock->ops->ioctl(即inet_dgram_ops.ioctl,也就是inet_ioctl)
接下来的工作,就看具体的操作了。下面列出部分操作对应的函数。

1)设置/查询ip、广播地址等操作,执行devinet_ioctl函数。
2)设置/查询接口名称、mac地址、mtu等,执行dev_ioctl函数。

这些操作,有些还需要调用驱动中的相关函数。
例如,设置mtu涉及到的执行路径:
dev_ifsioc
dev_set_mtu
dev->change_mtu(以Intel(R)的e1000网卡为例,dev->change_mtu对应的函数是网卡驱动中的e1000_change_mtu。源码:drivers\net\e1000\E1000_main.c)
再有,设置mac地址涉及的执行路径有:
dev_ifsioc
dev->set_mac_address(以Intel(R)的e1000网卡为例,dev->set_mac_address对应的函数是网卡驱动中的e1000_set_mac。源码:drivers\net\e1000\E1000_main.c)

最后,有些设置完成后,还需要通知内核中关心此事件的模块。
例如,mac地址变化后,就需要通知那些注册了关心此事件的内核模块。
具体代码如下:

notifier_call_chain(&netdev_chain,  NETDEV_CHANGEADDR, dev);

 

你可能感兴趣的:(linux)