This is a daemon for receiving and processing logs from the Linux Kernel, as
emitted over a network by the kernel’s netconsole module. It supports both the
old “legacy” text-only format, and the new extended format added in v4.4.
The core of the daemon does nothing but process messages and drop them: in order
to make the daemon useful, the user must supply one or more “output modules”.
These modules are shared object files which expose a small ABI that is called by
netconsd with the content and metadata for netconsole messages it receives.
This README explains how to build netconsd and use it with one of the existing
output modules in the modules/ directory. The end discusses how to write your
own custom output module.
Building netconsd
The default Makefile target intended for production use has no external
dependencies besides glibc. To build it, just say make (or gmake on BSD):
you’ll end up with a single executable in this directory called netconsd, and
a *.so file for every module in the modules/ directory.
The Makefile includes a few other handy targets:
debug: Adds the usual debug flags, and also enables the ASAN and
UBSAN sanitizers. You'll need to install libasan/libubsan on
your system to build this target and run the binaries.
32bit: Forces 32-bit compilation on x86_64 systems, for easily
testing portability to 32-bit CPU architectures. You'll need
to install 32-bit libraries if your distro doesn't have them.
debug32: Union of the 32bit and debug targets.
disasm: Emits verbose annotated disassembly in *.s files.
If you want to build the daemon with clang, just append CC="clang" to your
make invocation. All the above targets should build with both clang and gcc.
Running netconsd
Setting up the server
By default, netconsd will use 1 listener and 2 worker threads, and listen on
port 1514 for messages. You can use -l, -w, and -u respectively to change
the defaults.
There’s no universal wisdom about how many threads to use: just experiment with
different numbers and use netconsblaster to load up the server. Both the blaster
and the server will print how many packets they sent/processed.
If you run out of memory and OOM, you need more workers; if you see messages
being dropped, you need more listeners. The tuning here will obviously depend on
what your output module does: make sure to pass it when you do your testing.
For the simplest setup, just run:
$ make -s
$ ./netconsd ./modules/printer.so
Netconsd will listen on INADDR_ANY and IN6ADDR_ANY, unless you pass a
specific IPv4 or IPv6 address to listen on using the -a argument.
Note that some systems (at least, OpenBSD) do not allow dual stack sockets at
all, so as currently written netconsd is only capable of receiving IPv6
netconsole packets on those systems.
Setting up the client
The netconsole module takes a parameter like this:
saddr: Source address for the netconsole UDP packets
intf: The name of the interface to send the UDP packets from
dport: Destination port for the netconsole UDP packets
daddr: Destination address for the netconsole UDP packets
dmac: Destination L2 MAC address for the netconsole UDP packets
We need (6) because of how low-level netconsole is: it can’t consult the routing
table to send the packet, so it must know a priori what MAC address to use in
the Ethernet frame it builds.
If you’re talking to a server on the same L2 segment as the client, use the MAC
address of that server. Otherwise, use the MAC address of your router. You can
use the following quick shell one-liners to easily get the MAC of the router:
IPv6: ip -6 neighbor show | grep router
IPv4: sudo arp –a | grep gateway
Here are a couple examples for the parameter above:
Prepending + to the cmdline will cause kernels that support it to use extended
netconsole, which you almost certainly want. Kernels too old to support extcon
will silently ignore the +.
Adding the r to the command line will cause netcons to emit the kernel
release version in the first field of the extended message. For that, you need
to have extended log (extcon) enabled.
Once you have your parameter constructed, just insert the module with it:
If (1) exists, it is called when your module is loaded: the argument tells you
how many worker threads netconsd is going to call your module from. If you
return non-zero from this function, netconsd will abort() and exit.
If (3) exists, it is called when netconsd unloads your module.
For every message it receives, netconsd will call (2) in your module. The code
must be reentrant: netconsd_output_handler() will be called concurrently from
all of the worker threads in netconsd. The thread argument tells you which
worker is invoking the function, which makes it easy to have per-thread data.
Netconsd uses a consistent hash to decide which worker to pass messages to, so
messages from same remote address will always be queued to the same thread.
The src argument will always point to an in6_addr struct containing the source
address of the netconsole packet. If the source was an IPv4 address, it will be
formatted like ::FFFF:<IPv4 address> (see man ipv6 for details).
If the message had extended metadata, msg will point to the ncrx_msg struct
containing that metadata and buf will be NULL. Otherwise, msg will be NULL
and buf will point to a msgbuf struct with the raw message text.
Output modules must not modify the structures passed in. The memory backing all
the pointers passed in will be freed immediately after the handler returns.
Building the modules
For modules written in C this is trivial: just compile with -shared.
For modules written in C++ it can be a bit trickier: you will probably need to
build with -static-libstdc++ and/or -static-libgcc to make this work.
See the code and Makefile in modules/ for some examples of the above.
Contributing
See the CONTRIBUTING file for how to help out.
License
netconsd is BSD licensed, see the LICENSE file for more information.
netconsd was originally written by Calvin Owens as part of
fbkutils in 2016, with later
contributions by several other people. The ncrx library was originally written
by Tejun Heo. This repository is a direct continuation of that codebase.
Netconsd: The Netconsole Daemon
This is a daemon for receiving and processing logs from the Linux Kernel, as emitted over a network by the kernel’s netconsole module. It supports both the old “legacy” text-only format, and the new extended format added in v4.4.
The core of the daemon does nothing but process messages and drop them: in order to make the daemon useful, the user must supply one or more “output modules”. These modules are shared object files which expose a small ABI that is called by netconsd with the content and metadata for netconsole messages it receives.
This README explains how to build netconsd and use it with one of the existing output modules in the modules/ directory. The end discusses how to write your own custom output module.
Building netconsd
The default Makefile target intended for production use has no external dependencies besides glibc. To build it, just say
make(orgmakeon BSD): you’ll end up with a single executable in this directory callednetconsd, and a*.sofile for every module in themodules/directory.The Makefile includes a few other handy targets:
debug: Adds the usual debug flags, and also enables the ASAN and32bit: Forces 32-bit compilation on x86_64 systems, for easilydebug32: Union of the32bitanddebugtargets.disasm: Emits verbose annotated disassembly in*.sfiles.If you want to build the daemon with clang, just append
CC="clang"to your make invocation. All the above targets should build with both clang and gcc.Running netconsd
Setting up the server
By default, netconsd will use 1 listener and 2 worker threads, and listen on port 1514 for messages. You can use
-l,-w, and-urespectively to change the defaults.There’s no universal wisdom about how many threads to use: just experiment with different numbers and use netconsblaster to load up the server. Both the blaster and the server will print how many packets they sent/processed.
If you run out of memory and OOM, you need more workers; if you see messages being dropped, you need more listeners. The tuning here will obviously depend on what your output module does: make sure to pass it when you do your testing.
For the simplest setup, just run:
Netconsd will listen on
INADDR_ANYandIN6ADDR_ANY, unless you pass a specific IPv4 or IPv6 address to listen on using the-aargument.Note that some systems (at least, OpenBSD) do not allow dual stack sockets at all, so as currently written netconsd is only capable of receiving IPv6 netconsole packets on those systems.
Setting up the client
The netconsole module takes a parameter like this:
The fields are as follows:
sport: Source port for the netconsole UDP packetssaddr: Source address for the netconsole UDP packetsintf: The name of the interface to send the UDP packets fromdport: Destination port for the netconsole UDP packetsdaddr: Destination address for the netconsole UDP packetsdmac: Destination L2 MAC address for the netconsole UDP packetsWe need (6) because of how low-level netconsole is: it can’t consult the routing table to send the packet, so it must know a priori what MAC address to use in the Ethernet frame it builds.
If you’re talking to a server on the same L2 segment as the client, use the MAC address of that server. Otherwise, use the MAC address of your router. You can use the following quick shell one-liners to easily get the MAC of the router:
ip -6 neighbor show | grep routersudo arp –a | grep gatewayHere are a couple examples for the parameter above:
Prepending
+to the cmdline will cause kernels that support it to use extended netconsole, which you almost certainly want. Kernels too old to support extcon will silently ignore the+.Adding the
rto the command line will cause netcons to emit the kernel release version in the first field of the extended message. For that, you need to have extended log (extcon) enabled.Once you have your parameter constructed, just insert the module with it:
You’re good to go!
Testing on the client
Now that everything is running, you can use
/dev/kmsgto write some logs:The
<0>tells the kernel what loglevel to use: 0 isKERN_EMERG, which ensures your message will actually get transmitted.Writing an output module
Interface to netconsd
Output modules are shared object files loaded with
dlopen()at runtime by netconsd. Netconsd will look for three functions in your module:int netconsd_output_init(int worker_thread_count)void netconsd_output_handler(int thread, struct in6_addr *src, struct msgbuf *buf, struct ncrx_msg *msg)void netconsd_output_exit(void)If (1) exists, it is called when your module is loaded: the argument tells you how many worker threads netconsd is going to call your module from. If you return non-zero from this function, netconsd will
abort()and exit.If (3) exists, it is called when netconsd unloads your module.
For every message it receives, netconsd will call (2) in your module. The code must be reentrant:
netconsd_output_handler()will be called concurrently from all of the worker threads in netconsd. Thethreadargument tells you which worker is invoking the function, which makes it easy to have per-thread data.Netconsd uses a consistent hash to decide which worker to pass messages to, so messages from same remote address will always be queued to the same thread.
The
srcargument will always point to anin6_addrstruct containing the source address of the netconsole packet. If the source was an IPv4 address, it will be formatted like::FFFF:<IPv4 address>(seeman ipv6for details).If the message had extended metadata,
msgwill point to thencrx_msgstruct containing that metadata andbufwill beNULL. Otherwise,msgwill beNULLandbufwill point to amsgbufstruct with the raw message text.Output modules must not modify the structures passed in. The memory backing all the pointers passed in will be freed immediately after the handler returns.
Building the modules
For modules written in C this is trivial: just compile with
-shared.For modules written in C++ it can be a bit trickier: you will probably need to build with
-static-libstdc++and/or-static-libgccto make this work.See the code and Makefile in
modules/for some examples of the above.Contributing
See the CONTRIBUTING file for how to help out.
License
netconsd is BSD licensed, see the LICENSE file for more information.
netconsd was originally written by Calvin Owens as part of fbkutils in 2016, with later contributions by several other people. The ncrx library was originally written by Tejun Heo. This repository is a direct continuation of that codebase.