- 论坛徽章:
- 0
|
static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
struct in_ifaddr *ifa;
ASSERT_RTNL();
ifa = rtm_to_ifaddr(nlh);
//从netlink消息中获取地址结构
if (IS_ERR(ifa))
return PTR_ERR(ifa);
return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).pid);
//将地址配置到指定的网络设备
}
static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
u32 pid)
{
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 0;
}
ifa->ifa_flags &= ~IFA_F_SECONDARY;
//去除从属IP地址标志,因为主从IP地址是根据当前已配置的Ip地址决定的
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)
last_primary = &ifa1->ifa_next;
//如果ifa1是主IP地址,且范围大于要插入的ifa
//则last_primary = &ifa1->ifa_next;
if (ifa1->ifa_mask == ifa->ifa_mask &&
inet_ifa_match(ifa1->ifa_address, ifa)) {
//ifa1和要插入的ifa子网掩码相同,且处在同一子网下
if (ifa1->ifa_local == ifa->ifa_local) {
inet_free_ifa(ifa);
return -EEXIST;
}
//ifa1和要插入的ifa的本地IP地址相同,说明IP地址已存在,则释放ifa返回
if (ifa1->ifa_scope != ifa->ifa_scope) {
inet_free_ifa(ifa);
return -EINVAL;
}
//如果ifa1和要插入的ifa的范围不一样,说明ifa数据错误,则释放ifa返回
ifa->ifa_flags |= IFA_F_SECONDARY;
//执行到这里,说明存在相同寻址范围的地址,ifa是一个从设备
}
}
//ifa1在第一次并没有初始化,这样都不出错???
if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
net_srandom(ifa->ifa_local);
ifap = last_primary;
}
//说明ifa是第一次进行配置。添加熵到伪随机数引擎中
ifa->ifa_next = *ifap;
*ifap = ifa;
//将ifa添加到ifa1的后面
/* 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, pid);
//通过netlink发送RTM_NEWADDR消息给感兴趣的用户进程
blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
return 0;
}
static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
u32 pid)
{
struct sk_buff *skb;
u32 seq = nlh ? nlh->nlmsg_seq : 0;
int err = -ENOBUFS;
skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
//分配skb描述符,和建立(netlink消息结构+struct skb_shared_info)大小的数据区
//skb->data指向netlink消息数据结构
if (skb == NULL)
goto errout;
err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0);
//初始化struct ifaddrmsg,struct nlmsghdr和struct nlattr及属性数据
/* failure implies BUG in inet_nlmsg_size() */
BUG_ON(err < 0);
err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
//构建好netlink消息结构,skb描述符后发送RTM_NEWADDR消息
errout:
if (err < 0)
rtnl_set_sk_err(RTNLGRP_IPV4_IFADDR, err);
}
static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
struct nlattr *tb[IFA_MAX+1];
struct in_device *in_dev;
struct ifaddrmsg *ifm;
struct in_ifaddr *ifa, **ifap;
int err = -EINVAL;
ASSERT_RTNL();
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
if (err < 0)
goto errout;
//解析netlink消息中的attitude,见下文
ifm = nlmsg_data(nlh);
//获取netlink消息中的struct ifaddrmsg
in_dev = inetdev_by_index(ifm->ifa_index);
if (in_dev == NULL) {
err = -ENODEV;
goto errout;
}
__in_dev_put(in_dev);
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
ifap = &ifa->ifa_next) {
//遍历IP地址链表,查找指定的IP配置块
if (tb[IFA_LOCAL] &&
ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
continue;
//nla_get_be32:获取attribute数据
//nla_get_be32(tb[IFA_LOCAL]):获取要查找IP配置块的本地地址
if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
continue;
//判断设备名是否相等
if (tb[IFA_ADDRESS] &&
(ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
!inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
continue;
//目标地址不为为空且(子网掩码不相等,或者不再同一子网下),则结束本次循环
__inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).pid);
return 0;
}
err = -EADDRNOTAVAIL;
errout:
return err;
}
static inline int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen,
struct nlattr *tb[], int maxtype,
struct nla_policy *policy)
{
if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
return -EINVAL;
//如果netlink消息长度小于最小netlink消息长度,则出错返回
return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
nlmsg_attrlen(nlh, hdrlen), policy);
}
//保存所有attribute头的指针到struct nlattr *tb[]数组中
//nlmsg_attrdata(nlh, hdrlen):返回第一个attribute的指针
//nlmsg_attrlen(nlh, hdrlen):所有attribute的大小
//这里的attribute=struct nlattr(attribute头)+attribute数据
static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
int destroy, struct nlmsghdr *nlh, u32 pid)
{
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();
/* 1. Deleting primary ifaddr forces deletion all secondaries
* unless alias promotion is set
**/
//IP地址链表的排列顺序:主IP地址按ifa_scope从大到小排列。从IP地址加到链表末尾
if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
//如果要删除的ifa1是主IP地址
struct in_ifaddr **ifap1 = &ifa1->ifa_next;
//这里没有从链表头开始循环
//想不明白,不从链表头开始,下面怎么找到要删除主IP地址的上一个主IP地址
//ifa1后面的元素的ifa_scope是小于等于ifa1->ifa_scope的
while ((ifa = *ifap1) != NULL) {
if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
ifa1->ifa_scope <= ifa->ifa_scope)
last_prim = ifa;
//last_prim是要删除主IP地址的上一个主IP地址
//ifa->ifa_scope这里是不可能大于ifa1->ifa_scope的。。- -??
//等于的情况还说的说去。如果没有等于的情况:last_prim = in_dev->ifa_list
//下面进行从IP地址提权的时候,就会插入到链表头。。。- -??
//求解答,是不是我想错了- -??
if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
ifa1->ifa_mask != ifa->ifa_mask ||
!inet_ifa_match(ifa1->ifa_address, ifa)) {
//如果ifa是主IP地址
//或者ifa和ifa1子网掩码不同
//或者ifa和ifa1不在同一子网下
ifap1 = &ifa->ifa_next;
prev_prom = ifa;
//prev_prom是提权从设备的上一个主或从IP地址
continue;
}
//执行到这里ifa就是要删除主IP地址的一个从IP地址
if (!do_promote) {
//如果没有设置promote_secondaries,即从IP提升为主IP
*ifap1 = ifa->ifa_next;
rtmsg_ifa(RTM_DELADDR, ifa, nlh, pid);
blocking_notifier_call_chain(&inetaddr_chain,
NETDEV_DOWN, ifa);
inet_free_ifa(ifa);
//则释放所有从IP
} else {
promote = ifa;
//这里的ifa是要提权的从IP
break;
}
}
}
/* 2. Unlink it */
*ifap = ifa1->ifa_next;
//把ifa1->ifa_next赋值给ifa1前面一个元素的next中。
//在IP地址列表中摘出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, pid);
blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
if (promote) {
//这里开始提权从IP
if (prev_prom) {
prev_prom->ifa_next = promote->ifa_next;
//将从IP地址从IP地址列表上摘下
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, pid);
blocking_notifier_call_chain(&inetaddr_chain,
NETDEV_UP, promote);
for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) {
if (ifa1->ifa_mask != ifa->ifa_mask ||
!inet_ifa_match(ifa1->ifa_address, ifa))
continue;
fib_add_ifaddr(ifa);
//将从属IP地址(提权的从IP地址)相关的路由表项添加到ip_fib_local_table路由表中
}
}
if (destroy) {
inet_free_ifa(ifa1);
if (!in_dev->ifa_list)
inetdev_destroy(in_dev);
}
}
|
|