內核網絡子系統--添加/刪除ip地址
阿新 • • 發佈:2017-08-19
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地址