好久不见,网课还上的快乐吗( 又咕咕了好久呢,这次来写写关于networking的事。前些时日注册了自己的ASN,我也成为了能在公网上漏油的one man NOC了呐。然而由于贫穷我的上游只有Vultr和HE,在公网BGP上并没有很大的操作空间,虽然收了全表,但是import none,because why not?故而工作的重心更多的放在了overlay network上。现有的overlay network方案其实非常多,从tinc、zerotier到weave,还有新的nebula,他们都有着先进的控制平面,为使用者带来了极大的便利,但是也都存在着各自的问题。先从共性问题而言,他们大多提供的是二层转发,从使用的便利性而言,大二层确实很快乐,但在大规模的overlay network中,二层有着严重的scalability issue,同时也难以优化路由。各自而言,首先是tinc,tinc作为一个历史悠久的项目,长期支撑着tuna内部某个申必网络的运作,打洞、自发现、加密,tinc拥有可以想到的各种feature,然而它的转发平面性能一言难尽。再说zerotier,单就运作模式而言,zt更加接近SDN的意义,一个中心化的控制平面,但它的性能更糟糕....weave是一个奇妙的选择,它的原意是container networking,但也可以在host machine之间提供连接,虽然工作在用户态,他会使用内核中的Open vSwitch Datapath加速包转发,并使用IPSec加密,听上去是一个never reinvent the wheel的优秀方案呢。在实际的实验中,他也确实表现出了非常优异的包转发性能。但是!我没能找到一个关闭weave的二层转发的方式,更令人失望的是当需要转发时他会fallback到用户态转发。综上所述,我们的实际需求是:一个三层的隧道(既然不需要二层我们也没有理由承担ethernet头带来的额外overhead),同tinc一样,我们也希望能继续使用公钥体系加密,避免PSK带来的隐患,我们也希望他是一个内核态的隧道,来获得较优的转发性能。
A.K.A. wireguard。I'm limited by the technology of my time。满足这所有需求的,似乎就只有wireguard了。当然wireguard也不是一个完美的方案,它最大的问题有两点,首先是AllowedIP的机制,使得它几乎不可能与routing daemon妥善共存,另外一点则是sticky socket,这本是一个feature,但也导致wireguard所使用的UDP socket无法绑定至特定源地址,限制了他在具有多个上游的节点或是双栈节点上的使用。对于AllowedIP,解决方法虽说不漂亮,但是it works(,将它作为peer to peer的隧道使用,AllowedIP = ANY即可,(会有114514个interface就是了)(塞在netns里不就好了)。而对于bind to IP的问题,WIP。Update: wireguard-bind,提供了一个可以绑定至指定ip的wireguard实现,在rait中也已添加了相关支持。
wireguard作为一个全新的项目,相关的轮子也不多,有几个自动组网的,但都是单interface的架构,不曾考虑到与routing daemon的结合,故而我不得不造了个新轮子:RAIT,确保了link scope的通联,而对于site scope的通联性则是选择了babel作为路由协定,以从RTT的角度优化网络路径。netns的使用被证明是一个优秀的决定,每个节点的维护者往往会构建自己的路由策略,在以往的网络中,每个节点的网络栈同时又是整个cluster的转发平面,路由策略也会影响到整张网络,而netns的使用确保了一个不受干扰的转发平面,大大提升了网络的可靠性。在接下来的工作上,首先为wireguard添加bind to IP的支持自然是重点,同时在scalability上,目前的架构是由babel同时承担了内部与外部路由的广播,并不可取,故而与BGP的整合也值得探索。