Wednesday, 24 November 2010

Building cheap console server

This time from the department of almost wasted time...

We all know that serial ports come very handy when you need to (re)configure something like a switch/server/firewall or similar device. In theory you can do that over TCP/IP nowadays with one hint - you need to have connectivity. All would be ok if not the fact that those very switches/firewalls you want to reconfigure actually provide the connectivity you need :-)

The Idea


Now... why spend hundreds of pounds/dollars on off-the shelf kit? Sure, it's cool, properly built and works unless you mess it up, but where's the fun part?! Today I needed a very very quick and cheap solution, so:

  1. SheevaPlug - £114.00
  2. 13-port USB hub - £19.99
  3. USB-serial dongles (pl2303) - £14.99 each
This way I have fully networked console server with 4 ports just under £200 - acceptable, especially when the whole thing is running off DHCP and calls home via OpenVPN - very easy to deploy!

Tricky bits

Generic Sheeva has one USB host port and hub has 13 of them - I want to send it off to remote location and have somebody plug it in and not mess up what's where. Trick is to write appropriate udev rules to detect adapters and give them ttyUSBn names according to physical port on the hub.


All would be fine and easy if it worked as documented - sadly it doesn't. First problem was that ATTRS{devpath} (as returned by udevadm info --attribute-walk -n /dev/ttyUSBn that allows to distinguish usb ports) was used by rule in tests but wasn't propagated properly on none of my Debian or Ubuntu boxes. Then I tried to match KERNELS for parent devices - nope... if you go too far up the tree it doesn't see s**t :-/


The Solution

Finally I got the working rule set - long story short, here it is:

KERNEL=="ttyUSB*", SUBSYSTEM=="tty", DRIVERS=="pl2303", KERNELS=="1-1.1:1.0",   NAME="ttyUSB0"
KERNEL=="ttyUSB*", SUBSYSTEM=="tty", DRIVERS=="pl2303", KERNELS=="1-1.4.1:1.0", NAME="ttyUSB1"
KERNEL=="ttyUSB*", SUBSYSTEM=="tty", DRIVERS=="pl2303", KERNELS=="1-1.4.2:1.0", NAME="ttyUSB2"
KERNEL=="ttyUSB*", SUBSYSTEM=="tty", DRIVERS=="pl2303", KERNELS=="1-1.4.3:1.0", NAME="ttyUSB3"
KERNEL=="ttyUSB*", SUBSYSTEM=="tty", DRIVERS=="pl2303", KERNELS=="1-1.4.4:1.0", NAME="ttyUSB4"
KERNEL=="ttyUSB*", SUBSYSTEM=="tty", DRIVERS=="pl2303", KERNELS=="1-1.3.4:1.0", NAME="ttyUSB5"
KERNEL=="ttyUSB*", SUBSYSTEM=="tty", DRIVERS=="pl2303", KERNELS=="1-1.3.3:1.0", NAME="ttyUSB6"
KERNEL=="ttyUSB*", SUBSYSTEM=="tty", DRIVERS=="pl2303", KERNELS=="1-1.3.2:1.0", NAME="ttyUSB7"
KERNEL=="ttyUSB*", SUBSYSTEM=="tty", DRIVERS=="pl2303", KERNELS=="1-1.3.1:1.0", NAME="ttyUSB8"
KERNEL=="ttyUSB*", SUBSYSTEM=="tty", DRIVERS=="pl2303", KERNELS=="1-1.2.4:1.0", NAME="ttyUSB9"
KERNEL=="ttyUSB*", SUBSYSTEM=="tty", DRIVERS=="pl2303", KERNELS=="1-1.2.3:1.0", NAME="ttyUSB10"
KERNEL=="ttyUSB*", SUBSYSTEM=="tty", DRIVERS=="pl2303", KERNELS=="1-1.2.2:1.0", NAME="ttyUSB11"
KERNEL=="ttyUSB*", SUBSYSTEM=="tty", DRIVERS=="pl2303", KERNELS=="1-1.2.1:1.0", NAME="ttyUSB12"


I had to use KERNELS match as above to have variables seen by the rule. I still don't know (and at this moment don't care any more) why it didn't work as documented...

The bottom line is that it works, it can be done way cheaper than commercial solutions, literally at the fraction of cost - if you don't mind the spider-ish look of it :-)


Update:
Hat tip to @herkii for pointing out another approach.