【博客610】linux “ip lias“ and “ip secondary“

【博客610】linux “ip lias“ and “ip secondary“linux ip lias and ip secondary IP 别名 IP Alias 和 辅助 ip 地址 Secondary IP Address IP alias 是由 ifconfig 程序来创建和维护的 而 secondary IP address 则是由 ip 程序来创建和维护的 ip

大家好,我是讯享网,很高兴认识大家。

linux “ip lias” and “ip secondary”

IP 别名(IP Alias)和 辅助ip地址(Secondary IP Address)

IP alias 是由 ifconfig 程序来创建和维护的,而 secondary IP address 则是由 ip 程序来创建和维护的。ip addr add 创建的 secondary IP address 不能在 ifconfig -a 中看到,反过来,ifconfig 创建的 ethX:Y 却能在 ip addr show 中看到。实际上 ifconfig 只是取到第一个匹配的 IP 地址,而 ip addr show 却是完全取。

1、ip alias示例

ip alias 是由 Linux 系统的 ifconfig 命令来创建和维护的,别名IP就是在网卡设备上绑定的第二个及以上的IP

配置alias ip

# 使用下面两种方法都可以 # ifconfig eth0:1 192.168.40.20 netmask 255.255.255.0 up # ifconfig eth0:1 192.168.40.20/24 up 
讯享网

查看alias ip

讯享网# 使用别名的方法配置的VIP可以通过ifconfig查看,也可以通过ip addr 查看 # ifconfig eth0:1 eth0:1 Link encap:Ethernet HWaddr 00:0C:29:2C:5C:43 inet addr:192.168.40.20 Bcast:192.168.40.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 

删除alias ip

# 使用下面两种方法都可以 [root@crazy-acong ~]# ifconfig eth0:1 192.168.40.20 netmask 255.255.255.0 down [root@crazy-acong ~]# ifconfig eth0:1 down 

让alias ip永久生效

讯享网# 写入到网卡配置文件可以让别名IP永久生效,名字可以为ifcfg-eth0:x,x为0-255的任意数字,IP等内容格式和ifcfg-eth0一致,或者将命令写入/etc/rc.local 

2、Secondary ip示例

ip addr add 创建的辅助IP,不能通过ifconfig查看,但是通过ifconfig创建的别名IP却可以在ip addr show 命令查看。

配置Secondary ip

# ip addr add 192.168.40.20/24 dev eth0 

查看VIP别名的方法

# ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:0c:29:2c:5c:43 brd ff:ff:ff:ff:ff:ff inet 192.168.40.10/24 brd 192.168.40.255 scope global eth0 inet 192.168.40.20/24 scope global secondary eth0 inet6 fe80::20c:29ff:fe2c:5c43/64 scope link valid_lft forever preferred_lft forever 

删除

# ip addr del 192.168.40.20/24 dev eth0 

由此引入的ip a与 ifconfig的差别

在我的linux系统中用ip addr可以看到两个地址,用ifconfig只能看到一个地址

