从光纤通道卡中侵入以太网

2020-09-09 22:57:02

这个故事,就像过去的另一个故事一样,是从易趣购买开始的,我很快就会后悔。当我浏览我最喜欢的易趣供应商时,我发现了一个名为Job Lot的列表,上面有大约350种不同的网卡。这当然激起了我的兴趣。一些近距离的照片检查发现,这堆卡片里有一整堆卡片,价值相当于整批卡片的价格。所以我很自然地买了它。

我没有想到的是,“大约350”是很多东西。然而,由于一辆托盘卡车出现在我在伦敦的公寓,这一点很快就变得明显起来。

在处理了将托盘放入我的公寓本身这一略显尴尬的后勤挑战后,我开始对卡进行分类,发现自己有很多两种类型的卡,4x 1G Intel i20卡,以及来自QLogic(现在的Marvell)和Emulex(现在的Broadcom)的大量8G光纤通道卡。我的光纤通道PCIe卡数量不合理。

光纤通道(FC)用于通过与普通以太网不同的结构高效地将系统连接到远程存储。让它有点混乱的是,对于未受过训练的人来说,它们可能会与10G以太网混淆,因为它们都采用SFP+光模块。

在做了一些研究之后,似乎在FC的历史中确实存在对通过FC承载IP流量的支持,因此系统可能只能与FC连接。

有3个RFC涵盖了这一点,RFC2625(涵盖基础知识),RFC3831(添加IPv6支持),以及RFC4338对两者的最终更新。

看起来这项功能实际上从未真正达到完全支持的程度。IPoFC支持曾经存在于QLogic驱动程序中,但后来被删除了,这里是一次公开尝试,试图将该功能恢复到QLogic驱动程序中,并取得了一定程度的成功,只是没有稳定性或现代设备支持。

肯定有办法让这些卡发挥一些作用吧?既然我有这么多,我想试着给它们注入新的活力不会有什么坏处。

因此,我抓起两台测试机,在其中安装了一个单端口QLogic卡,并用OM3电缆将它们连接起来。

默认情况下,FC主机总线适配器(HBA)正在查找要与其建立会话的目标(通常是存储区域网络(SAN))。因此,虽然将两台机器连接在一起会打开链路,但默认情况下,它们不能相互执行任何操作。

为此,一侧需要处于目标模式并提供存储。因此,SCST项目有一个用于QLogic系列FC卡的驱动程序,该驱动程序可以使它们充当FC目标上的存储。

在编译此模块并使其正常工作后,我研究了如何使用SCST,并高兴地发现有一个用户空间模块。该模块允许完全在用户空间中创建设备,然后可以通过FC将其公开给另一个系统。

Root@testtop:~#rmmod qla2xxx#卸载主线driverroot@testtop:~#modbe qla2x00tgt#加载目标模式SCST versionroot@testtop:~##应用基本配置以允许另一端使用我们的";disk";root@testtop:~#scstadmin-config lol.conf收集当前配置:完成。->;检查配置文件';lol.cong->;完成->;应用配置。->;将目标属性';rel_tgt_id';设置为值';1';驱动程序/目标';qla2x00t/50:01:43:80:26:68:8E:5c';:完成。->;将新组';net';添加到驱动程序/目标';qla2x00t/50:01:43:80:26:68:8E:5C';:完成。->;将新启动器';50:01:43:80:21:de:b5:d6';添加到驱动程序/目标/组';Qla2x00t/50:01:43:80:26:68:8E:5C/NET';:完成。->;将新启动器';21:00:00:24:FF:0E:0E:75';添加到驱动程序/目标/组';qla2x00t/50:01:43:80:26:68:8e:5c/net';:完成。->;启用驱动程序/目标';qla2x00t/50:01:43:80:26:68:8E:5C';:完成。->;完成,5次更改。All done.root@testtop:~#。/scst-driver&;#启动driverroot@testtop:~##将虚拟磁盘连接到其他客户端。root@testtop:~#scstadmin-add_lun 0-driver qla2x00t\>;-target 50:01:43:80:26:68:8E:5C\>;-group net-device net3-->;已将LUN 0处的设备';net3';添加到驱动程序/目标/组';qla2x00t/50:01:43:80:26:68:8e:5c/net';:。->;完成。

