• __inet_insert_ifa/__inet_del_ifa


    Kernel: 4.12.6

    添加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();
    
        //ifa_local地址不存在
        if (!ifa->ifa_local) {
            inet_free_ifa(ifa);
            return 0;
        }
    
        //去除从地址标志
        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) //ifa范围小于主地址范围
                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 = last_primary;
        }
    
        //将ifa节点添加到ifa_list链表的合适位置
        //主地址添加符合范围的最后一个primary之后
        //从地址添加到链表尾
        ifa->ifa_next = *ifap;
        *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, 0);
    
        /* Send message first, then call notifier.
           Notifier will trigger FIB update, so that
           listeners of netlink will know about new ifaddr */
    
        //发送netlink消息
        rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
    
        //inetaddr_chain通知ip地址加入
        blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
    
        return 0;
    }
    
    static int inet_insert

    删除ip地址:主ip删除,若配置能够提升成主ip,则从ip提升成主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.
         */
        //遍历从地址,相同子网的清除fib表项
        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 */
    
        //从链表和hash表中删除目标地址
        *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);
    
        //进行地址提升
        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;
            }
    
            //去掉从地址标记
            promote->ifa_flags &= ~IFA_F_SECONDARY;
    
            //通知ip设置消息
            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表项
                
                fib_add_ifaddr(ifa);
            }
    
        }
    
        //如果有释放标记,则释放内存
        if (destroy)
            inet_free_ifa(ifa1);
    }
  • 相关阅读:
    oss blob上传
    app中画一条细线
    antd和原生交互,原生掉前端的方法
    -webkit-touch-callout 图片下载
    ifram嵌入网址 有跨域问题
    ...state
    数组对象的复制
    在vue中使用tinymce组件
    autofs自动挂载服务
    podmen
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/7392637.html
Copyright © 2020-2023  润新知