ip addr 2: enp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether d8:50:e6:db:a0:72 brd ff:ff:ff:ff:ff:ff inet 192.168.1.23/24 brd 192.168.1.255 scope global enp3s0 valid_lft forever preferred_lft forever inet 192.168.1.245/24 brd 192.168.1.255 scope global secondary enp3s0 valid_lft forever preferred_lft forever inet6 2001:da8:d800:1472:da50:e6ff:fedb:a072/64 scope global dynamic valid_lft 86381sec preferred_lft 14381sec inet6 fe80::da50:e6ff:fedb:a072/64 scope link valid_lft forever preferred_lft forever ifconfig enp3s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.1.23 netmask 255.255.255.0 broadcast 192.168.1.255 inet6 fe80::da50:e6ff:fedb:a072 prefixlen 64 scopeid 0x20<link> inet6 2001:da8:d800:1472:da50:e6ff:fedb:a072 prefixlen 64 scopeid 0x0<global> ether d8:50:e6:db:a0:72 txqueuelen 1000 (Ethernet) RX packets 14492 bytes  (10.3 MiB) RX errors 0 dropped 14 overruns 0 frame 0 TX packets 9217 bytes  (1.3 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 

原因:

ifconfig 和 ip addr 分别代表了 ip alias 和 secondary IP 两种机制。每个IP地址都有一个网卡 alias,还有一个标志位表示是 primary 还是 secondary IP。

  • ip alias:

IP的网卡 alias 就是 /etc/networking/interfaces 里那些 eth0:0, eth0:1……这些虚拟的网卡名称仅仅是为了给一块网卡添加多个IP地址。

  • ip secondary:
    secondary IP 是独立的另一套机制。同一块网卡上的多个IP,只要网络号(网段)不一样,就都是 primary IP;像楼主这样同一个网段里设了多个IP的,第一个IP是primary,后面添加的都是secondary。当primary被删掉时,secondary 默认会自动提升成 primary。

primary 和 secondary IP 的主要区别是本地发包的时候如果 socket 没有 bind 特定IP,会选出口网卡上的 primary IP 作为源IP

为什么ip和ifconfig看到的结果不一样:

ifconfig 是通过 ioctl,查看IP的时候,内核会遍历 ip alias 列表,对每个网卡 alias 只显示第一个IP(注意,不是把 primary IP 都打印出来)。而 ip addr 则是通过 netlink,会把所有IP都取出来,是否 secondary 的信息也会打印出来。ip addr 在设置IP的时候,又是不认网卡 alias 的。

添加地址可以通过两个用户空间程序搞定,一个是ifconfig,另 一个是ip addr add,ifconfig是基于ioctl进行地址添加的,而ip程序是基于netlink进行地址添加的,不管哪一种方式都可以达到目的

ip和ifconfig查看的方式不同:

为何用ip addr add添加的ip地址用ifconfig看不到,而ifconfig设置的地址ip addr show却是可以看到。这个问题通过看代码就可以明白,在ifconfig获得ip地址的时候,代码:

for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->ifa_next) { if (!strcmp(ifr.ifr_name, ifa->ifa_label) && sin_orig.sin_addr.s_addr == ifa->ifa_address) { break; } } 

源码解析:

取的是这个被找到的ifa的ip地址,而我们知道,所有的ifa链接成一个线性链表,那么找到了第一个就不会再往后走了,因此只能得到一个结果,就是链表最 前面的那个,而ip add show就不同了,具体在函数inet_dump_ifaddr中实现,该函数遍历所有的ifa,并且传到用户空间缓冲区。

注意

  • 用 ip addr add添加几个不在同一个网段的primary ip地址,然后再ifconfig一个和前面的ip都不在一个网段的ip,然后可以用ifconfig查看一下,发现不是刚刚用ifconfig设置进去 的那个ip,而是用ip addr add添加进去的,这就说明ifconfig永远都是取的ifa链表最前面的那一个
  • 如果你用ip addr add添加了很多的secondary ip地址,那么恰好你用ifconfig设置的ip地址和那些secondary ip在一个网段,那么所有的secondary ip都将被删除,这些都是sencondary ip的规范决定的,而且在代码中也有体现。
  • 另外还要注意,路由表的表项都是基于primary ip的,因为所有的操作都是以primary ip为主的,比如在添加路由的时候:
