两个函数分别完成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. HDU4647_Another Graph Game

    有趣的博弈题. 关键在于把比边权的平分到两边的点权上面,然后点权排序,每次从大的开始拿就可以了. #include <iostream> #include <cstdio> # ...

  2. noip模拟题《戏》game

    [问题背景]      zhx 和他的妹子(们) 做游戏.[问题描述]      考虑 N 个人玩一个游戏,任意两个人之间进行一场游戏(共 N*(N-1)/2 场),且每场一定能分出胜负.      ...

  3. BZOJ3711 PA2014Druzyny(动态规划+cdq分治+线段树)

    显然可以dp:设f[i]为前i个人最多能分多少组,则f[i]=max{f[j]}+1 (cmax<=i-j<=dmin). 容易发现d的限制是一段连续区间,二分或者随便怎么搞都行.c则有点 ...

  4. 【BZOJ4198】【NOI2015】荷马史诗(贪心,Huffman树)

    [BZOJ4198][NOI2015]荷马史诗(贪心,Huffman树) 题面 BZOJ 洛谷 题解 合并果子都是不知道多久以前做过的了.现在才知道原来本质就是一棵哈夫曼树啊. 这题我们仔细研究一下题 ...

  5. 【BZOJ1458】【洛谷4311】士兵占领(网络流)

    [BZOJ1458][洛谷4311]士兵占领(网络流) 题面 BZOJ权限题,洛谷真好 Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最 ...

  6. python基础(4)

    条件判断和循环 条件判断 计算机之所以能做很多自动化的任务,因为它可以自己做条件判断. 比如,输入用户年龄,根据年龄打印不同的内容,在Python程序中,用if语句实现: age = 20 if ag ...

  7. 【生成树,堆】【CF1095F】 Make It Connected

    Description 给定 \(n\) 个点,每个点有点权,连结两个点花费的代价为两点的点权和.另外有 \(m\) 条特殊边,参数为 \(x,y,z\).意为如果你选择这条边,就可以花费 \(z\) ...

  8. 《剑指offer》— JavaScript(14)链表中倒数第k个结点

    链表中倒数第k个结点 题目描述 输入一个链表,输出该链表中倒数第k个结点. 思路 两个指针,先让第一个指针和第二个指针都指向头结点,然后再让第一个指正走(k-1)步,到达第k个节点: 然后两个指针同时 ...

  9. OD脚本指令集

    声明: 1.本指令集搜集自各论坛.博客,欢迎补充讨论 OD脚本指令集 在后面的文档中, “源操作数” 和 “目的操作数”表示以下含义: - 十六进制常数,既没有前缀也没有后缀. (例如:是00FF, ...

  10. Qt ------ 再论事件循环

    在介绍在以前,我们要认识两个术语: 可重入的(Reentrant):如果多个线程可以在同一时刻调用一个类的所有函数,并且保证每一次函数调用都引用一个唯一的数据,就称这个类是可重入的(Reentrant ...