限制内核 udp bad checksum 失败告警信息

问题描述

某系统 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 的主要实现,根据内核代码,可以使用如下两种方式来配置限速:

  1. 使用 sysctl -w 来设置

    相关的项目如下:

    [root] #$ sysctl -a  | grep net.core.message 
    net.core.message_burst = 10
    net.core.message_cost = 5
    
  2. 通过 proc fs 来设置

    相关文件如下:

    /proc/sys/net/core/message_burst
    /proc/sys/net/core/message_cost
    
UDP和TCP协议都包含了校验和机制,用于检测数据在传输过程中是否发生了错误。 UDP协议使用16位校验和字段来对UDP数据报进行校验。发送端在发送数据之前,会对待发送的数据进行校验和的计算,并将校验和值存储在UDP首部的校验和字段中。接收端在接收数据报时,也会对接收到的数据进行校验和的计算,并将计算得到的校验和与接收到的校验和进行比较。如果两者不一致,则说明数据在传输过程中发生了错误。 TCP协议的校验和机制与UDP类似,也是使用16位校验和字段来对TCP报文进行校验。发送端在发送数据之前,会对待发送的数据进行校验和的计算,并将校验和值存储在TCP首部的校验和字段中。接收端在接收数据报时,同样会对接收到的数据进行校验和的计算,并将计算得到的校验和与接收到的校验和进行比较。如果两者不一致,则说明数据在传输过程中发生了错误。 校验和的计算方法是通过对发送数据进行求和并取反,再将结果存储在校验和字段中。这样,接收端在计算校验和时,将接收到的数据与校验和字段进行求和并取反,得到的结果应该为0。如果不为0,则说明数据在传输过程中发生了错误。 通过UDP和TCP的校验和机制,可以很大程度上保证数据的完整性和可靠性,提高了数据传输的准确性。但是需要注意的是,校验和只能检测出简单的传输错误,对于复杂的错误或恶意攻击则无法检测。因此,在实际应用中,还需要结合其他安全机制来保护数据的安全。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值