免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1691 | 回复: 0
打印 上一主题 下一主题

[网络子系统] linux内核网络之IP设置 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-03-16 01:38 |只看该作者 |倒序浏览
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);
        }
}
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP