• IP结构与操作之__inet_insert_ifa/__inet_del_ifa


    两个函数分别完成ip地址的添加和删除工作,具体见下面源码分析;

     1 /* 
     2     添加ip地址 
     3     主地址添加到最后一个满足范围的主地址后面
     4     从地址添加到整个列表后面
     5     若列表中存在与插入地址在同一子网的地址,则
     6     要求ip地址不同且范围相同,并且插入地址认为是从地址
     7 */
     8 static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
     9                  u32 portid)
    10 {
    11     struct in_device *in_dev = ifa->ifa_dev;
    12     struct in_ifaddr *ifa1, **ifap, **last_primary;
    13 
    14     ASSERT_RTNL();
    15 
    16     /* 地址不存在 */
    17     if (!ifa->ifa_local) {
    18         inet_free_ifa(ifa);
    19         return 0;
    20     }
    21 
    22     /* 清除从地址标记 */
    23     ifa->ifa_flags &= ~IFA_F_SECONDARY;
    24 
    25     /* 记录最后一个满足范围的主地址位置,用于插入 */
    26     last_primary = &in_dev->ifa_list;
    27 
    28     /* 遍历地址列表 */
    29     for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
    30          ifap = &ifa1->ifa_next) {
    31          /* 不是从地址&& 范围值小于当前地址 */
    32         if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
    33             ifa->ifa_scope <= ifa1->ifa_scope)
    34             /* 记录主地址的next指针 */
    35             last_primary = &ifa1->ifa_next;
    36 
    37         /* 同一子网 */
    38         if (ifa1->ifa_mask == ifa->ifa_mask &&
    39             inet_ifa_match(ifa1->ifa_address, ifa)) {
    40             /* 地址相同 */
    41             if (ifa1->ifa_local == ifa->ifa_local) {
    42                 /* 地址已存在 */
    43                 inet_free_ifa(ifa);
    44                 return -EEXIST;
    45             }
    46 
    47             /* 范围不同 */
    48             if (ifa1->ifa_scope != ifa->ifa_scope) {
    49                 /* 非法地址 */
    50                 inet_free_ifa(ifa);
    51                 return -EINVAL;
    52             }
    53 
    54             /* 同子网范围相同的不同ip地址为从地址 */
    55             ifa->ifa_flags |= IFA_F_SECONDARY;
    56         }
    57     }
    58 
    59 
    60     /* 下面添加地址规则 */
    61     /* 主地址放在最后一个满足范围的主地址的后面 */
    62     /* 从地址放在最后一个(从)地址的后面 */
    63 
    64 
    65     /* 地址为主地址 */
    66     if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
    67         prandom_seed((__force u32) ifa->ifa_local);
    68         /*  ifap指向最后一个主地址的next指针 */
    69         ifap = last_primary;
    70     }
    71 
    72     /* ifa的next赋值为ifap保存的值,也就是待插入位置的下一个节点地址 */
    73     ifa->ifa_next = *ifap;
    74 
    75     /* 而前面保存下一个节点的next指针指向新的ifa */
    76     *ifap = ifa;
    77 
    78     /* 插入hash表 */
    79     inet_hash_insert(dev_net(in_dev->dev), ifa);
    80 
    81     /* 重新开启检查生命周期任务 */
    82     cancel_delayed_work(&check_lifetime_work);
    83     queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0);
    84 
    85     /* Send message first, then call notifier.
    86        Notifier will trigger FIB update, so that
    87        listeners of netlink will know about new ifaddr */
    88 
    89     /* 发送添加新地址消息 */
    90     rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid);
    91 
    92     /* 通知设备启动 */
    93     blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
    94 
    95     return 0;
    96 }
      1 /* 删除ip地址,如果从地址允许提升为主地址,则提升 */
      2 static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
      3              int destroy, struct nlmsghdr *nlh, u32 portid)
      4 {
      5     struct in_ifaddr *promote = NULL;
      6     struct in_ifaddr *ifa, *ifa1 = *ifap;
      7     struct in_ifaddr *last_prim = in_dev->ifa_list;
      8     struct in_ifaddr *prev_prom = NULL;
      9 
     10     /* 从地址是否允许提升为主地址 */
     11     int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
     12 
     13     ASSERT_RTNL();
     14 
     15     /* ip控制块正在被销毁 */
     16     if (in_dev->dead)
     17         goto no_promotions;
     18 
     19     /* 1. Deleting primary ifaddr forces deletion all secondaries
     20      * unless alias promotion is set
     21      **/
     22 
     23     /* 如果是主地址 */
     24     if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
     25         struct in_ifaddr **ifap1 = &ifa1->ifa_next;
     26 
     27         /* 遍历链表 */
     28         while ((ifa = *ifap1) != NULL) {
     29 
     30             /* 最后一个满足范围的主地址 */
     31             if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
     32                 ifa1->ifa_scope <= ifa->ifa_scope)
     33                 last_prim = ifa;
     34 
     35             /* 主地址|| 子网掩码不同 || 网络前缀不同 */
     36             if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
     37                 ifa1->ifa_mask != ifa->ifa_mask ||
     38                 !inet_ifa_match(ifa1->ifa_address, ifa)) {
     39                 ifap1 = &ifa->ifa_next;
     40                 prev_prom = ifa;
     41                 continue;
     42             }
     43 
     44             /* 找到在同一子网的从地址 */
     45 
     46             /* 不允许提升ip地址 */
     47             if (!do_promote) {
     48                 /* 删除地址 */
     49                 inet_hash_remove(ifa);
     50                 *ifap1 = ifa->ifa_next;
     51 
     52                 /* 发送删除地址消息 */
     53                 rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid);
     54                 /* 通知设备关闭 */
     55                 blocking_notifier_call_chain(&inetaddr_chain,
     56                         NETDEV_DOWN, ifa);
     57                 inet_free_ifa(ifa);
     58             } else {
     59                 /* 需要提升的从地址为找到的地址 */
     60                 promote = ifa;
     61                 break;
     62             }
     63         }
     64     }
     65 
     66     /* On promotion all secondaries from subnet are changing
     67      * the primary IP, we must remove all their routes silently
     68      * and later to add them back with new prefsrc. Do this
     69      * while all addresses are on the device list.
     70      */
     71     /* 因为允许提升从地址,需要 删除从地址的路由 */
     72     for (ifa = promote; ifa; ifa = ifa->ifa_next) {
     73         if (ifa1->ifa_mask == ifa->ifa_mask &&
     74             inet_ifa_match(ifa1->ifa_address, ifa))
     75             fib_del_ifaddr(ifa, ifa1);
     76     }
     77 
     78 no_promotions:
     79     /* 2. Unlink it */
     80 
     81     /* 删除地址 */
     82     *ifap = ifa1->ifa_next;
     83     inet_hash_remove(ifa1);
     84 
     85     /* 3. Announce address deletion */
     86 
     87     /* Send message first, then call notifier.
     88        At first sight, FIB update triggered by notifier
     89        will refer to already deleted ifaddr, that could confuse
     90        netlink listeners. It is not true: look, gated sees
     91        that route deleted and if it still thinks that ifaddr
     92        is valid, it will try to restore deleted routes... Grr.
     93        So that, this order is correct.
     94      */
     95     /* 发送删除地址消息 */
     96     rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid);
     97     /* 通知设备关闭 */
     98     blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
     99 
    100     /* 允许提升从ip为主ip */
    101     if (promote) {
    102         struct in_ifaddr *next_sec = promote->ifa_next;
    103 
    104         /* 插入该从地址到主地址位置 */
    105         if (prev_prom) {
    106             prev_prom->ifa_next = promote->ifa_next;
    107             promote->ifa_next = last_prim->ifa_next;
    108             last_prim->ifa_next = promote;
    109         }
    110 
    111         /* 修改该ip为主地址 */
    112         promote->ifa_flags &= ~IFA_F_SECONDARY;
    113 
    114         /* 发送新地址消息 */
    115         rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
    116         /* 通知设备启动 */
    117         blocking_notifier_call_chain(&inetaddr_chain,
    118                 NETDEV_UP, promote);
    119 
    120         /* 重新添加路由表 */
    121         for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
    122             if (ifa1->ifa_mask != ifa->ifa_mask ||
    123                 !inet_ifa_match(ifa1->ifa_address, ifa))
    124                     continue;
    125             fib_add_ifaddr(ifa);
    126         }
    127 
    128     }
    129 
    130     /* 需要释放则释放内存 */
    131     if (destroy)
    132         inet_free_ifa(ifa1);
    133 }
  • 相关阅读:
    linux使用windows中编辑的文件,格式问题
    模拟退火算法c++
    progress第三方框架和二维码第三方框架的选择
    iOS 初始化项目内容
    github上使用SSH和gitignore
    wordpress 如何设置自定义的首页
    wordpress 删除底部"自豪地采用 WordPress"
    masonry注意事项
    iOS修改工程名
    iOS版本更新在APP中直接访问AppStore
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/7538366.html
Copyright © 2020-2023  润新知