两个函数分别完成ip地址的添加和删除工作,具体见下面源码分析;

 /*
添加ip地址
主地址添加到最后一个满足范围的主地址后面
从地址添加到整个列表后面
若列表中存在与插入地址在同一子网的地址,则
要求ip地址不同且范围相同,并且插入地址认为是从地址
*/
static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
u32 portid)
{
struct in_device *in_dev = ifa->ifa_dev;
struct in_ifaddr *ifa1, **ifap, **last_primary; ASSERT_RTNL(); /* 地址不存在 */
if (!ifa->ifa_local) {
inet_free_ifa(ifa);
return ;
} /* 清除从地址标记 */
ifa->ifa_flags &= ~IFA_F_SECONDARY; /* 记录最后一个满足范围的主地址位置,用于插入 */
last_primary = &in_dev->ifa_list; /* 遍历地址列表 */
for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
ifap = &ifa1->ifa_next) {
/* 不是从地址&& 范围值小于当前地址 */
if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
ifa->ifa_scope <= ifa1->ifa_scope)
/* 记录主地址的next指针 */
last_primary = &ifa1->ifa_next; /* 同一子网 */
if (ifa1->ifa_mask == ifa->ifa_mask &&
inet_ifa_match(ifa1->ifa_address, ifa)) {
/* 地址相同 */
if (ifa1->ifa_local == ifa->ifa_local) {
/* 地址已存在 */
inet_free_ifa(ifa);
return -EEXIST;
} /* 范围不同 */
if (ifa1->ifa_scope != ifa->ifa_scope) {
/* 非法地址 */
inet_free_ifa(ifa);
return -EINVAL;
} /* 同子网范围相同的不同ip地址为从地址 */
ifa->ifa_flags |= IFA_F_SECONDARY;
}
} /* 下面添加地址规则 */
/* 主地址放在最后一个满足范围的主地址的后面 */
/* 从地址放在最后一个(从)地址的后面 */ /* 地址为主地址 */
if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
prandom_seed((__force u32) ifa->ifa_local);
/* ifap指向最后一个主地址的next指针 */
ifap = last_primary;
} /* ifa的next赋值为ifap保存的值,也就是待插入位置的下一个节点地址 */
ifa->ifa_next = *ifap; /* 而前面保存下一个节点的next指针指向新的ifa */
*ifap = ifa; /* 插入hash表 */
inet_hash_insert(dev_net(in_dev->dev), ifa); /* 重新开启检查生命周期任务 */
cancel_delayed_work(&check_lifetime_work);
queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, ); /* Send message first, then call notifier.
Notifier will trigger FIB update, so that
listeners of netlink will know about new ifaddr */ /* 发送添加新地址消息 */
rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid); /* 通知设备启动 */
blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); return ;
}
 /* 删除ip地址,如果从地址允许提升为主地址,则提升 */
static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
int destroy, struct nlmsghdr *nlh, u32 portid)
{
struct in_ifaddr *promote = NULL;
struct in_ifaddr *ifa, *ifa1 = *ifap;
struct in_ifaddr *last_prim = in_dev->ifa_list;
struct in_ifaddr *prev_prom = NULL; /* 从地址是否允许提升为主地址 */
int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev); ASSERT_RTNL(); /* ip控制块正在被销毁 */
if (in_dev->dead)
goto no_promotions; /* 1. Deleting primary ifaddr forces deletion all secondaries
* unless alias promotion is set
**/ /* 如果是主地址 */
if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
struct in_ifaddr **ifap1 = &ifa1->ifa_next; /* 遍历链表 */
while ((ifa = *ifap1) != NULL) { /* 最后一个满足范围的主地址 */
if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
ifa1->ifa_scope <= ifa->ifa_scope)
last_prim = ifa; /* 主地址|| 子网掩码不同 || 网络前缀不同 */
if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
ifa1->ifa_mask != ifa->ifa_mask ||
!inet_ifa_match(ifa1->ifa_address, ifa)) {
ifap1 = &ifa->ifa_next;
prev_prom = ifa;
continue;
} /* 找到在同一子网的从地址 */ /* 不允许提升ip地址 */
if (!do_promote) {
/* 删除地址 */
inet_hash_remove(ifa);
*ifap1 = ifa->ifa_next; /* 发送删除地址消息 */
rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
/* 通知设备关闭 */
blocking_notifier_call_chain(&inetaddr_chain,
NETDEV_DOWN, ifa);
inet_free_ifa(ifa);
} else {
/* 需要提升的从地址为找到的地址 */
promote = ifa;
break;
}
}
} /* On promotion all secondaries from subnet are changing
* the primary IP, we must remove all their routes silently
* and later to add them back with new prefsrc. Do this
* while all addresses are on the device list.
*/
/* 因为允许提升从地址,需要 删除从地址的路由 */
for (ifa = promote; ifa; ifa = ifa->ifa_next) {
if (ifa1->ifa_mask == ifa->ifa_mask &&
inet_ifa_match(ifa1->ifa_address, ifa))
fib_del_ifaddr(ifa, ifa1);
} no_promotions:
/* 2. Unlink it */ /* 删除地址 */
*ifap = ifa1->ifa_next;
inet_hash_remove(ifa1); /* 3. Announce address deletion */ /* Send message first, then call notifier.
At first sight, FIB update triggered by notifier
will refer to already deleted ifaddr, that could confuse
netlink listeners. It is not true: look, gated sees
that route deleted and if it still thinks that ifaddr
is valid, it will try to restore deleted routes... Grr.
So that, this order is correct.
*/
/* 发送删除地址消息 */
rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
/* 通知设备关闭 */
blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); /* 允许提升从ip为主ip */
if (promote) {
struct in_ifaddr *next_sec = promote->ifa_next; /* 插入该从地址到主地址位置 */
if (prev_prom) {
prev_prom->ifa_next = promote->ifa_next;
promote->ifa_next = last_prim->ifa_next;
last_prim->ifa_next = promote;
} /* 修改该ip为主地址 */
promote->ifa_flags &= ~IFA_F_SECONDARY; /* 发送新地址消息 */
rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
/* 通知设备启动 */
blocking_notifier_call_chain(&inetaddr_chain,
NETDEV_UP, promote); /* 重新添加路由表 */
for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
if (ifa1->ifa_mask != ifa->ifa_mask ||
!inet_ifa_match(ifa1->ifa_address, ifa))
continue;
fib_add_ifaddr(ifa);
} } /* 需要释放则释放内存 */
if (destroy)
inet_free_ifa(ifa1);
}

__inet_insert_ifa/__inet_del_ifa的更多相关文章

  1. ifa_local 和 ifa_address

    ifa_local 和 ifa_address区别联系: 1. 在配置了支持广播的接口上,与IFA_LOCAL一样,同样表示本地ip地址: 2. 对于点对点链路,IFA_ADDRESS表示的是对端的地 ...

随机推荐

  1. mysql(五)查询缓存

    mysql的逻辑架构图如下: 当开启查询缓存时,mysql会将查询结果缓存到查询缓存区域,结果对应的key是使用查询语句,数据库名称,客户端协议的版本等因素算出的一个hash值. 在下次查询时,根据一 ...

  2. ios基础动画、关键帧动画、动画组、转场动画等

    概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌.在这里你可以看到iOS中如何使用图层精简非交互式绘图,如何通过核心动画创建基础动画.关键帧动画 ...

  3. 【loj2325】「清华集训 2017」小Y和恐怖的奴隶主 概率dp+倍增+矩阵乘法

    题目描述 你有一个m点生命值的奴隶主,奴隶主受伤未死且当前随从数目不超过k则再召唤一个m点生命值的奴隶主. T次询问,每次询问如果如果对面下出一个n点攻击力的克苏恩,你的英雄期望会受到到多少伤害. 输 ...

  4. [二十一]SpringBoot 之 导入xml配置

    SpringBoot理念就是零配置编程,但是如果绝对需要使用XML的配置,我们建议您仍旧从一个@Configuration类开始,你可以使用@ImportResouce注解加载XML配置文件,我拿一个 ...

  5. Day21-自定义分页

    一. 先简单来个示例 1.1 在urls.py中增加1条,user_list from django.conf.urls import url,include from django.contrib ...

  6. 转:linux命令: tail ,head 显示文件某行内容 与sed在线编辑器

    linux 如何显示一个文件的某几行(中间几行) 转:http://www.cnblogs.com/xianghang123/archive/2011/08/03/2125977.html http: ...

  7. 【转】Oracle 查询库中所有表名、字段名、表名说明、字段名说明

    转自 :http://gis-conquer.blog.sohu.com/170243422.html 查询所有表名:select t.table_name from user_tables t; 查 ...

  8. Eclipse在线安装spring-tool-suit插件

    查看eclipse版本:Help–>About Eclipse;如图1所示. 访问http://spring.io/tools/sts/all,复制在线安装url地址,不要下载ZIP文件,复制链 ...

  9. WebDriver的定位元素方法

    如果把页面上的元素看作人的话,在现实世界如何找到某人呢?方法有三: 一.通过人本身的属性,例如他的姓名,手机号,身份证号,性别,这些可区别他人的属性.在web页面上的元素也有这些属性,例如,id.na ...

  10. nginx服务器去掉url中的index.php 和 配置path_info

    隐藏index.php server { listen 80; server_name yourdomain.com; root /home/yourdomain/www/; index index. ...