void fib_add_ifaddr(struct in_ifaddr *ifa) { struct in_device *in_dev = ifa->ifa_dev; struct net_device *dev = in_dev->dev; struct in_ifaddr *prim = ifa; ... if (ifa->ifa_flags&IFA_F_SECONDARY) { //如果ifa是个sencondary地址,那么就找到它隶属的primary地址后然后以这个primary为主进行设置 prim = inet_ifa_byprefix(in_dev, prefix, mask); if (prim == NULL) { printk(KERN_DEBUG "fib_add_ifaddr: bug: prim == NULL/n"); return; } } fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim); //添加进路由表 ... } 

linux中的网卡配置多ip

Linux 中为同一个物理网卡增加多个 IP 地址,以前通过 ifconfig 命令来创建和维护 IP alias,而在新的 IPROUTE2 中通过 ip address 命令来创建和维护 Primary address 与 Secondary address。

  • 在每一个接口上可以配置多个 Primary 地址和多个 Secondary 地址。
  • 对一个特定的网络掩码(例子中的网络掩码为/24),只能有一个 Primary 地址。

在路由代码中对许多事件和条件作出响应依赖于 IP 地址为 Primary 地址还是 Secondary 地址。下面给一些例子:

  • 当删除一个 Primary 地址时,所有相关的 Secondary 地址也被删除。但通过 /proc 可以配置一个选项(net.ipv4.conf.*.promote_secondaries),在当前 Primary 地址被删除时可以将 Secondary 地址提升为 Primary 地址。
  • 当主机为本地生成的流量选择源 IP 地址时,只考虑 Primary 地址。

原理:

在 Linux 中,一个网卡可以有多个 IP,那么这多个 IP 有什么关系呢?其实这些 IP 组成了一个吊链结构,所谓吊链结构就是一些节点链接 成一条链,然后每个节点带有自己的一条链,如下图所示:

9.png
结构解析:

每个节点代表的 IP 地址标识一个网段,这个节点的 IP 就是这个网段的 Primary 地址,它下面所带的 IP 就是这个网段的 Secondary 地址,也就是说一个网卡可以带有各个节点所带链表长度之和个 IP 地址,而且这些 IP 不是线形的,而是上述的吊链结构。

注意:

  • 只要一个网卡上配置的ip不是一个网段的,那么都是Primary IP,就是吊链结构中上面的那条主链中的IP,linux中的Secondary address是主链结点的子链结点中的IP
  • 吊链在主链上是没有主次的,子链除了第一个节点其它节点也不分主次,都是平行的关系,但是子链中的第一个节点总是 链接在主链中,它们携带的地址就是primary地址,它们下面隶属的子链携带的地址就是这个primary地址的secondary地址
  • 一旦主链上一个节点被删除了,那么它的子链也将不复存在,但是这其实不太合理,因此linux中特意有了一个选项,就是当一个primary地址被删除时,如果它有secondary地址 的话,那么它的第一个secondary地址(长子)继承被删除的primary地址的位置成为primary地址,这样就显得很合理了,要不然在删除 primary地址的时候,如果有程序用secondary地址,那么要么延迟删除,要么程序崩溃,采用自动提升策略的话就不会出现问题。
  • IP aliases,那是以前版本有的了,就是一个实现问题,解决的问题和现在的secondary IP机制一样,它主要就是在物理网卡名字后面加上后缀从而成为虚拟网络接口,本质上和secondary IP机制没有区别,区别就是IP aliases显得不是那么直观,而secondary IP却是真正让应用看到了一个网卡的多个地址,比如你要是用IP aliases的话,有的时候你总是会问eth0:0是什么

linux网卡配置多个 IP 地址时源 IP 的选择

如果一个主机绑定有多个 IP 地址,那么在被动响应和主动发起连接两种方式中,源 IP 地址的选择机制肯定是有所差异的。

主机在接收外部数据包,并发送响应数据包时,响应源地址显然就是客户端请求的地址,这是非常容易理解的,如客户端向主机的 1.1.2.3:80 发起请求,那么主机响应数据包的源 IP 地址一定是 1.1.2.3 。

那么当主机对外主动发起请求时,数据包的源 IP 地址如何选择?

当一个主机创建 IP 数据包时,必须选择正确的源IP地址,这是至关重要的,因为只有源地址正确,才能让接收者正确响应。如果源地址错误,则无法得到对端主机的任何回应。

Linux 选择源 IP 地址使用以下三种机制:

  • 应用程序可以通过 bind(2) 系统调用,应用至 sendmsg(2) 调用上,并通过辅助数据对象 IP_PKTINFO ,从而显式指定源 IP 地址。在这种情况下,操作系统内核仅仅检查其源 IP 地址是否正确,否则产生相应的错误。
  • 如果应用程序没有指定源 IP 地址,包含源 IP 的路由表将决定数据包源 IP 地址,通过设置 ip route 命令的 src 参数,从而指定源 IP 地址。如果路由表没有包含 src 属性,则使用主要 IP 地址。
  • 其它情况下内核搜寻绑定定数据包路由接口上的 IP 地址, IPv6 选择第一个可用的 IP 地址。 IPv4 情况下,尽量选择与目标 IP 处于同一子网的源 IP ,如果目标 IP 与自己的所有 IP 没有处于同一子网,则使用第二种算法。

默认情况下,如果 Linux 的网卡有多个 IP 且位于不同的子网之中,如果数据包目标地址为某个子网中的 IP, 那么对应的与目标同子网的 IP 将会被使用。如果 eth0 有两个 IP 192.168.1.12/24、10.1.1.1/8,那么到 10.0.0.0 子网的数据包的源地址将使用 10.1.1.1。当然可以使用 ip route 的 src 属性指定源址。

总结:

以上两种方式都用来配置VIP,知名的高可用软件:heartbeat是用alias ip的方式,从heartbeat3开始,是用secondary ip,keepalived是用secondary ip的方式。工作中可以灵活的用上面两种方式。

小讯
上一篇 2025-01-24 16:18
下一篇 2025-01-14 21:05

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/18295.html