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

使用libnftnl(1.2.4)与libmnl(1.0.4)创建nftables表时mnl_cb_run返回‘无效参数’错误的排查求助

解决libnftnl/libmnl创建nftables表时mnl_cb_run返回“无效参数”的问题

我帮你排查了代码里的几个关键问题,这些问题是导致错误的核心原因,下面一步步给你修复方案:

1. 清理无用代码并修复内存泄漏

你一开始调用nfnlmsg_alloc_simple创建了struct nl_msg *msg,但后续完全没用到这个对象,也没释放它,这会造成内存泄漏。直接删掉这部分冗余代码即可。

2. 修正回调函数的消息类型验证逻辑

你的nft_error_cb回调直接假设收到的消息是NLMSG_ERROR类型,但mnl_cb_run会把所有接收到的Netlink消息传给回调。如果遇到非预期的消息类型,直接解析struct nlmsgerr会导致内存访问错误,进而触发mnl_cb_run返回EINVAL(无效参数)。

修改后的安全回调函数:

static int nft_error_cb(const struct nlmsghdr *nlh, void *data) {
    log_info("[DEBUG] nft_error_cb invoked, msg type: %u", nlh->nlmsg_type);

    // 只处理内核返回的ACK/错误消息(NLMSG_ERROR类型)
    if (nlh->nlmsg_type != NLMSG_ERROR) {
        log_info("[DEBUG] Ignoring non-error message type");
        return MNL_CB_OK; // 继续处理其他消息(如果存在)
    }

    struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
    if (err->error == 0) {
        // 收到ACK,说明操作成功
        log_info("[DEBUG] Received success ACK from kernel");
        return MNL_CB_STOP; // 终止回调处理
    }

    // 内核返回具体错误
    int kernel_err = -err->error;
    log_info("[KERNEL ERROR] errno=%d (%s)", kernel_err, strerror(kernel_err));
    return MNL_CB_ERROR; // 告知mnl_cb_run处理出错
}

3. 移除冗余的消息标志位

在nftnl_table_nlmsg_build_hdr中,你添加了NLM_F_REQUEST标志,但这个是Netlink消息的默认要求,libnftnl会自动处理,不需要手动添加。保留NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK即可。

修改后的消息头构建代码:

nlh = nftnl_table_nlmsg_build_hdr(
    buf, NFT_MSG_NEWTABLE, family, NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK, seq
);

4. 完善错误路径的资源释放

你的代码在部分错误路径中没有关闭mnl_socket(比如nftnl_table_alloc失败后),会导致文件句柄泄漏。所有错误分支都要确保socket被关闭、表结构被释放。

完整修复后的核心函数

调整后的nftablehandler_create_table函数:

int nftablehandler_create_table(char* table_name, int family){
    struct mnl_socket *sock = mnl_socket_open(NETLINK_NETFILTER);
    if (!sock) {
        log_info("Error: mnl_socket_open failed");
        return -1;
    }

    if (mnl_socket_bind(sock, 0, MNL_SOCKET_AUTOPID) < 0) {
        log_info("Error: mnl_socket_bind failed");
        mnl_socket_close(sock);
        return -1;
    }

    struct nftnl_table *t = nftnl_table_alloc();
    if (!t) {
        log_info("Error: Could not allocate table structure.\n");
        mnl_socket_close(sock);
        return -1;
    }

    nftnl_table_set_str(t, NFTNL_TABLE_NAME, table_name);
    nftnl_table_set_u32(t, NFTNL_TABLE_FAMILY, family);

    static uint32_t seq_counter = 0;
    uint32_t seq = ++seq_counter;
    uint32_t portid = mnl_socket_get_portid(sock);

    char buf[MNL_SOCKET_BUFFER_SIZE];
    struct nlmsghdr *nlh = nftnl_table_nlmsg_build_hdr(
        buf, NFT_MSG_NEWTABLE, family, NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK, seq
    );
    if (!nlh) {
        log_info("Error: Could not build table message header.\n");
        nftnl_table_free(t);
        mnl_socket_close(sock);
        return -1;
    }

    nftnl_table_nlmsg_build_payload(nlh, t);

    int err = mnl_socket_sendto(sock, nlh, nlh->nlmsg_len);
    if (err < 0){
        log_info("[ERROR][NFTABLE][TABLE CREATION FAILED - SEND][TABLE NAME: %s]", table_name);
        nftnl_table_free(t);
        mnl_socket_close(sock);
        return err;
    }

    err = mnl_socket_recvfrom(sock, buf, sizeof(buf));
    if (err < 0){
        log_info("[ERROR][NFTABLE][TABLE CREATION FAILED - RECV][TABLE NAME: %s]", table_name);
        nftnl_table_free(t);
        mnl_socket_close(sock);
        return err;
    }

    err = mnl_cb_run(buf, err, seq, portid, nft_error_cb, NULL);
    if (err < 0){
        log_info("[ERROR][NFTABLE][CALLBACK FAILED / KERNEL ERROR][TABLE NAME: %s][ERROR: %s]%d", 
                 table_name, strerror(errno), errno);
        nftnl_table_free(t);
        mnl_socket_close(sock);
        return err;
    }

    log_info("[INFO][NFTABLE][TABLE CREATION SUCCESSFUL][TABLE NAME: %s]", table_name);
    nftnl_table_free(t);
    mnl_socket_close(sock);
    return 0;
}

额外注意事项

  • 调用strdup("test_table")后记得手动释放内存:char* table = strdup("test_table"); int res = nftablehandler_create_table(table, family); free(table);
  • 可以用nft list tables命令手动验证表是否创建成功,排除代码外的环境问题。

内容的提问来源于stack exchange,提问作者Vignesh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 06:39:12