内核网络子系统--添加/删除ip地址

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);
}
时间: 08-17

内核网络子系统--添加/删除ip地址的相关文章

c/c++ 网络编程 UDP 改变IP地址

网络编程 UDP 改变IP地址 在程序里动态改变主机的IP地址 1,改变ipv4的地址 #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <netinet/in.h> #include <net

CentOS 网络设置修改 指定IP地址 DNS 网关(转)

CentOS 网络设置修改 指定IP地址 DNS 网关(实测 笔记) 环境: 系统硬件:vmware vsphere (CPU:2*4核,内存2G) 系统版本:Centos-6.5-x86_64 路由器网关:192.168.1.1 步骤: 1.查看网络MAC地址 [[email protected] ~]# cat /etc/udev/rules.d/70-persistent-net.rules 显示如下信息 # PCI device 0x15ad:0x07b0 (vmxnet3) SUBSY

内核网络子系统--devinet_ioctl

Kernel: 4.12.6 deinet_ioctl:获取或者设置接口的地址,掩码,标记等信息: 注意,使用SIOCSIFFLAGS关闭设备,如果使用了别名,则删除对应ip,如果其为主ip,并且从ip未设置提升主ip,则所有从ip也会删除: int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) { struct ifreq ifr; struct sockaddr_in sin_orig; struct s

网络工程师必备素质-IP地址练习题

if need answers , mail to [email protected] 练习-IP地址和子网划分的题目 1. 192.168.1.0/24 使用掩码255.255.255.240 划分子网,其可用子网数为( ),每个子网内可用主机地址数为( ) A. 14 14 B. 16 14 C. 254 6 D. 14 62 2. 子网掩码为255.255.0.0 ,下列哪个 IP 地址不在同一网段中( ) A. 172.25.15.201 B. 172.25.16.15 C. 172.1

(四十七)socket编程——socket引入、网络字节序、IP地址转换函数、sockaddr数据结构介绍

一.什么是socket socket这个词可以表示很多概念: 在TCP/IP协议中,"IP地址+TCP或UDP端口号"唯一标识网络通讯中的一个进程,"IP地址+端口号"就称为socket. 在TCP协议中,建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接.socket本身有"插座"的意思,因此用来描述网络连接的一对一关系. TCP/IP协议最早在BSD UNIX上实现,为TCP/

Linux C 网络编程 - 获取本地 ip 地址,mac,通过域名获取对应的 ip

获取本地 ip 地址,mac,通过域名获取对应的 ip, 是网络编程可能遇到的比较常见的操作了,所以总结如下(封装了3个函数), 直接上代码: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <netdb.h> #include <net/if.h> #inc

CentOS 6 网络设置修改 指定IP地址 DNS 网关(实测 笔记)_(转)

环境: 系统硬件:vmware vsphere (CPU:2*4核,内存2G) 系统版本:Centos-6.5-x86_64 路由器网关:192.168.1.1 步骤: 1.查看网络MAC地址 [[email protected] ~]# cat /etc/udev/rules.d/70-persistent-net.rules 显示如下信息 # PCI device 0x15ad:0x07b0 (vmxnet3) SUBSYSTEM=="net", ACTION=="add

【网络技术】根据ip地址子网掩码计算网络地址、直接广播地址、主机号

我不用专业的角度 去分析,我用傻瓜方法去做题. 这是模拟题,拿这个题做例子. 网址类型:当然是B类就不多说了 把ip地址和子网掩码转换成二进制,然后进行与运算. 145.189.24.3        10010001 10111101 00011000 00000011 255.255.224.0      11111111 11111111 11100000 00000000 网络地址:把ip地址和子网掩码进行与运算.两个1碰上是1  一个1碰上是0  两个0碰上 是0 变成了:      

CentOS 6 网络设置修改 指定IP地址 DNS 网关(转)

环境: 系统硬件:vmware vsphere (CPU:2*4核,内存2G) 系统版本:Centos-6.5-x86_64 路由器网关:192.168.1.1 步骤: 1.查看网络MAC地址 [[email protected] ~]# cat /etc/udev/rules.d/70-persistent-net.rules 显示如下信息 # PCI device 0x15ad:0x07b0 (vmxnet3) SUBSYSTEM=="net", ACTION=="add