1. 程式人生 > >內核網絡子系統--添加/刪除ip地址

內核網絡子系統--添加/刪除ip地址

fad 目標 destroy insert use ip地址 rest routes oid

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);
}

內核網絡子系統--添加/刪除ip地址