Wandering Thoughts archives

2022-03-22

Getting a fixed baud rate on your serial ports for logins under systemd

Many servers have support for serial consoles and in general for serial ports, either physical ones or virtual ones provided by things like IPMI Serial over LAN, and Linux (still) supports logins over them. Systemd makes life very convenient for any serial consoles (also) you have; if you configure the kernel with one or more kernel serial consoles via 'console=' arguments, systemd will automatically start a getty on it (as covered in Gettys on Serial Consoles (and Elsewhere) and the manual page for systemd-getty-generator).

(We no longer use serial consoles as /dev/console, where things like systemd messages go. But we still send kernel messages to them and support logging in to machines over them, via our serial console server.)

The standard systemd 'serial-console@.service' unit uses agetty(8) with a variety of baud rate options, specifying '--keep-baud 115200,57600,38400,9600'. As covered by the manual page, this means agetty will start out with whatever baud rate the serial port is at and then cycle through the baud rates with a serial BREAK. On our kernel serial consoles, this appears to reliably keep agetty at the kernel's baud rate (which we normally set to 115200 these days). Unfortunately, on other serial ports this can result in the baud rate winding up at 9600 baud. When the serial port is a virtual IPMI serial over LAN port, sometimes this works (although slowly) and sometimes it doesn't work at all.

To set a particular serial port to a fixed baud rate (the baud rate you'd like and your IPMI expects), you need an override for 'serial-getty@ttyS<X>.service', which you can conveniently get with 'systemctl edit ...'. My first naive version just contained a [Service] section with a new ExecStart for the revised agetty command line. Unfortunately systemd objects to this, complaining that you can't have two ExecStart lines in one .service unit of this type. To fix this, we need to null out ExecStart in our drop-in file, for an end result of:

[Service]
ExecStart=
ExecStart=-/sbin/agetty -o '-p -- \\u' 115200 %I $TERM

(Assuming that you want 115200 as your baud, which you probably do.)

The trick of clearing out (resetting) ExecStart is covered in an example in the manual page for systemd.unit (as part of example 2). It may be covered elsewhere, but if so I didn't spot it. In my opinion this should be better documented

(I believe I found out how to do this clearing from a StackOverflow answer, although I can't find the answer right now.)

PS: I don't know what's happening with additional serial ports to drop them to 9600 baud so regularly. Since I can do 'stty -a </dev/ttyS0; stty 115200 </dev/ttyS0; stty -a </dev/ttyS0' and have the serial port stick at 115200 baud (on a machine with no getty on ttyS0), it's not as simple as the kernel resetting serial ports to 9600 baud when they're closed. Maybe something makes agetty think that the serial port should drop to 9600 baud as soon as agetty starts talking to it. Since all of this was with IPMI virtualized ports, perhaps agetty sees a whole cascade of BREAK signals when it starts up with nothing connected to the virtual serial port on the other side.

linux/SystemdSerialPortsFixedBaud written at 22:02:47; Add Comment


Page tools: See As Normal.
Search:
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.