日期:2014-05-16  浏览次数:20798 次

从ip addr add和ifconfig的区别看linux网卡ip地址的结构

转至:http://blog.csdn.net/dog250/article/details/5303542

今天一个老外在邮件列表上问了一个问题,就是ip addr add和ifconfig的区别,我给他进行了解答,可能因为英语不好吧,解答的很简单,因此我还是要在这里详细说明一下。其实它们之间没有什么区别,只 是表述方式不同罢了。如果你非常理解网络协议的原理以及网络的分层架构那么我想你就不会有这个问题,实际上,每一个网卡设备都有一个mac地址,但是却可 以有多个网络层地址,比如IP地址,然而这个事实无法很好地像用户提供操作接口,所以就引出了ip别名(IP aliases)和辅助ip(secondary IP addresses)的概念。其实很容易理解这个事实,按照分层的思想,下层总是为上层服务,也就是为上层提供舞台,上层利用下层的服务,而不必让下层知 道自己的情况,如果一个拥有合理mac地址的网卡没有配置网络层地址(比如IP地址)这件事合理的话,那么为这个设备配置多个IP地址也是合理的,正好像 一个ip可以对应多个应用层端口一样,也就是说,下层对上层总是一对多的关系,在分层架构中这种关系是合理的。下面我们就看一下linux的网卡的ip地 址结构。刚才说了在linux中,一个网卡可以有多个IP,那么这多个ip有什么关系呢?其实这些ip组成了一个吊链结构,所谓吊链结构就是一些节点链接 成一条链,然后每个节点带有自己的一条链,如下图所示:
clip_image001 clip_image002 clip_image003 clip_image004
每 个节点代表的ip地址标识一个网段,这个节点的ip就是这个网段的 Primary地址,它下面所带的ip就是这个网段的Secondary地址,也就是说一个网卡可以带有各个节点所带链表长度之和个ip地址,而且这些 ip不是线形的,而是上述的吊链结构。我们看一下这么做有什么好处。玩过Cisco路由器的朋友可能都知道有个Secondary IP的概念,这个特性可以创建逻辑子网,也就是说在一个物理网口上连接两个子网,这咋看起来好像不可思议,其实很简单,比如这个网口接到一台交换机上,如 果这个网口没有配置Secondary IP的话,那么这台交换机只能连接一个网段的主机,比如192.168.1.1/24,但是,如果它配置了Secondary IP,那么就可以连接两个网段的主机,比如192.168.1.1/24和10.0.0.1/24,道理就是这么简单,但是却很有用,该机制可以被路由汇 总策略所使用。注意上面这个例子中的Secondary IP不是这里说的linux的Secondary address,在linux中恰恰相反,只要一个网卡上配置的ip不是一个网段的,那么都是Primary IP,就是吊链结构中上面的那条主链中的IP,linux中的Secondary address是主链结点的子链结点中的IP,这一点一定注意,概念是不能混淆的。前面说的只是吊链中主链的作用,那么子链呢?其实想象一下也很简单,比 如一台机器上运行着一个代理服务器或者负载均衡服务,代理服务器或者负载均衡服务和主服务器要监听相同的端口,那么就可以用secondary address来解决了,只要需要在同一网段监听同一个端口的应用都是吊链中子链存在的原因,因此可以说,主链对外部或者说对下面链路层虚拟了多块网卡, 而子链向上层虚拟了多台机器,配置了吊链结构的linux主机如果说只有一块网卡,那么外部会认为它有多块网卡,对于内部,应用层会认为彼此在不同的主机 上,这就是效果。
除了上面大体的介绍之外,还有很多细节,吊链在主链上是没有主次的,子链除了第一个节点其它节点也不分主次,都是平行 的关系,但是子链中的第一个节点总是 链接在主链中,它们携带的地址就是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是什么?我就曾经在内核里面拼命找eth0:0这个网络设备的注册代码,都要疯掉了也没有找到,其实 我并不是很傻,但是我却因为那个该死的名字作出了傻事。
下面就可以看看linux内核的实现代码了,首先弄明白一些数据结构,最重要的就是net_device,其次就是in_device,然后就是in_ifaddr,明白了这三个数据结构,一切就明白了,这是真的。
struct net_device
{
...
???? void??????????????????? *ip_ptr;?????? //指向一个in_device结构,这个字段从net_device中分离表明一个网卡可以支持多种网络层协议的
...
}
struct in_device
{
???????? struct net_device?????? *dev;?????????? //指向它隶属的net_device,也就是网卡
???????? atomic_t??????????????? refcnt;???????? //引用计数
???????? int???????????????????? dead;
???????? struct in_ifaddr??????? *ifa_list;????? //所有的ip地址链表
...
};
struct in_ifaddr?? //代表一个ip地址
{
???????? struct in_ifaddr??????? *ifa_next;?????? //上面的in_device中的ifa_list字段就是靠这个字段连成链的
???????? struct in_device??????? *ifa_dev;??????? //回指in_device结构
???????? struct rcu_head???????? rcu_head;
???????? u32???????????????????? ifa_local;?????? //ip地址
???????? u32???????????????????? ifa_address;
???????? u32???????????????????? ifa_mask;??????? //掩码
???????? u32???????????????????? ifa_broadcast;?? //广播地址
???????