问题描述
某系统 dmesg 信息中有如下内容频繁打印,冲掉了其它相关的信息,需要限制打印。
UDP: bad checksum. From 10.66.245.93:61525 to 255.255.255.255:137 ulen 58
相关代码
内核源码树中的文件名:
net/ipv4/udp.c
相关源码:
csum_error:
/*
* RFC1122: OK. Discards the bad packet silently (as far as
* the network is concerned, anyway) as per 4.1.3.4 (MUST).
*/
net_dbg_ratelimited("UDP%s: bad checksum. From %pI4:%u to %pI4:%u ulen %d\n",
proto == IPPROTO_UDPLITE ? "Lite" : "",
&saddr, ntohs(uh->source), &daddr, ntohs(uh->dest),
ulen);
这部分功能为,内核检验报文的 checksum 失败,丢弃报文并打印警告。问题的原因可能是网络链路存在问题导致有错包出现。
从功能上说,这个属于异常告警,直接关闭显然不太合理,但是系统中一直打印这些信息加之 dmesg 使用环形缓冲区,一些有用的内核打印信息会被这个信息冲掉,为此需要进行处理。
如何限制打印?
从上文的源代码中可以看出,内核调用了 net_dbg_ratelimited 函数来打印这个告警信息,net_dbg_ratelimited 函数本身就有限速的功能,但是这个限速明显不符合我们的要求,如果能够提高限速,或许能够解决我们的问题。
从 net_dbg_ratelimited 函数的实现着手
linux-5.x 内核代码中,net_dbg_ratelimited 函数实现代码如下:
#if defined(CONFIG_DYNAMIC_DEBUG) || \
(defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE))
#define net_dbg_ratelimited(fmt, ...) \
do { \
DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \
if (DYNAMIC_DEBUG_BRANCH(descriptor) && \
net_ratelimit()) \
__dynamic_pr_debug(&descriptor, pr_fmt(fmt), \
##__VA_ARGS__); \
} while (0)
#elif defined(DEBUG)
#define net_dbg_ratelimited(fmt, ...) \
net_ratelimited_function(pr_debug, fmt, ##__VA_ARGS__)
#else
#define net_dbg_ratelimited(fmt, ...) \
do { \
if (0) \
no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#endif
我们的系统中开启了 CONFIG_DYNAMIC_DEBUG 内核配置,这里只需要考虑第一种情况。根据代码能够将问题缩小到 net_ratelimit 函数中。
net_ratelimit 函数源码如下:
DEFINE_RATELIMIT_STATE(net_ratelimit_state, 5 * HZ, 10);
/*
* All net warning printk()s should be guarded by this function.
*/
int net_ratelimit(void)
{
return __ratelimit(&net_ratelimit_state);
}
EXPORT_SYMBOL(net_ratelimit);
net_ratelimit_state 为内核向用户态导出的可配置接口,它在 net_core_table ctl_table 中的定义如下:
{
.procname = "message_cost",
.data = &net_ratelimit_state.interval,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_jiffies,
},
{
.procname = "message_burst",
.data = &net_ratelimit_state.burst,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
},
我们可以通过修改 net.core.message_cost 与 net.core.message_burst 来完成限速功能。
实现限速的两种方式
上文已经描述了 net_dbg_ratelimited 的主要实现,根据内核代码,可以使用如下两种方式来配置限速:
-
使用 sysctl -w 来设置
相关的项目如下:
[root] #$ sysctl -a | grep net.core.message net.core.message_burst = 10 net.core.message_cost = 5
-
通过 proc fs 来设置
相关文件如下:
/proc/sys/net/core/message_burst /proc/sys/net/core/message_cost