这很棒,因为它允许我使用Just系统编程技术创建虚拟设备。缺点是,虽然有这方面的文档,但在野外使用它的代码示例数量实际上是一个,而且它是SCST代码库中包含的fileio示例。然而,这个代码示例将被证明是无价的,因为它的速度很高(可以读取高达6Gbps),并且足够干净,可以作为参考。

当我更深入地论证概念时,我意识到我不能简单地通过FC来回发送任意数据包,这意味着我必须实施符合SCSI标准的设备才能来回传输网络流量。

不管怎样,我开始认真研究它,并决定看看我是否可以用Go编写一个虚拟设备处理程序。令我意想不到的是,这意味着你基本上必须几乎从头开始编写一个设备。这意味着我必须熟悉磁盘驱动器所使用的协议:SCSI。稍微让人恼火的是,作为一个磁盘实际上是令人惊讶的复杂。我现在明白为什么驱动器固件中存在错误了,因为提供SCSI命令集中等视图的手册有500多页长。

存在的最基本的SCSI命令之一是查询,它描述连接的设备的型号和类型。它也是(除了ping的SCSI版本之外)Linux将发送给SCSI设备的首批命令之一,并且它将根据查询的输出做出分类决策。

您可以通过查看dmesg并查找类似以下内容来查看此早期命令的输出:

这些是内核发出查询命令并输出您的设备返回的类类型(在上面的例子中是“直接访问块设备”)的结果。提供的设备类型将决定内核如何处理您。选择块存储设备类型将导致内核自动发送各种信息收集SCSI命令,这些命令很难正确实现。谢天谢地,还有一系列其他设备可供选择。

在尝试了一段时间之后,我发现识别为扫描器会导致Linux内核提出的问题最少。只需一两次查询,就会在/dev/sg<;n>;下生成一个设备供您使用。

现在我们有了一个最小的虚拟SCSI设备,我们可以着手让它为我们移动以太网包。即使Smartctl在解析它时遇到了一些问题,它也是“足够接近”的。

Root@Black-box:~#Smartctl-a/dev/sg1 Smartctl 6.6 2017-11-05 r4594[x86_64-linux-4.19.0-9-amd64](本地版本)版权所有(C)2002-17,Bruce Allen,Christian Franke,www.Smartmontools.org=信息部分的开始=供应商:BENJOJO产品:网卡lolRevision:350合规性:SPC-4用户容量:由于对IEC模式页的错误响应,提前终止命令强制智能命令失败:正在退出。要继续,请添加一个或多个&T允许选项。

因此,我决定构建一个基本接口,该接口接受SCSI写入作为出站数据包,并允许客户端轮询传入数据包。与前一个项目一样,我使用Tun/TAP在两个系统上制作了一个虚拟网卡。

在FC客户端上,我们可以使用Linux(Sg)中的通用SCSI接口手动触发读写命令。

Ping 42.42.42.1(42.42.42.1)56(84)字节数据。42.42.42.1中的64字节:icmp_seq=1 ttl=64 time=387 ms42.42.1:icmp_seq=2 ttl=64 time=194 ms64 byte from 42.42.42.1:icmp_seq=3 ttl=64 time=102 ms。

但由于它轮询的是假驱动器,因此具有高延迟和极低的吞吐量(低于80kbit/s)。我们可以通过将轮询间隔从测试100ms减少到1ms来快速改进这一点。

这为我们提供了更好的延迟和吞吐量,仅此一项,我们就几乎达到了10Mbit/s。

然而,我们现在已经达到了合理轮询新数据包的速度极限。现在,理想情况下,我们需要在数据包可用时将其推送到另一端。要做到这一点,最简单的方法是将SCSI读取请求挂起一段时间,直到出现数据包。然而,由于SCST的用户空间模式的工作方式(一次只能处理一个请求),我们必须找到一种智能的方式来服务长期存在的SCSI读取,同时仍然能够处理写入…。所以我做了一件简单的事情,只做了两个SCSI设备。

