Netconsole

由 Ingo Molnar <mingo@redhat.com> 启动, 2001.09.17

Matt Mackall <mpm@selenic.com> 的 2.6 移植和 netpoll api, Sep 9 2003

Cong Wang <xiyou.wangcong@gmail.com> 的 IPv6 支持, Jan 1 2013

Tejun Heo <tj@kernel.org> 的扩展控制台支持, May 1 2015

Breno Leitao <leitao@debian.org> 的发布前缀支持, Jul 7 2023

Matthew Wood <thepacketgeek@gmail.com> 的用户数据附加支持, Jan 22 2024

Breno Leitao <leitao@debian.org> 的系统数据附加支持, Jan 15 2025

请将错误报告发送给 Matt Mackall <mpm@selenic.com> Satyam Sharma <satyam.sharma@gmail.com>, 和 Cong Wang <xiyou.wangcong@gmail.com>

简介:

此模块通过 UDP 记录内核 printk 消息,从而允许调试磁盘日志记录失败且串行控制台不切实际的问题。

它可以内置或作为模块使用。作为内置模块,netconsole 会在 NIC 卡之后立即初始化,并将尽快启动指定的接口。虽然这不允许捕获早期内核崩溃,但它确实捕获了大部分启动过程。

发送方和接收方配置:

它采用字符串配置参数 “netconsole”,格式如下

netconsole=[+][r][src-port]@[src-ip]/[<dev>],[tgt-port]@<tgt-ip>/[tgt-macaddr]

  where
       +             if present, enable extended console support
       r             if present, prepend kernel version (release) to the message
       src-port      source for UDP packets (defaults to 6665)
       src-ip        source IP to use (interface address)
       dev           network interface name (eth0) or MAC address
       tgt-port      port for logging agent (6666)
       tgt-ip        IP address for logging agent
       tgt-macaddr   ethernet MAC address for logging agent (broadcast)

示例

linux netconsole=4444@10.0.0.1/eth1,9353@10.0.0.2/12:34:56:78:9a:bc

insmod netconsole netconsole=@/,@10.0.0.2/

或使用 IPv6

insmod netconsole netconsole=@/,@fd00:1:2:3::1/

或使用 MAC 地址选择出口接口

linux netconsole=4444@10.0.0.1/22:33:44:55:66:77,9353@10.0.0.2/12:34:56:78:9a:bc

它还支持通过指定用分号分隔的多个代理的参数并将完整的字符串括在“引号”中来记录到多个远程代理,如下所示

modprobe netconsole netconsole="@/,@10.0.0.2/;@/eth1,6892@10.0.0.3/"

内置 netconsole 在 TCP 堆栈初始化后立即启动,并尝试以提供的地址启动提供的设备。

远程主机有几个选项可以接收内核消息,例如

  1. syslogd

  2. netcat

    在使用基于 BSD 的 netcat 版本的发行版(例如 Fedora、openSUSE 和 Ubuntu)上,必须在不使用 -p 开关的情况下指定侦听端口

        nc -u -l -p <port>' / 'nc -u -l <port>
    
    or::
    
        netcat -u -l -p <port>' / 'netcat -u -l <port>
    
  3. socat

socat udp-recv:<port> -

动态重新配置:

动态可重新配置性是 netconsole 的一个有用补充,它允许从基于 configfs 的用户空间界面动态添加、删除远程日志记录目标或重新配置其参数。

要包含此功能,请在构建 netconsole 模块(或内核,如果 netconsole 是内置的)时选择 CONFIG_NETCONSOLE_DYNAMIC。

以下是一些示例(其中 configfs 安装在 /sys/kernel/config 挂载点)。

要添加远程日志记录目标(目标名称可以是任意的)

cd /sys/kernel/config/netconsole/
mkdir target1

请注意,新创建的目标具有默认参数值(如上所述)并且默认情况下已禁用 -- 必须首先通过将 “1” 写入 “enabled” 属性来启用它们(通常是在相应地设置参数之后),如下所述。

要删除目标

rmdir /sys/kernel/config/netconsole/othertarget/

该接口向用户空间公开 netconsole 目标的这些参数

enabled

当前是否启用了此目标?

(读写)

extended

启用扩展模式

(读写)

release

将内核版本添加到消息前

(读写)

dev_name

本地网络接口名称

(读写)

local_port

要使用的源 UDP 端口

(读写)

remote_port

远程代理的 UDP 端口

(读写)

local_ip

要使用的源 IP 地址

(读写)

remote_ip

远程代理的 IP 地址

(读写)

local_mac

本地接口的 MAC 地址

