Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 20 Oct 2003 12:13:27 -0400 (EDT)
From:      Robert Watson <rwatson@FreeBSD.org>
To:        current@FreeBSD.org
Subject:   ethercons: ethernet console driver for 5-current
Message-ID:  <Pine.NEB.3.96L.1031014211213.48934A-100000@fledge.watson.org>

next in thread | raw e-mail | index | archive | help

I had a fair amount of time over the last week running in disconnected
operation, and realized I had too many cables under my desk, so I spent a
bit of time exploring the FreeBSD console code.  After reading a FREENIX
paper this summer on a Linux ethernet console driver, I took a pass at
implementing ethernet console support for FreeBSD.  This driver is similar
to the Linux driver, although not binary-compatible on the wire, as this
driver supports both input and output, while the Linux driver supports
only output monitoring (and the protocol can't represent bi-directional
communication well).  There are some potential work-arounds for this,
which I'll explore at some point.  In general, the wire protocol is
probably the weakest part of the endeavor, but I'm having trouble finding
documentation for a decent wire console protocol that doesn't come with an
entire network stack attached.

As with the Linux driver, communication happens at the ethernet link
layer, using protocol number 0x0666 (entertaining choice).  The contents
consist of a little meta-data (not found in Linux), and a nul-terminated
string, although the kernel code currently generates only single
characters due to the nature of the console code.  ethercons implements
both a low level putc() console interface, and a high-level pseudo-tty
appropriate for /dev/console redirection and getty/login.  Unlike the
other low-level console drivers, ethercons does not implement low-level
input checkc/getc, as ethercons is interrupt driven, and that interface is
a polled interface that conflicts with the tty code.  I'm considering
adopting a timeout-driven model as done in ofw_console, but haven't
convinced myself that is entirely desirable.  In addition, the ethercons
device is not available for I/O when in the debugger context, due to its
use of the network stack.  To support this, I recently added a flags field
to the console definition, and a NODEBUGGER flag.

To enable support for ethercons, add "options ETHERCONS" to your kernel
configuration.  A series of tunables and sysctls is available to tune the
behavior of ethercons:

kern.ethercons.ifnet_raise	"ifconfig up" the interface prior to
				reaching init so that ethercons may be
				used in single usermode.  Otherwise,
				ethercons only becomes available when the
				interface is brought up later by
				dhclient/ifconfig/...  Alternatively, for
				network booted environments, the interface
				may already be up.

kern.ethercons.interface_preference	Interface name preference, if any.
					Otherwise, the default is the first
					ethernet interface.  The most
					recently used interface is
					available read-only via
					kern.ethercons.interface.

kern.ethercons.target	Target ethernet address for the console target.
			Otherwise, the default is ff:ff:ff:ff:ff:ff. 

The ethercons client uses bpf; it's a fairly limited tool in its current
form.  It has several modes of operation:

log		Follow the console output of all ethernet consoles,
		logging the output to various log files, named by the
		source ethernet address of the messages (specified by
		interface).

miniterm	A minimalist interactive terminal program to be pointed
		at a specific ethernet interface and hardware address.

send		Send a string to a remote console as input (specified
		by interface, target address).

sendcr		Send a string to the remote console as input, along
		with a carriage return (specified by interface, target
		address).

tail		Follow the console output of a particular ethernet console
		(specified by interface and source address).

tailall		Follow the console output of all ethernet consoles, even
		though the results are potentially messy (specified by
		interface).

It should be possible to create a more complete client for easier
interactive use; alternatively, the firewire console code binds a socket
for use with a telnet client, which could be done for ethercons, which
might be a better approach than writing more interactive code of that
sort. 

You can set up a getty/login session on /dev/ethercons using /etc/ttys:

  ethercons       "/usr/libexec/getty Pc" xterm   on secure

The changes consist of three parts: two new kernel files
(src/sys/dev/{ethercons.c, ethercons.h}), a kernel patch (ethercons.diff),
and a userland tool for monitoring/logging/communicating with the ethernet
console (src/usr.sbin/ethercons/{ethercons.c,ethercons.h}).  Note that to
build the userland ethercons tool, the updated ethernet.h must be in
/usr/include/net due to its reliance on the new constant. 

  http://www.watson.org/~robert/freebsd/ethercons-0.2.tgz

I believe I have merged all the necessary patches to support ethercons
into the base tree, wich the exception of the tweaks to net/ethernet.h to
allocate a new ethernet protocol number.

I have no immediate plans to commit this code, but would appreciate
feedback.  It appears to work fairly well for me, but it highlighted some
limitations to the FreeBSD networking and console code:

(1) Unless you use netgraph, it is "hard" to extended the set of ethernet
    protocol handlers.  Introducing dynamicism in the protocol switches
    will introduce additional locking costs.

(2) Two levels of support are present in the console driver: first,
    low-level console support provides a simple getc/checkc/putc interface
    for kernel output and input.  However, to support user process
    interaction with the console, such as syslogd writing to the console,
    or single-user mode, you need a tty.  The two interfaces are fairly
    incompatible due to the polled vs. interrupt-driven model.  To
    support the polled interface, the console driver needs to own the
    buffer memory.  To support the tty interface, the tty driver needs to
    own the memory.  The open firmware console works around this by
    having timeouts that transfer data from a console-owned buffer to a
    tty-owned buffer at intervals.  The low-level console code races with
    the timeout to "get there first" and extract data for the low-level
    console when it is required.  All in all, this puts console/tty driver
    writers in a sticky situation if the underlying medium doesn't support
    polled access naturally, and behaves in an interrupt-driven fashion.

So, the quick summary: it appears to work, it has limitations, and the
wire protocol sucks.  I'd like to find a better wire protocol (without too
much overhead), and figure out a better answer for low-level console
interactions.  The client is also pretty limited, and could do with some
improvement.

Robert N M Watson             FreeBSD Core Team, TrustedBSD Projects
robert@fledge.watson.org      Network Associates Laboratories



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.NEB.3.96L.1031014211213.48934A-100000>