Root@Black-box:~#dmesg|ail-n 5[710.064439]qla2xxx[0000:01:00.0]-500A:6:检测到环路(8 Gbps)。[710.923684]scsi 6:0:0:0:0:扫描仪BENJOJO网卡lol 350pq:0 ansi:6[710.924371]scsi 6:0:0:0:0:连接的scsi通用sg1类型6[710.924979]scsi 6:0:0:1:scsi BENJOJJ。6:0:0:1:附加SCSI通用SG2类型6。

一个用于SCSI写入(向另一端发送数据包),另一个用于SCSI读取(从另一端读取数据包)。

Root@Black-box:~#ping 42.42.42.1(42.42.42.1)56(84)字节数据。来自42.42.42.1的64字节数据。icmp_seq=1ttl=64 time=0.956 ms64字节from 42.42.42.1:icmp_seq=2ttl=64 time=1.11ms64字节from 42.42.42.1:icmp_seq=3 ttl=64 time=。时间4msrtt min/avg/max/mdev=0.956/1.036/1.106/0.067 ms。

Root@Black-Box:~#iperf-c 42.42.42.1---Client正在连接到42.42.42.1,Tcp端口5001TCP窗口大小:85.0KByte(default)---[3]本地42.42.42.2端口52766与42.42.42.1端口5001[ID]间隔传输带宽[3]0.0-10.0秒105兆字节88.2Mbit/秒

Root@Black-Box:~#iperf-c 42.42.42.1---Client正在连接到42.42.42.1,Tcp端口5001TCP窗口大小:325KByte(default)---[3]本地42.42.42.2端口52752与42.42.42.1端口5001[ID]间隔传输带宽[3]0.0-10.0秒579兆字节485兆比特/秒。

在这一点上,虽然我们还没有达到6Gbps的技术极限,但我们已经基本达到了“作为带外网络足够好”的功能水平。遗憾的是,我没有FC交换机来测试这是否可以通过结构,但我看不出有任何理由不应该这样做。但在一个稍微有创意的设置中,当系统完全无法访问时,有人可以使用备份IP网络这样的东西。

我想只要付出一些努力,你就可以让这件事变得更快,但对我个人来说,这是不值得的。与尝试的IPoFC后端口非常相似,在不消耗大量CPU的同时使吞吐量好于千兆以太网可能是不切实际的,因此这样的项目的价值是最小的。同样值得一提的是,我确实研究过修改qla2xx驱动程序本身,但如果没有QLogic芯片组本身的正式文档,直接将其修改为以太网卡似乎相当困难。

然而,在项目期间,我确实设法实现了几次性能跳跃,比如确保不在热路径上发出调试消息,以及稍后我发现的涉及GO通道性能影响的稍微模糊的问题。我确信您可以通过将多个SCSI设备链接在一起,然后使用多队列Tun/TAP功能来避免阻塞单个Tun/TAP文件描述符,从而获得更快的链接。

最终的完整系统火焰图如下所示(单击以进行交互)半个CPU用于400mbit/s的巨型帧:

虽然采用英特尔X520 10千兆位以太网卡的相同系统如下所示(单击查看交互式)(CPU负载仅是10G流的单个核心):

您可以在我的GitHub上找到这段粗略的代码,但它确实最好用作SCST的用户空间模块的数据点,因为我不能真诚地推荐人们用GO这样的语言编写虚拟SCSI设备。

如果你想看内部结构,你可以在我的gihub上找到它们:https://github.com/benjojo/IPoverFC

既然我一开始就提到我有很多这样的卡,如果有人在伦敦地区,愿意从我手中拿走一些,我会很高兴地离开他们。我大约有2袋易购的Emulex FC 8Gbit卡和1袋QLogic的易购。如果这是您的爱好,请发送电子邮件至[email protected]

如果你对此很感兴趣,你可以在博客的其余部分找到你喜欢的其他部分。如果你想了解我的漫游或项目的最新消息,你可以使用我博客的RSS Feed,或者你可以在Twitter上关注我。