(只读)

remote_mac

远程代理的 MAC 地址

(读写)

transmit_errors

数据包发送错误数

(只读)

“enabled” 属性还用于控制是否可以更新目标的参数 -- 您只能修改已禁用的目标的参数(即,如果 “enabled” 为 0)。

要更新目标的参数

cat enabled                            # check if enabled is 1
echo 0 > enabled                       # disable the target (if required)
echo eth2 > dev_name                   # set local interface
echo 10.0.0.4 > remote_ip              # update some parameter
echo cb:a9:87:65:43:21 > remote_mac    # update more parameters
echo 1 > enabled                       # enable target again

您还可以动态更新本地接口。如果您想使用新出现的接口(并且可能在 netconsole 加载/初始化时不存在),这将特别有用。

在启动时(或模块加载时)使用 netconsole= 参数定义的 Netconsole 目标会被分配名称 cmdline<index>。例如,参数中的第一个目标被命名为 cmdline0。您可以通过创建具有匹配名称的 configfs 目录来控制和修改这些目标。

假设您在启动时定义了两个 netconsole 目标

netconsole=4444@10.0.0.1/eth1,9353@10.0.0.2/12:34:56:78:9a:bc;4444@10.0.0.1/eth1,9353@10.0.0.3/12:34:56:78:9a:bc

您可以通过创建以下目标在运行时修改这些目标

mkdir cmdline0
cat cmdline0/remote_ip
10.0.0.2

mkdir cmdline1
cat cmdline1/remote_ip
10.0.0.3

附加用户数据

启用 netconsole 动态配置后,可以将自定义用户数据附加到消息末尾。可以修改用户数据条目,而无需更改目标的 “enabled” 属性。

userdata 下的目录(键)限制为 53 个字符长度,userdata/<key>/value 中的数据限制为 200 个字节

cd /sys/kernel/config/netconsole && mkdir cmdline0
cd cmdline0
mkdir userdata/foo
echo bar > userdata/foo/value
mkdir userdata/qux
echo baz > userdata/qux/value

消息现在将包含此额外的用户数据

echo "This is a message" > /dev/kmsg

发送

12,607,22085407756,-;This is a message
 foo=bar
 qux=baz

使用以下命令预览将附加的用户数据

cd /sys/kernel/config/netconsole/cmdline0/userdata
for f in `ls userdata`; do echo $f=$(cat userdata/$f/value); done

如果创建了 userdata 条目但没有数据写入 value 文件,则该条目将从 netconsole 消息中省略

cd /sys/kernel/config/netconsole && mkdir cmdline0
cd cmdline0
mkdir userdata/foo
echo bar > userdata/foo/value
mkdir userdata/qux

qux 键被省略,因为它没有值

echo "This is a message" > /dev/kmsg
12,607,22085407756,-;This is a message
 foo=bar

使用 rmdir 删除 userdata 条目

rmdir /sys/kernel/config/netconsole/cmdline0/userdata/qux

警告

当将字符串写入用户数据值时,输入会按 configfs 存储调用中的每行进行分解,这可能会导致令人困惑的行为

mkdir userdata/testing
printf "val1\nval2" > userdata/testing/value
# userdata store value is called twice, first with "val1\n" then "val2"
# so "val2" is stored, being the last value stored
cat userdata/testing/value
val2

建议不要使用换行符编写用户数据值。

用户数据中的任务名称自动填充

在 netconsole configfs 层次结构中,userdata 目录下有一个名为 taskname_enabled 的文件。此文件用于启用或禁用自动任务名称填充功能。此功能会自动填充在发送消息的 CPU 中调度的当前任务名称。

启用任务名称自动填充

echo 1 > /sys/kernel/config/netconsole/target1/userdata/taskname_enabled

启用此选项后,netconsole 消息将在用户数据字段中包含一个额外的行,格式为 taskname=<任务名称>。这允许 netconsole 消息的接收者轻松找到生成该消息时当前调度的应用程序,为内核消息提供额外的上下文并帮助对其进行分类。

示例

echo "This is a message" > /dev/kmsg
12,607,22085407756,-;This is a message
 taskname=echo

在此示例中,该消息是在 “echo” 是当前调度进程时生成的。

用户数据中的内核版本自动填充

在 netconsole configfs 层次结构中,有一个名为 release_enabled 的文件位于 userdata 目录中。此文件控制内核版本自动填充功能,该功能将内核版本信息附加到每个发送的消息中的用户数据字典中。

启用版本自动填充

echo 1 > /sys/kernel/config/netconsole/target1/userdata/release_enabled

