最近使用docker,涉及到需要跨多台物理机部署系统,查了好多资料,最后查到了ipvlan。那什么是vlan,什么又是ipvlan。
交换机层面的vlan,是按802.1Q规范,在链路层中加了4字节的标识vlan的数据,交换机根据接口的类型,pid以及vlan的id,来判断是否需要转发此数据包,最终实现了不同vlan的广播包的隔离。
ipvlan不涉及802.1Q协议,是基于linux的ipvlan驱动实现的,其原理是在一台物理机上,可以创建多个虚拟网络设备,这些设备拥有相同的mac地址。如下图所示:
物理机computer1,其网卡eth0 ip地址是192.168.1.2,mac是00-50-56-C0-00-08。其中包含两个ipvlan设备,ip是192.168.2.2和192.168.2.3,网段与物理机不同,但其与物理机共用同一个mac。
先说下结论,物理机1中的192.168.2.2可以与物理机2中的192.168.2.4通信。下面以l2模式192.168.2.2向192.168.2.4发送arp包,说下具体的通信过程。
- 重要的数据结构
每一个ipvlan设备,都有对应的net_device和ipvl_dev。
主设备(net_device *phy_dev)是ipvlan_link_new方法中tb[IFLA_LINK]指定的序号的设备,主设备带有IFF_IPVLAN_MASTER标记,而子设备带有IFF_IPVLAN_SLAVE标记。
调用register_netdevice注册设备时,会调用ipvlan_init,如果主设备还未打上IFF_IPVLAN_MASTER标记,会执行ipvlan_port_create创建ipvl_port,并给主设备打IFF_IPVLAN_MASTER标记。ipvl_port是用于同一个主设备的所有设备共享的,子设备会连接到ipvl_port的ipvlans链表上。
- 数据离开物理机1
数据发送方法是ipvlan_start_xmit->ipvlan_queue_xmit->ipvlan_xmit_mode_l2。
在ipvlan_xmit_mode_l2中,通过源mac和目的mac,来判断是否是目的地址是本机的包。
ether_addr_equal(eth->h_dest, eth->h_source)
arp包目的mac地址是ff-ff-ff-ff-ff-ff,与物理机1mac地址不相同,调用dev_queue_xmit,最终将包通过物理网卡eth0发送出去。广播包的格式如下:
00-50-56-C0-00-08 (oui Unknown) > Broadcast, ethertype ARP (0x0806), length 42: Request who-has 192.168.2.4 tell 192.168.2.2, length 28
- 数据包进入物理机2
网络设备开启时,执行ipvlan_addr4_event->ipvlan_add_addr4->ipvlan_add_addr,将ip地址添加到port->hlhead和ipvlan->addrs上。
广播包会被同网段(交换机未划vlan的情况下)的所有物理机收到。ipvlan接收处理流程如下:
ipvlan_handle_frame->ipvlan_handle_mode_l2。
在ipvlan_handle_mode_l2中通过ipvlan_get_L3_hdr获取arp头,arp头中包含目的ip。再通过ipvlan_addr_lookup查找到目的ipvlan设备,数据包交给ipvlan_rcv_frame处理。
ipvlan_rcv_frame中调用ipvlan_skb_crossing_ns将数据包的目的网络设备更改为拥有192.168.2.4ip地址的ipvlan设备,数据最终到达192.168.2.4对应的网络设备。
ipvlan_skb_crossing_ns(skb, dev);
- arp回包
arp的回复包,由 192.168.2.4发送,目的mac地址为物理机1 eth0的mac地址,数据离开物理机2,进入物理机1,最终到达192.168.2.2,与上面的过程类似,就不再赘述了。