Linux内核使用Raw socket发包高速率下死机,是否为正确实现方案?
内核态套接字发送代码问题排查
在内核中使用socket发送数据包是合法的实现方案,kernel_sendmsg是内核提供的标准原生接口,你遇到的高负载死机问题是代码逻辑缺陷导致,和方案本身无关。
现有代码的致命缺陷
- 内存泄漏问题:当前仅当
kernel_sendmsg返回值大于等于0时才会释放frame缓冲区,一旦发送失败进入错误返回分支,frame不会被释放,高发送速率下会快速耗尽系统内存,触发内核OOM panic。 - 空指针风险:代码中直接使用外部
sock变量,未做空指针合法性校验,若套接字处于未初始化、已释放或异常关闭状态,高并发场景下传入野指针调用kernel_sendmsg会直接触发空指针引用崩溃。 - 上下文适配问题:
kernel_sendmsg属于可能阻塞的接口,如果你的send_packet函数是在中断、软中断等原子上下文,或是持有自旋锁的场景下调用,高负载下触发进程调度会直接抛出内核BUG死机。 - 入参校验缺失:没有判断传入的
size是否小于ETH_HLEN,若传入的报文长度不足,len = size - ETH_HLEN会得到负值,赋值给无符号类型的iov_len后会变成超大值,导致内存越界访问崩溃。
优化建议
- 首先修复内存泄漏、入参校验类基础问题,修复后代码参考:
bool send_packet(uint8_t *frame, const uint32_t size) { int len, ret; struct iphdr *ip; struct msghdr msg; struct kvec vec; // 增加入参合法性校验 if (unlikely(!frame || size <= ETH_HLEN || !sock)) { kfree(frame); return false; } ip = (struct iphdr*)(frame + ETH_HLEN); tgb_pr_debug("packet ip version : %d\n",ip->version); tgb_pr_debug("packet from %pI4 to %pI4\n",&ip->saddr, &ip->daddr); tgb_pr_debug("packet ip protocol : %d\n",ip->protocol); memset(&msg,0,sizeof(msg)); len = size - ETH_HLEN; vec.iov_base = ip; vec.iov_len = len; ret = kernel_sendmsg(sock,&msg,&vec,1,len); if (ret < 0) { pr_err("sendmsg return code %d\n",ret); kfree(frame); // 错误分支补充缓冲区释放逻辑 return false; } kfree(frame); return true; }
- 如果你当前的调用上下文是原子上下文无法接受阻塞,建议替换发送方案,改用
dev_queue_xmit直接向网卡提交skb发送,性能更高且不存在阻塞风险。
内容的提问来源于stack exchange,提问作者Jordan
相关产品推荐
相关产品推荐

