相信不少兄弟的SDN启蒙都是各种高大上的论文中五花八门的概念和应用,等到真把开源控制器和mininet装好,要开始干活了,才发现什么traffic engineering, 什么consistent update,根本不是那么回事儿。大家要处理的第一个包甚至都不是TCP,而是ARP,而且还是广播!这里有兄弟可能会想到DHCP,LLDP,甚至会想到IPv6的邻居发现,博主会在以后的文章中详细讨论它们,这次只讲ARP。
SDN控制器管理的是由一些交换机(包括OVS和物理交换机)构成的网络而不是网络边缘的服务器(包括bare metal server和vm),但是SDN控制器在proactive的编辑各种表的时候又需要知道服务器在网络当中的位置。ARP几乎成为最好的甚至是唯一的获取这些信息的渠道(IPv6邻居发现是另外一个话题),因为从ARP我们至少可以学到两件事情:第一,每一个mac究竟出现在网络中哪台交换机的哪个端口。第二,每一个mac上究竟有哪些IP地址。
也许有兄弟会问:我们可以通过服务器发出的任何二层或者三层的报文来学到这两件事情,为什么一定是ARP呢?答案有三:首先,既然ARP是每一台服务器发出的几乎第一个报文,我们为什么不直接从这个报文中学到以上的信息呢?既然做proactive的SDN,那就应该在第一时间学习网络中服务器的位置。其次,如果我们的SDN网络连ARP都没有处理好,服务器都没法收到ARP reply,那么也就没有后面的其他报文了。第三,也是最重要的原因:我们其实并不知道网络边缘的服务器是什么设备,它可能是一个一般意义上的服务器,也可能是一个防火墙,或者是一个第三方的路由器。如果我们在SDN网络边缘看到了一个三层的报文,并且简单的认为这个报文的src mac和src IP来自同样一台服务器,那么就错大了。
我们不妨拿传统的交换机和SDN控制器管理的网络做个类比。在传统的交换机上,mac learning是一个非常简单的过程:我在port1上看到了mac1,那么交换机就有了一个二层的表项:到mac1走port1。在SDN的世界里,并没有什么本质的不同:我们在switch1 port1上看到了mac1,那么到mac1就走switch1 port1。唯一的不同是:传统交换机的学习就发生在交换机上。而在SDN的世界里,学习发生在SDN控制器里(有人称之为centralized mac learning),因为控制器一定要知道它管理的这个网络究竟连接了一些什么mac/IP,才能proactive的编辑整个SDN网络的流表。一种比较常见的方式是:交换机把ARP request/reply以packet-in的形式发给控制器,控制器便学习到了mac, vlan, IP, 交换机和端口之间的关系。在开源的floodlight里有一个类似的例子,在所有其他开源的控制器里,也都有类似的例子。
讲到这里,做OpenStack/CloudStack的兄弟们会仰天大笑:太老土了吧,还centralized mac learning?有了orchestration之后,网络中所有vm的一切信息在第一时间已经被控制器知道了!此言不假,但有两个问题:第一,如果有人没有部署orchestration而只用物理服务器怎么办?其实,对于SDN网络而言,orchestration也是某种意义上的mac learning,只不过这个learnning没有通过ARP。
第二个问题则更加重要,无论SDN控制器用何种方式学到mac/IP在网络中的位置,这仅仅是第一步,接下来的问题是:怎样回复服务器发出的ARP request? 这个问题是SDN系统设计的一个挑战,并且这个挑战会随着系统feature的不断丰富,一次又一次的出现。接下来博主主要会从L2和L3两个方面分析一下这个问题可能的解法,欢迎大家查漏补缺。
如果source和destination处于一个subnet,这是一个纯二层的问题。有两种极端的解法。
极端解法一:让SDN控制器回复所有的ARP request。既然SDN控制器已经通过orchestration或者ARP packet-in的方式学习到了网络中的mac,那么只要将所有ARP request都以packet-in的形式发送到控制器,控制器就完全有能力将ARP reply通过packet-out的方式回复给source。
这种极端做法显而易见的缺点是:过多的ARP request会让SDN控制器应接不暇,成为潜在的安全隐患。于是,不少SDN厂家在这种方案的基础上进行了改进,一种改进的思路是:既然控制器上有一个大表记录着网络中所有IP到mac的映射,那么我们就可以在所有网络边缘交换机上把这个表cache下来,这样,当交换机再次收到ARP request的时候,就可以通过查找这个表直接回复相应的ARP reply,而不需要广播。
以上这个改进确实是个可行的方案,但是有两个前提:1)用户不在乎高可靠性(high availability),2)一定要部署在有orchestration的环境当中。但这两个大大的前提往往会让相当一部分客户止步。首先如果source和destination都好好的,但是SDN控制器宕了,于是最基本的ARP便无法正常工作,这是一件让任何客户都很难接受的事情。其次,在没有orchestration的环境当中,有些服务器是不主动说话的(silent server),也就是说在silent server发出第一个ARP之前,控制器根本没有机会得知它的存在。在这种情况下,SDN网络必须要能够正确的广播ARP request,当SDN网络收到silent server的ARP reply之后,还要能够正确的将其转发。
极端解法二:在一个广播域中广播ARP request。既然极端解法一并不适用于所有的情形,那么我们便很自然的想到了另外一个极端解法,索性广播ARP request吧,该谁回复ARP reply就让谁回复。这样做有几个好处,首先是SDN网络中ARP的行为和传统二层交换中ARP的行为是一致的。客户在destination打开tcpdump会看到ARP request。而在之前的方案中,destination是看不到ARP request的。单就这一点,在向客户解释说明的时候就省了好多事。第二个好处是即便控制器宕了,只要source和destination还在,ARP就能工作。第三个好处是这个方案解决了silent server的问题,只要广播处理的正确,silent server就能够收到ARP request并回复ARP reply。
当然这个方案的代价也很大,就是要正确的处理广播。如果仅仅是二层网络,我们可以用spanning tree,用SDN控制器计算spanning tree是一件麻烦但能够做到的事情。如果是二层被三层隔离,就需要打隧道了。以vxlan为例,最初vxlan要求在underlay网络中部署IP multicast来处理ARP,没有人愿意,于是才有了后来的unicast-only vxlan。
博主把极端解法二称为“种树”:从本质上来讲,SDN控制器其实在为每一个广播域种一棵没有环的树,好让ARP在这棵树上广播。如何高效的“种树”是真正体现各个厂家硬实力的地方,不管是用spanning tree在二层种树,打隧道在三层种树还是其他方法,这棵树都必须要做到:无论任何网络拓扑或者任何网络事件,有且只有一个广播报文到达广播域中的各个服务器。
分析到这里,博主已经把当source和destination在一个subnet时,处理ARP的种种考虑走马观花的讨论了一遍。博主才疏学浅,但在博主知识范围内的ARP解决方案基本就是在以上两个极端之间找一个折中并做一定的创新。
讨论完source和destination处于同一个subnet的情况,我们来看一下两者处于不同subnet的情况,这时我们需要考虑两个问题。
问题一:谁是default gateway?
传统网络中,二层三层的界限往往非常清晰,二三层分界的地方就是default gateway所在的地方。但在seamless vm migration大行其道的今天,二层三层的界限越来越模糊,我们已经很难明确的指出default gateway在网络当中的位置了,于是常听人们感叹:default gateway is everywhere。博主见识有限,到目前为止见到的default gateway大体上会出现在三个地方。
第一种情形是网络中有一个专门的router(可能是硬件也可能是OVS)来做default gateway,这种情形常出现在overlay的解决方案中,比如Juno release之前的neutron reference implementation,比如vxlan L3 gateway。有客户担心这种方案的高可靠性,于是人们又在这种方案之上加入了VRRP。
第二种情形是default gateway在SDN控制器上。有些开源的SDN控制器就在采用这种方式。一种常见的逻辑是这样的:source发出了ARP request问default gateway的mac,交换机把这个ARP request以packet-in的形式告诉控制器,控制器再以packet-out的形式把ARP reply发给source,于是source就知道了default gateway的mac。我知道有兄弟会说:这样控制器不又成了单点故障和bottleneck了吗?所以人们在此基础之上进行了改进,发明了第三种部署default gateway的方式。
这第三种方式就是把default gateway部署在所有的网络边缘的交换机上,有人称之为destributed default gateway。在情形二中,SDN控制器已经掌握了所有subnet的default gateway,我们完全可以把这个信息以某种方式cache/offload到所有的网络边缘的交换机上。这样,这些交换机就可以代替控制器回复所有要default gateway mac的ARP request。
在以上三种方案中,方案一目前来说最常见。方案三在被越来越多的人接受,因为它的优势实在太明显了。
问题二:如何处理silent server?
如果没有部署任何的orchestration system,如果网络中还有大量的bare metal server,那么silent server带来的问题就不容忽视。我们设想一下下面这个场景:source和destination处在不同的subnet,并且destination是一个silent server。如果source向destination发了一个ping echo request,由于SDN控制器对destination一无所知,所以网络中不会有关于destination的任何表项,于是这个echo request被很自然的packet-in到了控制器,此时的控制器又能对这个packet-in做什么呢?
博主目前还没有看到任何关于这个问题的公开讨论。一个最鲁莽的办法就是控制器以packet-out的方式在SDN网络边缘的所有端口上发ARP request,要destination IP所对应的mac。如果destination真的接入了我们的网络,便会回复ARP reply,那时控制器便会学习到destination连接在哪台交换机的哪个端口,相应的表项便会得到更新。只是这样一个鲁莽的方法代价太大了。如果哪位兄弟有更好的办法,欢迎提出来大家一起讨论。
讲到这里,博主已经把SDN系统设计中关于ARP的考量梳理了一遍。不过ARP不会就此罢休。在以后的文章中,博主还会讨论到NAT和floating IP,到那时,ARP会卷土重来,给我们制造更多的麻烦。