TCP/IP源码学习——inet_select_addr函数分析
浏览:1777次 出处信息
作者:gfree.wind@gmail.com
博客:blog.focus-linux.net linuxfocus.blog.chinaunix.net
博客:blog.focus-linux.net linuxfocus.blog.chinaunix.net
本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
======================================================================================================
当一个网卡配置了多个IP时,那么kernel选择哪个IP作为源IP来发送数据包呢?对于IPv4来说,这是由函数inet_select_addr决定的。
- __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
- {
- __be32 addr = 0;
- struct in_device *in_dev;
- struct net *net = dev_net(dev);
- rcu_read_lock();
- /*
- 得到该device的IP地址配置
- 一直比较奇怪为什么IP的地址配置对应的结构,名字为in_device。device的internet地址?
- */
- in_dev = __in_dev_get_rcu(dev);
- if (!in_dev)
- goto no_in_dev;
//遍历primary地址
- for_primary_ifa(in_dev) {
- /*
- 这里对IP地址的scope进行判,其实用的枚举与route的scope相同
- enum rt_scope_t {
- RT_SCOPE_UNIVERSE=0,
- /* User defined values */
- RT_SCOPE_SITE=200,
- RT_SCOPE_LINK=253,
- RT_SCOPE_HOST=254,
- RT_SCOPE_NOWHERE=255
- };
- 那么,scope的值越小,对于IP地址来说,其表示的可用范围也就越大。(关于IP address的scope,参见 http://www.embeddedlinux.org.cn/linux_net/0596002556/understandlni-CHP-30-SECT-2.html#understandlni-CHP-30-SECT-2.1 )因此,当ifa->ifa_scope的值大于参数scope时,那么其就不符合要求。
- */
- if (ifa->ifa_scope > scope)
- continue;
/*
1. 当dst目的地址为0时,那么该地址就可以直接作为备选
2. 当dst不为0时,需要地址与dst匹配,即处于同一网络。
*/
- if (!dst || inet_ifa_match(dst, ifa)) {
- /* 找到了匹配的地址,可以跳出循环了 */
- addr = ifa->ifa_local;
- break;
- }
/* 将第一个primary地址保存到addr中,作为一个默认候选地址 */
- if (!addr)
- addr = ifa->ifa_local;
- } endfor_ifa(in_dev);
/*
找到了可以使用的地址。
从上面可以看出,这里有两种成功找到的情况
1. 真正找到了匹配的地址
2. 如没有匹配的地址,那么就使用符合scope要求的第一个primary 地址
*/
- if (addr)
- goto out_unlock;
- no_in_dev:
- /* Not loopback addresses on loopback should be preferred
- in this case. It is importnat that lo is the first interface
- in dev_base list.
- */
- /* 在指定的device上找不到匹配的地址,只能遍历所有的device了*/
- for_each_netdev_rcu(net, dev) {
- in_dev = __in_dev_get_rcu(dev);
- if (!in_dev)
- continue;
/* 同样是遍历primary地址*/
- for_primary_ifa(in_dev) {
- /*
- 只要符合scope的要求,就可以使用了
- 这里特意排除了RT_SCOPE_LINK这种情况。这样的IP地址被用于与整个儿LAN通信,但是为什么前面不需要这个检查呢?
- 还有一个问题,为什么这里不进行目的地址dst是否匹配的判断了呢?
- */
- if (ifa->ifa_scope != RT_SCOPE_LINK &&
- ifa->ifa_scope <= scope) {
- addr = ifa->ifa_local;
- goto out_unlock;
- }
- } endfor_ifa(in_dev);
- }
- out_unlock:
- rcu_read_unlock();
- return addr;
- }
再顺便看一下函数inet_ifa_match,该函数用于判断IP地址是否处于同一网段内。
- static __inline__ int inet_ifa_match(__be32 addr, struct in_ifaddr *ifa)
- {
- return !((addr^ifa->ifa_address)&ifa->ifa_mask);
- }
也就是!((IP1^IP2)&mask)。对于这个需求,最直观的作法是IP1&mask == IP2&mask。经过测试,前者要比后面那个直观的作法快10%以上。
那么kernel中的作法需要如何理解呢?其实我们完全可以从后面那个直观的作法得到kernel的作法。
IP1&mask == IP2&mask ---> !((IP1&mask)^(IP2&mask)) ---->!((IP1^IP2)&mask)
这下理解了吧?两个IP做异或,如果其网络部分如果相同,那么网络部分异或的值应该为0.而主机部分的值则通过mask屏蔽掉。最后取反,就得到了是否匹配的结果。
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
扫一扫订阅我的微信号:IT技术博客大学习
<< 前一篇:ERLANG OTP源码分析 – gen_fsm
后一篇:Zen Cart 源码阅读笔记 (一) >>
文章信息
- 作者:gfree.wind@gmail.com 来源: kernelchina blogs
- 标签: TCP/IPinet_selec
- 发布时间:2012-07-12 23:26:04
近3天十大热文
- [66] Oracle MTS模式下 进程地址与会话信
- [65] Go Reflect 性能
- [64] 如何拿下简短的域名
- [60] android 开发入门
- [59] 图书馆的世界纪录
- [59] 【社会化设计】自我(self)部分――欢迎区
- [58] IOS安全–浅谈关于IOS加固的几种方法
- [54] 视觉调整-设计师 vs. 逻辑
- [48] 读书笔记-壹百度:百度十年千倍的29条法则
- [47] 界面设计速成