为什么内核不接收我的通用netlink消息?

时间:2020-07-01 15:18:18

标签: c netlink

我正在尝试使用通用网络链接将嵌套属性从用户空间发送到内核,函数nl_send_auto()返回52(这应该是发送给内核的字节数),但是内核没有接收到消息。我的方法有问题吗?这是我在用户空间上编写的代码:

int err = -1;
struct nl_msg *msg;
struct nlattr *attr;
struct nl_sock *sock;
int family;
int send = 0;

if ((sock = nl_socket_alloc()) == NULL)
    return err;

if ((err = genl_connect(sock)))
    return err;

if ((family = genl_ctrl_resolve(sock, FAMILY)) < 0)
    return family;

if ((msg = nlmsg_alloc()) == NULL)
    return err;

if ((genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, FAMILY, 0, 
    NLM_F_REQUEST, CREATE_STATE, 1)) == NULL)
    return err;

if (!(attr = nla_nest_start(msg, KLUA_NL_STATE))){
    nla_nest_cancel(msg, attr);
    return err;
}

if ((ret = nla_put_string(msg, STATE_NAME, cmd->name)) ||
    (ret = nla_put_u32(msg, MAX_ALLOC, cmd->maxalloc)) ||
    (ret = nla_put_u32(msg, CURR_ALLOC, cmd->curralloc))
    )
    return err;

nla_nest_end(msg, attr);

if ((send = nl_send_auto(ctrl->sock, msg)) < 0)
    return send;

printf("All done sended %d bytes\n", send);

nlmsg_free(msg);

此代码显示52,这是发送到内核的字节;

FAMILY宏定义为(在内核空间和用户空间中):

#define FAMILY "family"

我的netlink属性是(用于内核和用户空间):

enum {
    KLUA_NL_STATE,
    STATE_NAME,
    MAX_ALLOC,
    CURR_ALLOC,
    ATTR_COUNT,
#define ATTR_MAX (ATTR_COUNT - 1)
};

我的操作清单是:

enum {
    CREATE_STATE = 16,
};

我的内核代码是:

struct nla_policy lunatik_policy[ATTR_MAX] = {
    [KLUA_NL_STATE] = { .type = NLA_NESTED },
};

static int klua_create_state(struct sk_buff *buff, struct genl_info *info);

static const struct genl_ops l_ops[] = {
    {
        .cmd    = CREATE_STATE,
        .doit   = klua_create_state,
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0)
        /*Before kernel 5.2.0, each operation has its own policy*/
        .policy = lunatik_policy
#endif
    },
};

#define KLUA_NL_STATE_ATTRS_COUNT 3

struct genl_family lunatik_family = {
    .name    = FAMILY,
    .version = 1,
    .maxattr = ATTR_MAX,
    .netnsok = true,
    .policy  = lunatik_policy,
    .module  = THIS_MODULE,
    .ops     = l_ops,
    .n_ops   = ARRAY_SIZE(l_ops),
};

static int klua_create_state(struct sk_buff *buff, struct genl_info *info)
{
    pr_info("I received the message\n");
    return 0;
}

此代码不会在dmesg上打印任何内容,我想知道为什么。

1 个答案:

答案 0 :(得分:0)

您的实际问题

在Linux 5.2重构期间,NLA_F_NESTED标志的语义有所变化。看来您现在需要在致电nla_nest_start()时始终将其包括在内:

if (!(attr = nla_nest_start(msg, KLUA_NL_STATE))){
    ...
}

应该是

if (!(attr = nla_nest_start(msg, NLA_F_NESTED | KLUA_NL_STATE))){
    ...
}

是的,我很清楚libnl库显然应该为您执行此操作,也许将来会这样做,但是很遗憾,这就是我们现在的情况。

也:

enum {
    KLUA_NL_STATE,
    ...
};

属性零始终保留。您需要将其更改为

enum {
    KLUA_NL_STATE = 1,
    ...
};

仅供参考:操作0也已保留,因此很幸运您选择了16。但是将来请记住这一点。

语法问题

这些可能只是复制粘贴错误,但无论如何我还是将它们包括在内,以使登陆此页面的其他人都可以找到示例。

if ((genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, FAMILY, 0, 
    NLM_F_REQUEST, CREATE_STATE, 1)) == NULL)
    return err;

应该是

if ((genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, family, 0, 
    NLM_F_REQUEST, CREATE_STATE, 1)) == NULL)
    return err;

也:

if ((ret = nla_put_string(msg, STATE_NAME, cmd->name)) ||
    (ret = nla_put_u32(msg, MAX_ALLOC, cmd->maxalloc)) ||
    (ret = nla_put_u32(msg, CURR_ALLOC, cmd->curralloc))
    )
    return err;

应该是

if ((err = nla_put_string(msg, STATE_NAME, cmd->name)) ||
    (err = nla_put_u32(msg, MAX_ALLOC, cmd->maxalloc)) ||
    (err = nla_put_u32(msg, CURR_ALLOC, cmd->curralloc))
    )
    return err;

也:

if ((send = nl_send_auto(ctrl->sock, msg)) < 0)
    return send;

应该是

if ((send = nl_send_auto(sock, msg)) < 0)
    return send;