为啥内核没有收到我的通用网络链接消息?
Posted
技术标签:
【中文标题】为啥内核没有收到我的通用网络链接消息?【英文标题】:Why isn't the Kernel receveing my generic netlink messages?为什么内核没有收到我的通用网络链接消息? 【发布时间】:2020-07-01 15:18:18 【问题描述】:我正在尝试使用通用 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】:你的实际问题
在 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;
【讨论】:
以上是关于为啥内核没有收到我的通用网络链接消息?的主要内容,如果未能解决你的问题,请参考以下文章