Linux的网卡驱动中内含了好多“虚拟网卡”。先前的文章以前详尽剖析过tun,ifb等虚拟网卡,类似的思路,在虚拟化大行其道的趋势下,Linux源码树中不断降低对“网络虚拟化”的支持,不光是为了支持“虚拟机”技术,更多的是给了用户和程序员更多的选择。
这种对网路虚拟化的支持技术包括任何重量级的虚拟化技术,比较重的诸如对虚拟机技术的支持,轻量级的则是netnamespace技术。近日的工作基于netnamespace技术,关于这个技术我也不多说了,它主要是提供了每位namespace独立的合同栈以及网卡,对于网路合同栈以及网卡之外的部份,所有namespace是共享的,这些轻量级的针对网路的虚拟化技术对于模拟多顾客端网路联接非常有用并且操作简单。我会单独写一篇文章来展示这些操作。
假如仅仅为了完成工作,这么我不会写这篇文章,早在今年的时侯,我写过一篇关于netnamespace的,按照那种上面的stepbystep,工作就早已可以完成了,但是在今年年底到明年年初,这个工作我们也早已做过了,但是对于学习而言,就不是这样了。学习应当是遇到一点折腾一点,我晓得,好多人都晓得,如今不比念书那会儿了,我们谁都没有整块的时间系统地进行学习,非常是对于我这些结了婚有了儿子,须要为了还房贷而不再任性的路人丙来讲,更是这样。因而就须要对所见到的技术有一种可遇而不可求的相见恨晚的觉得红帽子linux,这样就有动力把它吃透了。
本文中,我想通过几张图来介绍一下Linux中常用的几类和网路虚拟化相关的虚拟网卡,其实,这种虚拟网卡的使用场景并除了限于netnamespace,重量级的虚拟机也可以使用,之所以用netnamespace举例是由于它的简单性。总体来说,这种虚拟网卡的原理就摆在哪里,具体在哪些场景下使用它们,就看你自己的想像力了。
网路虚拟化
总体来讲,所谓的网路虚拟化在本文食指的是主机中的网路虚拟化,着重于在一台数学主机中,分离出多个TCP/IP合同栈的意思。网路虚拟化可以独立实现,也可以依托别的技术实现。在Linux中,独立的网路虚拟化实现就是netnamespace技术,依托别的技术实现的网路虚拟化就是虚拟机技术,我们其实晓得,每位虚拟机上面都有自己的合同栈,而这些依托虚拟机技术实现的网路虚拟化可能还要更简单一些,由于宿主机并不须要去“实现”一个合同栈,而是把这个任务交给了虚拟机的操作系统来完成,宿主机“相信”虚拟机上面一定运行着一个拥有合同栈的操作系统。
理解虚拟网卡的精义
你要晓得,一块网卡就是一道门,一个插口,它里面通常接合同栈,下边通常接介质。最关键的是,你要明晰它们确实在前面和下边接的是哪些。
因为网卡的上插口在OS中实现,或则使用PF技术在用户态实现,总而言之,它们是软的,这就意味着你可以任意实现它们。反之,下插口便不受机器运行软件的控制了,你没法通过软件改变双绞线的事实,不是吗?甚或,我们通常关注网卡下边接的是哪些,是哪些呢?暂且将它称作endpoint吧。在开始正文之前,我先列出几个常见的endpoint:
以太网ETHx:普通双绞线或则光纤;
TUN/TAP:用户可以用文件句柄操作的字符设备;
IFB:一次到原始网卡的重定向操作;
VETH:触发虚拟网卡对儿peer的RX;
VTI:加密引擎;
...
关于数据在寄主网卡和虚拟网卡之间的路由(广义的路由),有好多形式,在初期的内核中,对bridge(Linux的bridge也算是一种虚拟网卡)的支持是靠一个在netif_receive_skb中硬编码调用的一个br_handle_frame_hook钩子来实现的,这个钩子由bridge模块注册。并且随着虚拟网卡种类的越来越多,总不能每一种都硬编码如此一种钩子,这样会促使netif_receive_skb变得太臃肿,因而一种新的方法被提出来了,事实上很简单,就是将这些钩子向下具象了一层,不再硬编码,而是统一在netif_receive_skb中调用惟一的一个rx_handler的钩子。具体怎么设置这些钩子,就看这个寄主网卡须要绑定哪种类型的虚拟网卡了,例如:
对于bridge:调用netdev_rx_handler_register(dev,br_handle_frame,p),在netif_receive_skb中调用的是br_handle_frame;
对于bonding:调用netdev_rx_handler_register(slave_dev,bond_handle_frame,new_slave),在netif_receive_skb中调用的是bond_handle_frame;
对于MACVLAN:调用netdev_rx_handler_register(dev,macvlan_handle_frame,port),在netif_receive_skb中调用的是macvlan_handle_frame;
对于IPVLAN:调用netdev_rx_handler_register(dev,ipvlan_handle_frame,port),在netif_receive_skb中调用的是ipvlan_handle_frame;
对于...
每一块寄主网卡只能注册一个rx_handler,然而网卡和网卡却可以叠加。
VETH虚拟网卡技术
关于这个虚拟网卡,我在《
OpenVPN多处理之-netns容器与iptablesCLUSTER
》中有提及过,每一个VETH网卡都是一对儿以太网卡,不仅xmit插口与常规的以太网卡驱动不同之外,其它的几乎就是一块标准的以太网卡。VETH网卡既然是一对儿两个,这么我们把一块叫做另一块的peer,标准上也是如此讲的。其xmit的实现就是:将数据发送到其peer,触发其peer的RX。这么问题来了,这种数据怎么发送到VETH网卡对儿之外呢?自问必有自答,自答如下:
1.假如确实须要将数据发到外部,通过将一块VETH网卡和一块普通ETHx网卡进行bridge,通过bridge逻辑将数据forward到ETHx,因而发出;
2.莫非非要把数据包发往外部吗?类似loopback那样的,不就是自发自收吗?使用VETH可以很方面但是隐秘地将数据包从一个netnamespace发送到同一台机器的另一个netnamespace,但是不被嗅探到。
VETH虚拟网卡十分之简单,原理图如下所示:
VETH使用原始淳朴的形式联接了不同的netnamespace,符合UNIX的风格,因而你须要动用好多别的技术或则工具来完成netnamespace的隔离以及数据的发送。
MACVLAN虚拟网卡技术
MACVLAN技术堪称是提出一种将一块以太网卡虚拟成多块以太网卡的极简单的方案。一块以太网卡须要有一个MAC地址,这就是以太网卡的核心中的核心。
往年,我们只能为一块以太网卡添加多个IP地址arm linux,却不能添加多个MAC地址,由于MAC地址正是通过其全球惟一性来标示一块以太网卡的,即使你使用了创建ethx:y这样的方法,你会发觉所有那些“网卡”的MAC地址和ethx都是一样的,本质上,它们还是一块网卡,这将限制你做好多二层的操作。有了MACVLAN技术,你可以如此做了。
我们先来看一下MACVLAN技术的流程示意图:
在具体的执行上,通过下边的命令linux 网卡虚拟化命令,你可以创建一个MACVLAN网卡,它是基于eth0虚拟下来的:
iplinkaddlinketh0namemacv1typemacvlan
你可以觉得有人将双绞线“物理上”每根一分为二,接了两个水晶头,因而联接了两块网卡,其中一块是虚拟的MACVLAN网卡。而且既然共享介质,莫非不用运行CSMA/CD吗?其实不用,由于事实上,最终的数据是通过eth0发出的,而现代的以太网卡工作的全双工模式,只要是交换式全双工(个别标准而言,这是必须的),eth0自己能做好。
如今可以说一下MACVLAN技术建立的虚拟网卡的模式了。之所以MACVLAN拥有所谓的模式,是由于相比VETH,它更是将复杂性构建在了一个早已容不下哪些的以太网概念上,因而互相交互的元素都会太多,它们之间的关系不同,造成最终MACVLAN的行为不同。还是图解的形式:
1.bridge模式
这个bridge只是针对同属于一块寄主以太网卡的MACVLAN网卡以及寄主网卡之间的通讯行为的,与外部通讯无关。所谓的bridge指的是在这种网卡之间,数据流可以实现直接转发,不须要外部的协助,这有点类似于LinuxBOX内建了一个bridge,即用brctl命令所做的那一切。
2.VEPA模式
VEPA模式我旁边会专门讲。如今要晓得的是,在VEPA模式下,即便是MACVLANeth1和MACVLANeth2同时配在在eth0上,它们三者之间的通讯也不能直接进行,而必须通过与eth0相连的外部的交换机协助,这一般是一个支持“发夹弯”转发的交换机。
3.private模式
这些private模式的隔离硬度比VEPA更强。在private模式下,即便是MACVLANeth1和MACVLANeth2同时配在在eth0上,eth0联接了外部交换机S,S支持“发夹弯”转发模式,尽管这样,MACVLANeth1的广播/多播流量也未能抵达MACVLANeth2,反之亦然,之所以隔离广播流量,是由于以太网是基于广播的,隔离了广播,以太网将丧失了依托。
假如你想配置MACVLAN的模式,请在iplink命令前面添加mode参数:
iplinkaddlinketh0namemacv1typemacvlanmodebridge|vepa|private
VETH网卡与MACVLAN网卡之间的优缺
我们先看一下怎样配置一个独立的netnamespace。
1.VETH形式
ipnetnsaddns1
iplinkaddv1typevethpeernameveth1
iplinksetv1netnsns1
brctladdbrbr0
brctladdifbr0eth0
brctladdifbr0veth1
ifconfigbr0192.168.0.1/16
2.MACVLAN形式
iplinkaddlinketh0namemacv1typemacvlan
iplinksetmacv1netnsns1
可以看见,MACVLAN做起同样的事,比VETH来的简单了。这么效率呢?Linux的bridge基于软件实现,须要不断查找hash表,这个同样也是MACVLANbridge模式的做法,并且VEPA模式和private模式下,都是直接转发的。它们的区别可以从右图展示下来:
VEPA技术
VEPA是哪些?VirtualEthernetPortAggregator。它是HP在虚拟化支持领域对抗Cisco的VN-Tag的技术。所以说,Cisco的VN-Tag和VEPA致力解决同一个问题或则说同一类问题。解决的是哪些问题呢?浅显点说,就是虚拟机之间网路通讯的问题,非常是坐落同一个宿主机内的虚拟机之间的网路通讯问题。
莫非这个问题没有解决吗?我使用的VMWare可以在我的PC中创建多个虚拟机,虽然我拔除我的PC机网线,这种虚拟机之间也能通信...VMWare内部有一个vSwitch。就是说,几乎所有的虚拟机技术,外置的交叉网路都能解决虚拟机之间的通讯问题。这么还要VN-Tag以及VEPA干哪些?
这个问题涉及到两个领域,一个是扩充性问题,另一个是职责边界问题。说明小白点就是,外置的vSwitch之类的东西在性能和功能上足以满足要求吗?它属于虚拟机软件厂商的边沿产品,甚至说不是一个独立的产品,它通常都是附属虚拟机软件附赠的,没有自己的销售赢利模式,虚拟机厂商之所以外置它是由于它只是为了让用户体验到虚拟机之间“有相互通信的能力”,所以厂商是不会加码将这些外置的虚拟交换机或则虚拟路由器做完美的,它们推的是虚拟机软件本身。
另外,千百年来,网路管理员和系统管理员之间的职责边界是清晰的,直至抵达了虚拟化时代。假如使用外置的虚拟交换机,这么假如这个交换机出了故障或则有复杂的配置任务计划,找谁呢?要晓得这个虚拟交换机外置于寄主服务器内部,这是系统管理员的领域,通常的网管设置未能触摸到这种设备,数据中心复杂的四权分立管理模式也未能让网管去登陆服务器。反过来,系统管理员对网路合同的认知程度又远远比不上专业网管。这就引起了外置于虚拟机软件的虚拟网路设备的难堪境遇。另一方面,这个虚拟的网路设备确实不是很专业的网路设备。爆燃!
Cisco不愧为网路界的大咖。它总是在出现这些难堪场景的时侯率先提出一个标准linux 网卡虚拟化命令,于是它改建了以太网合同,推出了VN-Tag,如同ISL之于IEEE802.1q那样。VN-Tag在标准的合同头中降低了一个全新的数组,这些做法的前提是Cisco有能力用最快的速率推出一款设备并让其真正跑上去。在瞧瞧HP的还击,HP没有Cisco那样的能力,它不会去更改合同头,而且它可以更改合同的行为因而解决问题,尽管比Cisco晚了一步,然而HP提出的VEPA不愧是一种愈发开放的形式,Linux可以很容易的降低对其的支持。
VEPA,它很简单,一个数据包从一个交换机的一个网口步入,之后从同一个网口发回来,似乎是毫无意义的做法,并且它却没有改变以太网的合同头。这些做法在平时看来真的是毫无意义的,由于正常来讲,一块网卡联接一根网线,倘若是自己发给自己的数据,这么这个数据是不会抵达网卡的,对于Linux而言,直接就被loopback给bypass了。并且对于虚拟化场景而言,情况就有所不同了,尽管数学宿主机上可能拥有一块以太网卡,并且从该网卡发出的数据包却不一定来自同一个合同栈,它可能来自不同的虚拟机或则不同的netnamespace(仅针对Linux),由于在支持虚拟化OS的内部,一块化学网卡被虚拟成了多块虚拟网卡,每一块虚拟网卡属于一个虚拟机...此时,倘若不更改以太网合同头且又没有外置的虚拟交换机,就须要外部的一台交换机来协助转发,典型的就是从一个交换口收到数据包,把它从该口再发出去,由寄主网卡决定是否接收以及怎样接收。如右图所示:
对于以太网卡而言,硬件上根本就不须要任何更改,软件驱动更改即可,对于交换机而言,须要更改的极少,只要在MAC/Port映射表查询失败的情况下,将数据包广播到包括入口的所有端口即可,对于STP合同,也是类似的更改。对于HP而言,发出VEPA是一个正确的选择,由于它不像Cisco和Intel那样,可以大量生产网卡和设备,因而控制硬件标准。对于支持VEPA的交换机而言,仅仅须要支持一种“发夹弯”的模式就可以了。爆燃!
IPVLAN虚拟网卡技术
这个小节我们来看下IPVLAN。在理解了MACVLAN以后,理解IPVLAN就非常容易了。IPVLAN和MACVLAN的区别在于它在IP层进行流量分离而不是基于MAC地址,因而,你可以听到,同属于一块寄主以太网卡的所有IPVLAN虚拟网卡的MAC地址都是一样的,由于寄主以太网卡根本不是用MAC地址来分流IPVLAN虚拟网卡的流量的。具体的流程如右图所示:
IPVLAN的创建命令如下:
iplinkaddlinktypeipvlanmode{l2|L3}
将一个IPVLAN虚拟网卡装入一个独立的netnamespace的方法和MACVLAN完全一样,而且它俩之间改怎么做出选择呢?好在IPVLAN有Linux源码树上的Document,因而我就不多嘴了:
4.1L2mode:InthismodeTXprocessinghappensonthestackinstanceattachedtotheslavedeviceandpacketsareswitchedandqueuedtothemasterdevicetosendout.InthismodetheslaveswillRX/TXmulticastandbroadcast(ifapplicable)aswell.
4.2L3mode:InthismodeTXprocessinguptoL3happensonthestackinstanceattachedtotheslavedeviceandpacketsareswitchedtothestackinstanceofthemasterdevicefortheL2processingandroutingfromthatinstancewillbeusedbeforepacketsarequeuedontheoutbounddevice.Inthismodetheslaveswillnotreceivenorcansendmulticast/broadcasttraffic.
5.Whattochoose(macvlanvs.ipvlan)?Thesetwodevicesareverysimilarinmanyregardsandthespecificusecasecouldverywelldefinewhichdevicetochoose.ifoneofthefollowingsituationsdefinesyourusecasethenyoucanchoosetouseipvlan-(a)TheLinuxhostthatisconnectedtotheexternalswitch/routerhaspolicyconfiguredthatallowsonlyonemacperport.(b)NoofvirtualdevicescreatedonamasterexceedthemaccapacityandputstheNICinpromiscousmodeanddegradedperformanceisaconcern.(c)Iftheslavedeviceistobeputintothehostile/untrustednetworknamespacewhereL2ontheslavecouldbechanged/misused.
MACVTAP虚拟网卡技术
这是本文提到的最后一种虚拟网卡。为何会有这些虚拟网卡呢?我们还是从问题说起。
假如一个用户态实现的虚拟机或则模拟器,它在运行OS的时侯,如何模拟网卡呢?或则说我们实现了一个用户态的合同栈,和内核合同栈完全独立,你可以把它们想像成两个netnamespace,此时怎样把数学网卡的流量路由到用户态呢?或则反过来,怎样将用户态合同栈发出的数据路由到BOX外部呢?依照常规的看法,我们晓得TAP网卡的endpoint是一个用户态可访问的字符设备,OpenVPN使用的就是它,好多轻量级用户态合同栈也有用到它,我们会给出下边的方案:
又要用到“万能的bridge”。这是多么的麻烦,这是多么的悲哀。
正如MACVLAN取代VETH+Bridge一样,稍稍该一下的MACVLAN也能代替TAP+Bridge,很简单,那就是将rx_handler实现更改一下,寄主以太网卡收到包然后,不交给MACVLAN的虚拟网卡上插口联接的合同栈,而是发到一个字符设备队列。很简单吧,这就是MACVTAP!
遗憾的多队列TUN/TAP虚拟网卡技术
这是老湿在2014年的时侯做的,虽然只是做了一些移植和更改工作。并且发觉有了MACVTAP以后,我的这个版本顿时就被爆了。遗憾!向之所欣,俯仰之间,已为陈迹。