You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker容器内以太网socket mmap内存失败问题求助

问题:Docker容器中AF_PACKET Socket的mmap内存映射失败(错误码11)

环境与复现信息

  • Docker启动命令:
docker run --rm -it -e "PYTHONUNBUFFERED=1" --network=host snf
  • 程序逻辑:通过AF_PACKET原始Socket配置TPACKET_V3版本、开启混杂模式、设置RX_RING后,启动两个线程各映射64MB内存(总计约128MB)

核心代码片段

int packet_socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP));
if (packet_socket == -1) {
    printf("Can't create AF_PACKET socket: %s\n", strerror(errno));
    return -1;
}

int version = TPACKET_V3;
int setsockopt_packet_version = setsockopt(packet_socket, SOL_PACKET, PACKET_VERSION, &version, sizeof(version));

if (setsockopt_packet_version < 0) {
    printf("Can't set packet v3 version\n");
    return -1;
}

int interface_number = get_interface_number_by_device_name(packet_socket, interface_name);
if (interface_number == -1) {
    printf("Can't get interface number by interface name\n");
    return -1;
}

struct packet_mreq sock_params;
memset(&sock_params, 0, sizeof(sock_params));
sock_params.mr_type = PACKET_MR_ALLMULTI;
sock_params.mr_ifindex = interface_number;

int set_promisc = setsockopt(packet_socket, SOL_PACKET, PACKET_ADD_MEMBERSHIP, (void *) &sock_params, sizeof(sock_params));
if (set_promisc == -1) {
    printf("Can't enable promisc mode: %s\n", strerror(errno));
    return -1;
}

struct sockaddr_ll bind_address;
memset(&bind_address, 0, sizeof(bind_address));

bind_address.sll_family = AF_PACKET;
bind_address.sll_protocol = htons(ETH_P_ALL);
bind_address.sll_ifindex = interface_number;

struct tpacket_req3 req;
memset(&req, 0, sizeof(req));

req.tp_block_size = blocksiz;
req.tp_frame_size = framesiz;
req.tp_block_nr = blocknum;
req.tp_frame_nr = (blocksiz * blocknum) / framesiz;

req.tp_retire_blk_tov = 60; // Timeout in msec
req.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH;

int setsockopt_rx_ring = setsockopt(packet_socket, SOL_PACKET , PACKET_RX_RING , (void *) &req , sizeof(req));
if (setsockopt_rx_ring == -1) {
    printf("Can't enable RX_RING for AF_PACKET socket: %s\n", strerror(errno));
    return -1;
}

uint8_t* mapped_buffer = NULL;
struct iovec *rd = NULL;
mapped_buffer = (uint8_t *) mmap(NULL, req.tp_block_size * req.tp_block_nr, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, packet_socket, 0);
if (mapped_buffer == MAP_FAILED) {
    printf("mmap failed: %d %s\n", errno, strerror(errno));
    return -1;
}

报错输出

mem: 64 mb per iface; cores: 2 per iface 
mmap failed: 11 Resource temporarily unavailable 
mmap failed: 11 Resource temporarily unavailable

已尝试操作

  • 使用sudo运行Docker容器
  • 容器内以root身份启动应用
  • 宿主机直接运行程序无异常

问题原因与解决方法

错误码11(EAGAIN)的核心原因是Docker容器默认的内存锁定(memlock)限制过低,代码中mmap使用了MAP_LOCKED标志,会将映射区域锁定到物理内存,而容器默认memlock配额远不足以支撑128MB的锁定需求。

解决步骤

  1. 启动容器时解除memlock限制
    在Docker启动命令中添加--ulimit memlock=-1:-1参数,将内存锁定的软、硬限制设为无限制:

    docker run --rm -it -e "PYTHONUNBUFFERED=1" --network=host --ulimit memlock=-1:-1 snf
    
  2. 验证限制是否生效
    进入容器后执行以下命令,输出应为unlimited:

    ulimit -l
    
  3. 可选:调整容器内存配额
    如果容器有内存使用上限,需确保分配的内存大于映射需求,例如:

    docker run --rm -it -e "PYTHONUNBUFFERED=1" --network=host --ulimit memlock=-1:-1 --memory=512m snf
    

补充说明

宿主机运行正常是因为root用户默认memlock限制较高或无限制,而Docker容器即使以root身份运行,也会继承daemon的默认资源限制,其中memlock默认值通常仅为几十KB,无法满足128MB的锁定需求。

内容的提问来源于stack exchange,提问作者Jessy James stands with Russia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 21:53:23