示例

echo "This is a message" > /dev/kmsg
12,607,22085407756,-;This is a message
 release=6.14.0-rc6-01219-g3c027fbd941d

注意

此功能提供与 “release prepend” 功能相同的数据。但是,在这种情况下,版本信息附加到用户数据字典中,而不是包含在消息头中。

用户数据中的 CPU 编号自动填充

在 netconsole configfs 层次结构中,userdata 目录下有一个名为 cpu_nr 的文件。此文件用于启用或禁用自动 CPU 编号填充功能。此功能会自动填充发送消息的 CPU 编号。

启用 CPU 编号自动填充

echo 1 > /sys/kernel/config/netconsole/target1/userdata/cpu_nr

启用此选项后,netconsole 消息将在用户数据字段中包含一个额外的行,格式为 cpu=<cpu_number>。这允许 netconsole 消息的接收者轻松区分和解复用来自不同 CPU 的消息,这在处理并行日志输出时特别有用。

示例

echo "This is a message" > /dev/kmsg
12,607,22085407756,-;This is a message
 cpu=42

在此示例中,该消息由 CPU 42 发送。

注意

如果用户在用户数据字典中设置了冲突的 cpu 键,则将报告两个键,其中内核填充的条目出现在用户条目之后。例如

# User-defined CPU entry
mkdir -p /sys/kernel/config/netconsole/target1/userdata/cpu
echo "1" > /sys/kernel/config/netconsole/target1/userdata/cpu/value

输出可能如下所示

12,607,22085407756,-;This is a message
 cpu=1
 cpu=42    # kernel-populated value

扩展控制台:

如果在配置行中添加前缀 ‘+’ 或将 “extended” 配置文件设置为 1,则启用扩展控制台支持。以下是一个启动参数示例

linux netconsole=+4444@10.0.0.1/eth1,9353@10.0.0.2/12:34:56:78:9a:bc

日志消息以扩展元数据标头传输,格式如下,与 /dev/kmsg 相同

<level>,<sequnum>,<timestamp>,<contflag>;<message text>

如果启用了 ‘r’(发布)功能,则内核版本会添加到消息的开头。例如

6.4.0,6,444,501151268,-;netconsole: network logging started

<message text> 中的不可打印字符使用 “xff” 表示法进行转义。如果消息包含可选字典,则逐字换行符用作分隔符。

如果消息不适合一定数量的字节(目前为 1000),则消息会被 netconsole 分割成多个片段。这些片段以添加的 “ncfrag” 标头字段传输

ncfrag=<byte-offset>/<total-bytes>

例如,假设块大小小得多,消息 “the first chunk, the 2nd chunk.” 可能会拆分如下

6,416,1758426,-,ncfrag=0/31;the first chunk,
6,416,1758426,-,ncfrag=16/31; the 2nd chunk.

其他说明:

警告

默认目标以太网设置使用广播以太网地址发送数据包,这可能会导致同一以太网段上其他系统的负载增加。

提示

某些 LAN 交换机可能配置为抑制以太网广播,因此建议从传递给 netconsole 的配置参数中显式指定远程代理的 MAC 地址。

提示

要找出例如 10.0.0.2 的 MAC 地址,您可以尝试使用

ping -c 1 10.0.0.2 ; /sbin/arp -n | grep 10.0.0.2

提示

如果远程日志记录代理与发送方位于不同的 LAN 子网上,则建议尝试指定默认网关的 MAC 地址(您可以使用 /sbin/route -n 找到它)作为远程 MAC 地址。

注意

网络设备(在上述情况下为 eth1)可以运行任何其他类型的网络流量,netconsole 不会造成干扰。如果内核消息量很大,Netconsole 可能会导致其他流量略有延迟,但应该没有其他影响。

注意

如果您发现远程日志记录代理没有收到或打印来自发送方的所有消息,则可能是您已将 “console_loglevel” 参数(在发送方上)设置为仅将高优先级消息发送到控制台。您可以使用以下命令在运行时更改此设置

dmesg -n 8

或者通过在启动时在内核命令行上指定 “debug”,将所有内核消息发送到控制台。还可以使用 “loglevel” 内核引导选项设置此参数的特定值。有关详细信息,请参阅 dmesg(8) 手册页和 内核的命令行参数

Netconsole 的设计目标是尽可能快,以便能够记录最关键的内核错误。它也可以从 IRQ 上下文中工作,并且在发送数据包时不会启用中断。由于这些独特的需要,配置不可能更自动,并且一些基本限制将保留:仅支持 IP 网络、UDP 数据包和以太网设备。