Project Hydra:USB 多头怪兽
当涉及到服务器控制台时,用户有两个主要选择:图形界面或文本界面。我个人更喜欢串行控制台而不是图形控制台,而且这种偏好并非完全出于自命不凡。与 KVM 切换器不同,串行控制台切换器是跨平台的且相对便宜。然而,串行控制台切换器的问题在于它们不可扩展。随着我们购买更多的服务器,我们经常发现自己缺少可用的端口。通常,在这种情况下,我会权宜之计,使用附近机器上的可用串行端口和零调制解调器电缆来创建一个临时的控制台服务器。
这种情况让我们开始思考。如果有一个专用的、可远程访问的控制台服务器,连接到我们所有服务器的多个串行端口,那将非常酷。实现这一目标的一种方法是使用多端口串行卡,但它们的价格与串行控制台切换器相当,并且也存在类似的扩展性问题。相反,我们找到了如何使用现成的 USB 总线和 USB 转串行适配器的方法。这种解决方案即使在我们混合的环境中也能很好地工作,而且它也是可扩展且廉价的。
然而,在将这个想法视为控制台访问的万灵药之前,我们应该讨论一下其局限性。首先是 USB 总线,它每个控制器限制为 127 个设备。这看起来很多,但重要的是要记住,集线器算作一个设备,并且在 Linux 下,根集线器也算作一个设备。因此,考虑一个 USB 集线器和 USB 串行适配器的树。设 n 为每个集线器的端口数,k 为树中集线器的数量,r 为 USB 串行适配器的数量。这给了我们总共 n * k 个端口。要在一个树中连接 k 个集线器,我们至少需要 k – 1 个互连,因此 USB 串行适配器的最大数量为 r = nk – (k – 1)。由于最多有 126 个设备(127 减去根集线器的一个),在最佳情况下,我们有 k + r = 126。求解 nk 得到两个方程,nk = 125 和 r = 126 – k。当 nk = 125 没有整数解时,最好向上舍入 k;否则,可用端口的数量将小于最大数量。因此,使用四端口集线器 (n = 4),我们得到 k = 32 和 r = 94,单个控制器上最多有 94 个 USB 串行适配器。使用七端口集线器,k = 18 和 r = 108。
通过使用额外的 USB 控制器,我们可以做得比 127 个设备更好。虽然大多数 PC 都配备了多个 USB 端口,但这些端口通常位于同一个控制器上,并且 127 个设备的限制约束了这两个端口。即使我们添加更多控制器,允许的 USB 串行设备数量也存在上限 256 个,或 r </= 256。这是分配的 USB 串行主设备号(即 188)允许的次设备号数量的限制。更有进取心的用户可能会修改驱动程序以允许更多的主设备号。在串行端口具有高波特率的情况下,也可能需要添加额外的控制器;请记住,USB 总线限制为 12Mbps。时序问题也可能使可用的 USB 串行适配器数量低于理论极限,但添加控制器相对容易且廉价。
使用 USB 设备的另一个限制是互连长度;电缆的最大长度限制为五米。有效的电缆长度可以通过使用有源设备来延长,例如有源集线器或有源延长线,尽管即使是有源延长线也算作一个设备。总深度限制为七层,包括根设备和底层设备。这意味着最多可以有六个 5 米的互连,总长度为 30 米。虽然 30 米足以到达我们服务器机房的每个角落,但通过使用屏蔽 RS-232 电缆将 USB 串行适配器连接到服务器控制台端口,可以将覆盖范围再增加 15 米。还有其他扩展 RS-232 信号的方法;例如,使用一对 RS-422 适配器,有效范围约为 1.3 公里。
集线器的选择是无关紧要的;但是,所有集线器都必须供电以限制信号衰减。然而,USB 串行适配器的选择很重要。我们尝试的第一个适配器是 Xircom/Entrega,它在内核驱动程序列表中被列为实验性的。事实证明,该供应商从未提供其驱动程序的源代码,因此 Linux 驱动程序是通过逆向工程开发的。虽然此驱动程序适用于某些型号,但它不适用于我们购买的型号。为了避免类似的命运,请花一些时间浏览 USB 用户邮件列表存档或 USB 设备数据库(请参阅资源)。
Keyspan 系列适配器经常被推荐,但它们相当昂贵,每个大约 50 美元。我们设法找到了一些基于 pl2303 芯片的 Maxxtro 适配器,每个大约 15 美元,效果很好。这些适配器本质上是一根电缆,一端带有 USB 连接器,中间有一些电路,另一端带有公 DB9 连接器。唯一需要的另一件东西是 DB9f-DB9f 串行电缆,用于将适配器连接到控制台端口;串行电缆需要是零调制解调器电缆。
我们每个集线器花费约 16 美元,每根 5 米 USB A/B 电缆 5 美元,每个 USB 串行适配器 15 美元,每根 1 米零调制解调器电缆约 2 美元。如果我们假设每个四端口集线器连接三个适配器,将第四个端口留给后代集线器,并且每个集线器需要一个 5 米互连,那么每个控制台端口的平均成本为 (16 + 5 + 3 * 15 + 3 * 2) / 3,即平均每个控制台 24 美元。因此,16 个 USB 串行控制台端口将花费约 384 美元。
当然,还有控制台服务器本身的费用,但我忽略了这一点,因为我们只是使用了一台原本会被送人的机器。其次,大多数串行控制台切换器不附带我已包含在 USB 解决方案的每端口成本中的必要布线硬件。
现在您已经准备好购买一些硬件并尝试一下,您如何使其工作?首先,配置您的内核以支持 USB。至少,您需要将 CONFIG_USB、CONFIG_USB_SERIAL 和 CONFIG_USB_SERIAL_PL2303(或您选择的适配器的驱动程序)设置为 y 或 m。您还需要 USB 控制器驱动程序之一,EHCI、UHCI 或 OHCI。我建议将所有这些驱动程序构建为模块,以简化您可能需要执行的任何故障排除。模块构建完成后,插入 USB 串行适配器,加载模块并检查以下输出dmesg。您应该看到几行输出,以
usbserial.c: PL-2303 converter detected usbserial.c: PL-2303 converter ↪now attached to ttyUSB0
在这里,我将一个 USB 串行适配器连接到集线器。该适配器已被分配设备名称 ttyUSB0,因为它是第一个检测到的 USB 串行适配器。如果您要将此适配器连接到控制台端口并将 minicom 指向 /dev/ttyUSB0,您应该能够建立连接。虽然过程就是这么简单,但这就是我们遇到问题的地方。一旦我将服务器连接到此适配器,就无法保证此服务器始终在 /dev/ttyUSB0 上可用。ttyUSB 设备号按照设备在总线上检测到的顺序分配。虽然设备检测到的顺序是一个明确定义的算法,但问题是 USB 串行驱动程序始终分配第一个可用的 ttyUSB 设备号。举一个简单的例子,考虑两个设备,ttyUSB0 和 ttyUSB1。如果我们断开分配给 ttyUSB1 的适配器,断开 ttyUSB0,然后重新连接曾经是 ttyUSB1 的适配器,它现在是 ttyUSB0,因为那是第一个可用的 ttyUSB 设备号。
当然,我们可以通过不插拔设备来避免这个问题,尽管可以说这种能力是 USB 的优势。但是,仍然存在一个问题:设备可能在模块加载以外的其他时间被检测到。考虑向现有设备树添加新的 USB 串行适配器,可能是为了连接新的服务器。因为新设备现在是最后一个检测到的设备,所以它接收下一个可用的 ttyUSB 设备号。假设以前没有设备断开连接,这可能是最高的 ttyUSB 设备号。但是,如果此设备添加到树的根集线器附近,那么下次控制台服务器重新启动或 USB 串行模块重新加载时,此设备可能会被分配一个较低的 ttyUSB 设备号,因为它可能是最早检测到的设备之一。
一个可能的解决方案:如果我们能够通过 USB 串行适配器在设备树中的位置来定位它,会怎么样?这个选项会更可靠,因为现有结构不太可能被修改。也就是说,即使添加新设备,我们也可以选择保留现有设备在树中的位置。检查 /proc/bus/usb/devices 发现总线上检测到的每个设备都有一个拓扑字段,形式为
T: Bus=# Lev=# Prnt=# Port=# Cnt=# Dev#=#
感兴趣的字段是 Port,它指示此设备在其父设备(通常是集线器)上的位置,以及 Prnt,它指示设备的 USB 设备 ID,同样通常是此设备连接到的集线器。从特定设备向后工作到根,可以递归地确定设备的路径。虽然这确实将 USB 路径连接到代表其在树中位置的特定设备,但关于分配的 ttyUSB 设备号的信息无法从 /proc/bus/usb/devices 中获得。我们与 USB 路径的唯一连接是 Dev 字段中分配的 USB 设备号。不幸的是,USB 设备号是按照设备检测到的顺序分配的。因此,它具有与以前相同的问题;如果将设备添加到现有树中,它将被分配下一个可用的 USB 设备号,这可能与重新加载 USB 串行模块时的分配不同。
需要的是一种将 USB 路径直接关联到分配的 ttyUSB 设备号的方法。事实证明,USB 开发人员已经解决了这个问题。从内核 2.4.20-pre7 开始,USB 串行驱动程序存在一个新的 proc 条目:/proc/tty/driver/usb-serial。此驱动程序包含一些条目,至少从 pre7 开始,这些条目看起来像
0: module:pl2303 name:"PL-2303" vendor:067b ↪product:2303 num_ports:1 port:1 ↪path:usb-00:07.2-2.3.4 1: module:pl2303 name:"PL-2303" vendor:067b ↪product:2303 num_ports:1 port:1 ↪path:usb-00:07.2-2.4.4
第一个冒号分隔的字段是分配的 ttyUSB 设备号,USB 路径是 path: 部分之后的位。在本例中,第一行指示 ttyUSB0 是连接到路径 usb-00:07.2-2.3.4 的 USB 串行设备,向后工作,它转换为插入集线器端口 3 的集线器的端口 4,插入根集线器 00:07.2 的端口 2。
00:07 部分是一个额外的奖励。此字段唯一地描述了 USB 控制器,因此我们还可以确定设备分配到的控制器。
为了使它真正起作用,有必要存储服务器名称到 USB 路径的映射。也就是说,在构建 USB 串行设备树并将它们连接到服务器控制台后,创建一个文本文件,将服务器名称映射到 /proc/tty/driver/usb-serial 中的 USB 路径。然后,编写一个脚本就很简单了,该脚本接受服务器名称,解析此文件以确定 USB 路径,然后解析 /proc/tty/driver/usb-serial 以确定 ttyUSB 设备号。一旦知道 ttyUSB 设备号,脚本就可以使用 minicom 作为示例建立与端口的连接。我更进一步,编写了一个脚本,该脚本探测每个 ttyUSB 设备,尝试从登录标语中确定主机,然后记录 USB 路径和服务器名称。但这并非万无一失,因为某些操作系统不在标语中提供主机名。更糟糕的是,如果控制台保持登录状态,则标语将不可用。尽管如此,此选项使创建映射文件变得更容易一些。
一旦控制台端口连接到 USB 串行适配器,就可以使用 minicom、screen 或您喜欢的终端程序连接到分配的 ttyUSB 端口号来访问控制台。如果服务器本身支持串行控制台,这将立即起作用,大多数 Sun、HP-UX 和 IBM 机器都是如此。不太常见的是,某些 PC 在 BIOS 中包含控制台重定向功能,该功能允许将视频和键盘完全重定向到串行端口。如果硬件重定向不可用,则可以通过在 /etc/inittab 中设置 tty 条目来使用软件重定向,类似于以下内容之一
Solaris
tty0:234:respawn:/usr/lib/saf/ttymon -g -h -p ↪"'uname -n' console login: "-T vt100 -d ↪/dev/ttya -l console
IRIX
t1:23:respawn:/sbin/suattr -C ↪CAP_FOWNER,CAP_DEVICE_MGT,CAP_DAC_WRITE+ip ↪-c "exec /sbin/getty ttyd1 console"
远程串行控制台入门的一个好的起点是 Remote-Serial-Console-HOWTO(请参阅资源)。使用软件重定向端口的缺点是,如果机器无法启动,您将无法访问控制台。您也无法访问操作系统启动之前发生的系统的任何部分。例如,对于 PC,您无法访问 PC BIOS 或任何控制器 BIOS。如果此级别的访问至关重要,您可能会对名为 PC Weasel 的产品感兴趣 (www.realweasel.com),它可以创建一个完全可访问的硬件重定向控制台,并提供远程重置 PC 的能力。
由于无法在没有硬件控制台端口的情况下硬重置或在操作系统启动之前访问控制台,因此此控制台访问解决方案无法取代亲临现场。但是,此访问解决方案易于扩展,并且成本几乎与传统的串行控制台切换器相同。此外,可以根据需要添加端口,并且可以热插拔添加。
真正将 USB 控制台服务器与手动切换器区分开来的是远程和并行访问控制台的能力。也就是说,任意数量的用户可以远程连接到 USB 控制台服务器,然后将每个 shell 连接到单独的、尽管是唯一的控制台。此外,访问连接的控制台的唯一限制是访问 USB 控制台服务器的限制;您可以使用本地键盘和显示器、SSH、拨号调制解调器、自定义 Web 界面、电子邮件等等。当然,由于 USB 串行适配器提供标准的串行端口,因此也可能存在其他应用程序。目前,我们正在考虑使用此系统来监控我们的 UPS 设备并管理关机事件。
资源
Linux USB 设备数据库:www.qbik.ch/usb/devices
Linux USB FAQ:www.linux-usb.org/FAQ.html
PC Weasel:www.realweasel.com
远程串行控制台 HOWTO:www.tldp.org/HOWTO/Remote-Serial-Console-HOWTO/index.html
Poul Petersen (petersp@alleft.com) 自 Slackware 的第一个版本发布以来一直从事 Linux 工作。从那时起,Linux 渗透到了他的桌面、笔记本电脑、起居室、家庭 Beowulf 集群,甚至他的汽车中。白天,他通过在 Rogue Wave Software 担任高级 UNIX 系统管理员来支付电费。