Merge branch 'tools-ynl-stop-using-libmnl'

Jakub Kicinski says:

====================
tools: ynl: stop using libmnl

There is no strong reason to stop using libmnl in ynl but there
are a few small ones which add up.

First (as I remembered immediately after hitting send on v1),
C++ compilers do not like the libmnl for_each macros.
I haven't tried it myself, but having all the code directly
in YNL makes it easier for folks porting to C++ to modify them
and/or make YNL more C++ friendly.

Second, we do much more advanced netlink level parsing in ynl
than libmnl so it's hard to say that libmnl abstracts much from us.
The fact that this series, removing the libmnl dependency, only
adds <300 LoC shows that code savings aren't huge.
OTOH when new types are added (e.g. auto-int) we need to add
compatibility to deal with older version of libmnl (in fact,
even tho patches have been sent months ago, auto-ints are still
not supported in libmnl.git).

Thrid, the dependency makes ynl less self contained, and harder
to vendor in. Whether vendoring libraries into projects is a good
idea is a separate discussion, nonetheless, people want to do it.

Fourth, there are small annoyances with the libmnl APIs which
are hard to fix in backward-compatible ways. See the last patch
for example.

All in all, libmnl is a great library, but with all the code
generation and structured parsing, ynl is better served by going
its own way.

v1: https://lore.kernel.org/all/20240222235614.180876-1-kuba@kernel.org/
====================

Link: https://lore.kernel.org/r/20240227223032.1835527-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2024-02-28 15:25:47 -08:00
commit a68c0320fd
5 changed files with 544 additions and 269 deletions

View File

@ -2,16 +2,16 @@
#ifndef __YNL_C_PRIV_H
#define __YNL_C_PRIV_H 1
#include <stdbool.h>
#include <stddef.h>
#include <libmnl/libmnl.h>
#include <linux/types.h>
struct ynl_parse_arg;
/*
* YNL internals / low level stuff
*/
/* Generic mnl helper code */
enum ynl_policy_type {
YNL_PT_REJECT = 1,
YNL_PT_IGNORE,
@ -27,6 +27,20 @@ enum ynl_policy_type {
YNL_PT_BITFIELD32,
};
enum ynl_parse_result {
YNL_PARSE_CB_ERROR = -1,
YNL_PARSE_CB_STOP = 0,
YNL_PARSE_CB_OK = 1,
};
#define YNL_SOCKET_BUFFER_SIZE (1 << 17)
#define YNL_ARRAY_SIZE(array) (sizeof(array) ? \
sizeof(array) / sizeof(array[0]) : 0)
typedef int (*ynl_parse_cb_t)(const struct nlmsghdr *nlh,
struct ynl_parse_arg *yarg);
struct ynl_policy_attr {
enum ynl_policy_type type;
unsigned int len;
@ -80,8 +94,6 @@ struct ynl_ntf_base_type {
unsigned char data[] __attribute__((aligned(8)));
};
extern mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE];
struct nlmsghdr *
ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
struct nlmsghdr *
@ -89,30 +101,26 @@ ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version);
int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr);
int ynl_recv_ack(struct ynl_sock *ys, int ret);
int ynl_cb_null(const struct nlmsghdr *nlh, void *data);
/* YNL specific helpers used by the auto-generated code */
struct ynl_req_state {
struct ynl_parse_arg yarg;
mnl_cb_t cb;
ynl_parse_cb_t cb;
__u32 rsp_cmd;
};
struct ynl_dump_state {
struct ynl_sock *ys;
struct ynl_policy_nest *rsp_policy;
struct ynl_parse_arg yarg;
void *first;
struct ynl_dump_list_type *last;
size_t alloc_sz;
mnl_cb_t cb;
ynl_parse_cb_t cb;
__u32 rsp_cmd;
};
struct ynl_ntf_info {
struct ynl_policy_nest *policy;
mnl_cb_t cb;
ynl_parse_cb_t cb;
size_t alloc_sz;
void (*free)(struct ynl_ntf_base_type *ntf);
};
@ -125,20 +133,299 @@ int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd);
int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg);
#ifndef MNL_HAS_AUTO_SCALARS
static inline uint64_t mnl_attr_get_uint(const struct nlattr *attr)
/* Netlink message handling helpers */
static inline struct nlmsghdr *ynl_nlmsg_put_header(void *buf)
{
if (mnl_attr_get_payload_len(attr) == 4)
return mnl_attr_get_u32(attr);
return mnl_attr_get_u64(attr);
struct nlmsghdr *nlh = buf;
memset(nlh, 0, sizeof(*nlh));
nlh->nlmsg_len = NLMSG_HDRLEN;
return nlh;
}
static inline unsigned int ynl_nlmsg_data_len(const struct nlmsghdr *nlh)
{
return nlh->nlmsg_len - NLMSG_HDRLEN;
}
static inline void *ynl_nlmsg_data(const struct nlmsghdr *nlh)
{
return (unsigned char *)nlh + NLMSG_HDRLEN;
}
static inline void *
ynl_nlmsg_data_offset(const struct nlmsghdr *nlh, unsigned int offset)
{
return (unsigned char *)nlh + NLMSG_HDRLEN + offset;
}
static inline void *ynl_nlmsg_end_addr(const struct nlmsghdr *nlh)
{
return (char *)nlh + nlh->nlmsg_len;
}
static inline void *
ynl_nlmsg_put_extra_header(struct nlmsghdr *nlh, unsigned int size)
{
void *tail = ynl_nlmsg_end_addr(nlh);
nlh->nlmsg_len += NLMSG_ALIGN(size);
return tail;
}
/* Netlink attribute helpers */
static inline unsigned int ynl_attr_type(const struct nlattr *attr)
{
return attr->nla_type & NLA_TYPE_MASK;
}
static inline unsigned int ynl_attr_data_len(const struct nlattr *attr)
{
return attr->nla_len - NLA_HDRLEN;
}
static inline void *ynl_attr_data(const struct nlattr *attr)
{
return (unsigned char *)attr + NLA_HDRLEN;
}
static inline void *ynl_attr_data_end(const struct nlattr *attr)
{
return ynl_attr_data(attr) + ynl_attr_data_len(attr);
}
#define ynl_attr_for_each(attr, nlh, fixed_hdr_sz) \
for ((attr) = ynl_attr_first(nlh, (nlh)->nlmsg_len, \
NLMSG_HDRLEN + fixed_hdr_sz); attr; \
(attr) = ynl_attr_next(ynl_nlmsg_end_addr(nlh), attr))
#define ynl_attr_for_each_nested(attr, outer) \
for ((attr) = ynl_attr_first(outer, outer->nla_len, \
sizeof(struct nlattr)); attr; \
(attr) = ynl_attr_next(ynl_attr_data_end(outer), attr))
#define ynl_attr_for_each_payload(start, len, attr) \
for ((attr) = ynl_attr_first(start, len, 0); attr; \
(attr) = ynl_attr_next(start + len, attr))
static inline struct nlattr *
ynl_attr_if_good(const void *end, struct nlattr *attr)
{
if (attr + 1 > (const struct nlattr *)end)
return NULL;
if (ynl_attr_data_end(attr) > end)
return NULL;
return attr;
}
static inline struct nlattr *
ynl_attr_next(const void *end, const struct nlattr *prev)
{
struct nlattr *attr;
attr = (void *)((char *)prev + NLA_ALIGN(prev->nla_len));
return ynl_attr_if_good(end, attr);
}
static inline struct nlattr *
ynl_attr_first(const void *start, size_t len, size_t skip)
{
struct nlattr *attr;
attr = (void *)((char *)start + NLMSG_ALIGN(skip));
return ynl_attr_if_good(start + len, attr);
}
static inline struct nlattr *
ynl_attr_nest_start(struct nlmsghdr *nlh, unsigned int attr_type)
{
struct nlattr *attr;
attr = ynl_nlmsg_end_addr(nlh);
attr->nla_type = attr_type | NLA_F_NESTED;
nlh->nlmsg_len += NLA_HDRLEN;
return attr;
}
static inline void
mnl_attr_put_uint(struct nlmsghdr *nlh, uint16_t type, uint64_t data)
ynl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *attr)
{
if ((uint32_t)data == (uint64_t)data)
return mnl_attr_put_u32(nlh, type, data);
return mnl_attr_put_u64(nlh, type, data);
attr->nla_len = (char *)ynl_nlmsg_end_addr(nlh) - (char *)attr;
}
static inline void
ynl_attr_put(struct nlmsghdr *nlh, unsigned int attr_type,
const void *value, size_t size)
{
struct nlattr *attr;
attr = ynl_nlmsg_end_addr(nlh);
attr->nla_type = attr_type;
attr->nla_len = NLA_HDRLEN + size;
memcpy(ynl_attr_data(attr), value, size);
nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len);
}
static inline void
ynl_attr_put_str(struct nlmsghdr *nlh, unsigned int attr_type, const char *str)
{
struct nlattr *attr;
const char *end;
attr = ynl_nlmsg_end_addr(nlh);
attr->nla_type = attr_type;
end = stpcpy(ynl_attr_data(attr), str);
attr->nla_len =
NLA_HDRLEN + NLA_ALIGN(end - (char *)ynl_attr_data(attr));
nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len);
}
static inline const char *ynl_attr_get_str(const struct nlattr *attr)
{
return (const char *)ynl_attr_data(attr);
}
static inline __s8 ynl_attr_get_s8(const struct nlattr *attr)
{
return *(__s8 *)ynl_attr_data(attr);
}
static inline __s16 ynl_attr_get_s16(const struct nlattr *attr)
{
return *(__s16 *)ynl_attr_data(attr);
}
static inline __s32 ynl_attr_get_s32(const struct nlattr *attr)
{
return *(__s32 *)ynl_attr_data(attr);
}
static inline __s64 ynl_attr_get_s64(const struct nlattr *attr)
{
__s64 tmp;
memcpy(&tmp, (unsigned char *)(attr + 1), sizeof(tmp));
return tmp;
}
static inline __u8 ynl_attr_get_u8(const struct nlattr *attr)
{
return *(__u8 *)ynl_attr_data(attr);
}
static inline __u16 ynl_attr_get_u16(const struct nlattr *attr)
{
return *(__u16 *)ynl_attr_data(attr);
}
static inline __u32 ynl_attr_get_u32(const struct nlattr *attr)
{
return *(__u32 *)ynl_attr_data(attr);
}
static inline __u64 ynl_attr_get_u64(const struct nlattr *attr)
{
__u64 tmp;
memcpy(&tmp, (unsigned char *)(attr + 1), sizeof(tmp));
return tmp;
}
static inline void
ynl_attr_put_s8(struct nlmsghdr *nlh, unsigned int attr_type, __s8 value)
{
ynl_attr_put(nlh, attr_type, &value, sizeof(value));
}
static inline void
ynl_attr_put_s16(struct nlmsghdr *nlh, unsigned int attr_type, __s16 value)
{
ynl_attr_put(nlh, attr_type, &value, sizeof(value));
}
static inline void
ynl_attr_put_s32(struct nlmsghdr *nlh, unsigned int attr_type, __s32 value)
{
ynl_attr_put(nlh, attr_type, &value, sizeof(value));
}
static inline void
ynl_attr_put_s64(struct nlmsghdr *nlh, unsigned int attr_type, __s64 value)
{
ynl_attr_put(nlh, attr_type, &value, sizeof(value));
}
static inline void
ynl_attr_put_u8(struct nlmsghdr *nlh, unsigned int attr_type, __u8 value)
{
ynl_attr_put(nlh, attr_type, &value, sizeof(value));
}
static inline void
ynl_attr_put_u16(struct nlmsghdr *nlh, unsigned int attr_type, __u16 value)
{
ynl_attr_put(nlh, attr_type, &value, sizeof(value));
}
static inline void
ynl_attr_put_u32(struct nlmsghdr *nlh, unsigned int attr_type, __u32 value)
{
ynl_attr_put(nlh, attr_type, &value, sizeof(value));
}
static inline void
ynl_attr_put_u64(struct nlmsghdr *nlh, unsigned int attr_type, __u64 value)
{
ynl_attr_put(nlh, attr_type, &value, sizeof(value));
}
static inline __u64 ynl_attr_get_uint(const struct nlattr *attr)
{
switch (ynl_attr_data_len(attr)) {
case 4:
return ynl_attr_get_u32(attr);
case 8:
return ynl_attr_get_u64(attr);
default:
return 0;
}
}
static inline __s64 ynl_attr_get_sint(const struct nlattr *attr)
{
switch (ynl_attr_data_len(attr)) {
case 4:
return ynl_attr_get_s32(attr);
case 8:
return ynl_attr_get_s64(attr);
default:
return 0;
}
}
static inline void
ynl_attr_put_uint(struct nlmsghdr *nlh, __u16 type, __u64 data)
{
if ((__u32)data == (__u64)data)
ynl_attr_put_u32(nlh, type, data);
else
ynl_attr_put_u64(nlh, type, data);
}
static inline void
ynl_attr_put_sint(struct nlmsghdr *nlh, __u16 type, __s64 data)
{
if ((__s32)data == (__s64)data)
ynl_attr_put_s32(nlh, type, data);
else
ynl_attr_put_s64(nlh, type, data);
}
#endif
#endif

View File

@ -3,10 +3,11 @@
#include <poll.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <linux/types.h>
#include <libmnl/libmnl.h>
#include <linux/genetlink.h>
#include <sys/socket.h>
#include "ynl.h"
@ -92,9 +93,9 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off,
data_len = end - start;
mnl_attr_for_each_payload(start, data_len) {
ynl_attr_for_each_payload(start, data_len, attr) {
astart_off = (char *)attr - (char *)start;
aend_off = astart_off + mnl_attr_get_payload_len(attr);
aend_off = astart_off + ynl_attr_data_len(attr);
if (aend_off <= off)
continue;
@ -106,7 +107,7 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off,
off -= astart_off;
type = mnl_attr_get_type(attr);
type = ynl_attr_type(attr);
if (ynl_err_walk_report_one(policy, type, str, str_sz, &n))
return n;
@ -124,8 +125,8 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off,
}
off -= sizeof(struct nlattr);
start = mnl_attr_get_payload(attr);
end = start + mnl_attr_get_payload_len(attr);
start = ynl_attr_data(attr);
end = start + ynl_attr_data_len(attr);
return n + ynl_err_walk(ys, start, end, off, policy->table[type].nest,
&str[n], str_sz - n, nest_pol);
@ -147,14 +148,14 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) {
yerr_msg(ys, "%s", strerror(ys->err.code));
return MNL_CB_OK;
return YNL_PARSE_CB_OK;
}
mnl_attr_for_each(attr, nlh, hlen) {
ynl_attr_for_each(attr, nlh, hlen) {
unsigned int len, type;
len = mnl_attr_get_payload_len(attr);
type = mnl_attr_get_type(attr);
len = ynl_attr_data_len(attr);
type = ynl_attr_type(attr);
if (type > NLMSGERR_ATTR_MAX)
continue;
@ -166,12 +167,12 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
case NLMSGERR_ATTR_MISS_TYPE:
case NLMSGERR_ATTR_MISS_NEST:
if (len != sizeof(__u32))
return MNL_CB_ERROR;
return YNL_PARSE_CB_ERROR;
break;
case NLMSGERR_ATTR_MSG:
str = mnl_attr_get_payload(attr);
str = ynl_attr_get_str(attr);
if (str[len - 1])
return MNL_CB_ERROR;
return YNL_PARSE_CB_ERROR;
break;
default:
break;
@ -185,14 +186,13 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
unsigned int n, off;
void *start, *end;
ys->err.attr_offs = mnl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]);
ys->err.attr_offs = ynl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]);
n = snprintf(bad_attr, sizeof(bad_attr), "%sbad attribute: ",
str ? " (" : "");
start = mnl_nlmsg_get_payload_offset(ys->nlh,
ys->family->hdr_len);
end = mnl_nlmsg_get_payload_tail(ys->nlh);
start = ynl_nlmsg_data_offset(ys->nlh, ys->family->hdr_len);
end = ynl_nlmsg_end_addr(ys->nlh);
off = ys->err.attr_offs;
off -= sizeof(struct nlmsghdr);
@ -211,18 +211,17 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
void *start, *end;
int n2;
type = mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_TYPE]);
type = ynl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_TYPE]);
n = snprintf(miss_attr, sizeof(miss_attr), "%smissing attribute: ",
bad_attr[0] ? ", " : (str ? " (" : ""));
start = mnl_nlmsg_get_payload_offset(ys->nlh,
ys->family->hdr_len);
end = mnl_nlmsg_get_payload_tail(ys->nlh);
start = ynl_nlmsg_data_offset(ys->nlh, ys->family->hdr_len);
end = ynl_nlmsg_end_addr(ys->nlh);
nest_pol = ys->req_policy;
if (tb[NLMSGERR_ATTR_MISS_NEST]) {
off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_NEST]);
off = ynl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_NEST]);
off -= sizeof(struct nlmsghdr);
off -= ys->family->hdr_len;
@ -254,13 +253,13 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
else
yerr_msg(ys, "%s", strerror(ys->err.code));
return MNL_CB_OK;
return YNL_PARSE_CB_OK;
}
static int ynl_cb_error(const struct nlmsghdr *nlh, void *data)
static int
ynl_cb_error(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
{
const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
struct ynl_parse_arg *yarg = data;
const struct nlmsgerr *err = ynl_nlmsg_data(nlh);
unsigned int hlen;
int code;
@ -270,16 +269,15 @@ static int ynl_cb_error(const struct nlmsghdr *nlh, void *data)
hlen = sizeof(*err);
if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
hlen += mnl_nlmsg_get_payload_len(&err->msg);
hlen += ynl_nlmsg_data_len(&err->msg);
ynl_ext_ack_check(yarg->ys, nlh, hlen);
return code ? MNL_CB_ERROR : MNL_CB_STOP;
return code ? YNL_PARSE_CB_ERROR : YNL_PARSE_CB_STOP;
}
static int ynl_cb_done(const struct nlmsghdr *nlh, void *data)
static int ynl_cb_done(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
{
struct ynl_parse_arg *yarg = data;
int err;
err = *(int *)NLMSG_DATA(nlh);
@ -289,23 +287,11 @@ static int ynl_cb_done(const struct nlmsghdr *nlh, void *data)
ynl_ext_ack_check(yarg->ys, nlh, sizeof(int));
return MNL_CB_ERROR;
return YNL_PARSE_CB_ERROR;
}
return MNL_CB_STOP;
return YNL_PARSE_CB_STOP;
}
static int ynl_cb_noop(const struct nlmsghdr *nlh, void *data)
{
return MNL_CB_OK;
}
mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE] = {
[NLMSG_NOOP] = ynl_cb_noop,
[NLMSG_ERROR] = ynl_cb_error,
[NLMSG_DONE] = ynl_cb_done,
[NLMSG_OVERRUN] = ynl_cb_noop,
};
/* Attribute validation */
int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr)
@ -314,9 +300,9 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr)
unsigned int type, len;
unsigned char *data;
data = mnl_attr_get_payload(attr);
len = mnl_attr_get_payload_len(attr);
type = mnl_attr_get_type(attr);
data = ynl_attr_data(attr);
len = ynl_attr_data_len(attr);
type = ynl_attr_type(attr);
if (type > yarg->rsp_policy->max_attr) {
yerr(yarg->ys, YNL_ERROR_INTERNAL,
"Internal error, validating unknown attribute");
@ -413,7 +399,7 @@ struct nlmsghdr *ynl_msg_start(struct ynl_sock *ys, __u32 id, __u16 flags)
ynl_err_reset(ys);
nlh = ys->nlh = mnl_nlmsg_put_header(ys->tx_buf);
nlh = ys->nlh = ynl_nlmsg_put_header(ys->tx_buf);
nlh->nlmsg_type = id;
nlh->nlmsg_flags = flags;
nlh->nlmsg_seq = ++ys->seq;
@ -435,7 +421,7 @@ ynl_gemsg_start(struct ynl_sock *ys, __u32 id, __u16 flags,
gehdr.cmd = cmd;
gehdr.version = version;
data = mnl_nlmsg_put_extra_header(nlh, sizeof(gehdr));
data = ynl_nlmsg_put_extra_header(nlh, sizeof(gehdr));
memcpy(data, &gehdr, sizeof(gehdr));
return nlh;
@ -464,7 +450,75 @@ ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version)
cmd, version);
}
int ynl_recv_ack(struct ynl_sock *ys, int ret)
static int ynl_cb_null(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
{
yerr(yarg->ys, YNL_ERROR_UNEXPECT_MSG,
"Received a message when none were expected");
return YNL_PARSE_CB_ERROR;
}
static int
__ynl_sock_read_msgs(struct ynl_parse_arg *yarg, ynl_parse_cb_t cb, int flags)
{
struct ynl_sock *ys = yarg->ys;
const struct nlmsghdr *nlh;
ssize_t len, rem;
int ret;
len = recv(ys->socket, ys->rx_buf, YNL_SOCKET_BUFFER_SIZE, flags);
if (len < 0) {
if (flags & MSG_DONTWAIT && errno == EAGAIN)
return YNL_PARSE_CB_STOP;
return len;
}
ret = YNL_PARSE_CB_STOP;
for (rem = len; rem > 0; NLMSG_NEXT(nlh, rem)) {
nlh = (struct nlmsghdr *)&ys->rx_buf[len - rem];
if (!NLMSG_OK(nlh, rem)) {
yerr(yarg->ys, YNL_ERROR_INV_RESP,
"Invalid message or trailing data in the response.");
return YNL_PARSE_CB_ERROR;
}
if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) {
/* TODO: handle this better */
yerr(yarg->ys, YNL_ERROR_DUMP_INTER,
"Dump interrupted / inconsistent, please retry.");
return YNL_PARSE_CB_ERROR;
}
switch (nlh->nlmsg_type) {
case 0:
yerr(yarg->ys, YNL_ERROR_INV_RESP,
"Invalid message type in the response.");
return YNL_PARSE_CB_ERROR;
case NLMSG_NOOP:
case NLMSG_OVERRUN ... NLMSG_MIN_TYPE - 1:
ret = YNL_PARSE_CB_OK;
break;
case NLMSG_ERROR:
ret = ynl_cb_error(nlh, yarg);
break;
case NLMSG_DONE:
ret = ynl_cb_done(nlh, yarg);
break;
default:
ret = cb(nlh, yarg);
break;
}
}
return ret;
}
static int ynl_sock_read_msgs(struct ynl_parse_arg *yarg, ynl_parse_cb_t cb)
{
return __ynl_sock_read_msgs(yarg, cb, 0);
}
static int ynl_recv_ack(struct ynl_sock *ys, int ret)
{
struct ynl_parse_arg yarg = { .ys = ys, };
@ -474,23 +528,7 @@ int ynl_recv_ack(struct ynl_sock *ys, int ret)
return -1;
}
ret = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE);
if (ret < 0) {
perr(ys, "Socket receive failed");
return ret;
}
return mnl_cb_run(ys->rx_buf, ret, ys->seq, ys->portid,
ynl_cb_null, &yarg);
}
int ynl_cb_null(const struct nlmsghdr *nlh, void *data)
{
struct ynl_parse_arg *yarg = data;
yerr(yarg->ys, YNL_ERROR_UNEXPECT_MSG,
"Received a message when none were expected");
return MNL_CB_ERROR;
return ynl_sock_read_msgs(&yarg, ynl_cb_null);
}
/* Init/fini and genetlink boiler plate */
@ -500,7 +538,7 @@ ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts)
const struct nlattr *entry, *attr;
unsigned int i;
mnl_attr_for_each_nested(attr, mcasts)
ynl_attr_for_each_nested(attr, mcasts)
ys->n_mcast_groups++;
if (!ys->n_mcast_groups)
@ -509,16 +547,16 @@ ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts)
ys->mcast_groups = calloc(ys->n_mcast_groups,
sizeof(*ys->mcast_groups));
if (!ys->mcast_groups)
return MNL_CB_ERROR;
return YNL_PARSE_CB_ERROR;
i = 0;
mnl_attr_for_each_nested(entry, mcasts) {
mnl_attr_for_each_nested(attr, entry) {
if (mnl_attr_get_type(attr) == CTRL_ATTR_MCAST_GRP_ID)
ys->mcast_groups[i].id = mnl_attr_get_u32(attr);
if (mnl_attr_get_type(attr) == CTRL_ATTR_MCAST_GRP_NAME) {
ynl_attr_for_each_nested(entry, mcasts) {
ynl_attr_for_each_nested(attr, entry) {
if (ynl_attr_type(attr) == CTRL_ATTR_MCAST_GRP_ID)
ys->mcast_groups[i].id = ynl_attr_get_u32(attr);
if (ynl_attr_type(attr) == CTRL_ATTR_MCAST_GRP_NAME) {
strncpy(ys->mcast_groups[i].name,
mnl_attr_get_str(attr),
ynl_attr_get_str(attr),
GENL_NAMSIZ - 1);
ys->mcast_groups[i].name[GENL_NAMSIZ - 1] = 0;
}
@ -528,35 +566,35 @@ ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts)
return 0;
}
static int ynl_get_family_info_cb(const struct nlmsghdr *nlh, void *data)
static int
ynl_get_family_info_cb(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
{
struct ynl_parse_arg *yarg = data;
struct ynl_sock *ys = yarg->ys;
const struct nlattr *attr;
bool found_id = true;
mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) {
if (mnl_attr_get_type(attr) == CTRL_ATTR_MCAST_GROUPS)
ynl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) {
if (ynl_attr_type(attr) == CTRL_ATTR_MCAST_GROUPS)
if (ynl_get_family_info_mcast(ys, attr))
return MNL_CB_ERROR;
return YNL_PARSE_CB_ERROR;
if (mnl_attr_get_type(attr) != CTRL_ATTR_FAMILY_ID)
if (ynl_attr_type(attr) != CTRL_ATTR_FAMILY_ID)
continue;
if (mnl_attr_get_payload_len(attr) != sizeof(__u16)) {
if (ynl_attr_data_len(attr) != sizeof(__u16)) {
yerr(ys, YNL_ERROR_ATTR_INVALID, "Invalid family ID");
return MNL_CB_ERROR;
return YNL_PARSE_CB_ERROR;
}
ys->family_id = mnl_attr_get_u16(attr);
ys->family_id = ynl_attr_get_u16(attr);
found_id = true;
}
if (!found_id) {
yerr(ys, YNL_ERROR_ATTR_MISSING, "Family ID missing");
return MNL_CB_ERROR;
return YNL_PARSE_CB_ERROR;
}
return MNL_CB_OK;
return YNL_PARSE_CB_OK;
}
static int ynl_sock_read_family(struct ynl_sock *ys, const char *family_name)
@ -566,22 +604,15 @@ static int ynl_sock_read_family(struct ynl_sock *ys, const char *family_name)
int err;
nlh = ynl_gemsg_start_req(ys, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, 1);
mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, family_name);
ynl_attr_put_str(nlh, CTRL_ATTR_FAMILY_NAME, family_name);
err = mnl_socket_sendto(ys->sock, nlh, nlh->nlmsg_len);
err = send(ys->socket, nlh, nlh->nlmsg_len, 0);
if (err < 0) {
perr(ys, "failed to request socket family info");
return err;
}
err = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE);
if (err <= 0) {
perr(ys, "failed to receive the socket family info");
return err;
}
err = mnl_cb_run2(ys->rx_buf, err, ys->seq, ys->portid,
ynl_get_family_info_cb, &yarg,
ynl_cb_array, ARRAY_SIZE(ynl_cb_array));
err = ynl_sock_read_msgs(&yarg, ynl_get_family_info_cb);
if (err < 0) {
free(ys->mcast_groups);
perr(ys, "failed to receive the socket family info - no such family?");
@ -600,38 +631,54 @@ static int ynl_sock_read_family(struct ynl_sock *ys, const char *family_name)
struct ynl_sock *
ynl_sock_create(const struct ynl_family *yf, struct ynl_error *yse)
{
struct sockaddr_nl addr;
struct ynl_sock *ys;
socklen_t addrlen;
int one = 1;
ys = malloc(sizeof(*ys) + 2 * MNL_SOCKET_BUFFER_SIZE);
ys = malloc(sizeof(*ys) + 2 * YNL_SOCKET_BUFFER_SIZE);
if (!ys)
return NULL;
memset(ys, 0, sizeof(*ys));
ys->family = yf;
ys->tx_buf = &ys->raw_buf[0];
ys->rx_buf = &ys->raw_buf[MNL_SOCKET_BUFFER_SIZE];
ys->rx_buf = &ys->raw_buf[YNL_SOCKET_BUFFER_SIZE];
ys->ntf_last_next = &ys->ntf_first;
ys->sock = mnl_socket_open(NETLINK_GENERIC);
if (!ys->sock) {
ys->socket = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
if (ys->socket < 0) {
__perr(yse, "failed to create a netlink socket");
goto err_free_sock;
}
if (mnl_socket_setsockopt(ys->sock, NETLINK_CAP_ACK,
if (setsockopt(ys->socket, SOL_NETLINK, NETLINK_CAP_ACK,
&one, sizeof(one))) {
__perr(yse, "failed to enable netlink ACK");
goto err_close_sock;
}
if (mnl_socket_setsockopt(ys->sock, NETLINK_EXT_ACK,
if (setsockopt(ys->socket, SOL_NETLINK, NETLINK_EXT_ACK,
&one, sizeof(one))) {
__perr(yse, "failed to enable netlink ext ACK");
goto err_close_sock;
}
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
if (bind(ys->socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
__perr(yse, "unable to bind to a socket address");
goto err_close_sock;;
}
memset(&addr, 0, sizeof(addr));
addrlen = sizeof(addr);
if (getsockname(ys->socket, (struct sockaddr *)&addr, &addrlen) < 0) {
__perr(yse, "unable to read socket address");
goto err_close_sock;;
}
ys->portid = addr.nl_pid;
ys->seq = random();
ys->portid = mnl_socket_get_portid(ys->sock);
if (ynl_sock_read_family(ys, yf->name)) {
if (yse)
@ -642,7 +689,7 @@ ynl_sock_create(const struct ynl_family *yf, struct ynl_error *yse)
return ys;
err_close_sock:
mnl_socket_close(ys->sock);
close(ys->socket);
err_free_sock:
free(ys);
return NULL;
@ -652,7 +699,7 @@ void ynl_sock_destroy(struct ynl_sock *ys)
{
struct ynl_ntf_base_type *ntf;
mnl_socket_close(ys->sock);
close(ys->socket);
while ((ntf = ynl_ntf_dequeue(ys)))
ynl_ntf_free(ntf);
free(ys->mcast_groups);
@ -679,7 +726,7 @@ int ynl_subscribe(struct ynl_sock *ys, const char *grp_name)
return -1;
}
err = mnl_socket_setsockopt(ys->sock, NETLINK_ADD_MEMBERSHIP,
err = setsockopt(ys->socket, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
&ys->mcast_groups[i].id,
sizeof(ys->mcast_groups[i].id));
if (err < 0) {
@ -692,7 +739,7 @@ int ynl_subscribe(struct ynl_sock *ys, const char *grp_name)
int ynl_socket_get_fd(struct ynl_sock *ys)
{
return mnl_socket_get_fd(ys->sock);
return ys->socket;
}
struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys)
@ -718,12 +765,12 @@ static int ynl_ntf_parse(struct ynl_sock *ys, const struct nlmsghdr *nlh)
struct genlmsghdr *gehdr;
int ret;
gehdr = mnl_nlmsg_get_payload(nlh);
gehdr = ynl_nlmsg_data(nlh);
if (gehdr->cmd >= ys->family->ntf_info_size)
return MNL_CB_ERROR;
return YNL_PARSE_CB_ERROR;
info = &ys->family->ntf_info[gehdr->cmd];
if (!info->cb)
return MNL_CB_ERROR;
return YNL_PARSE_CB_ERROR;
rsp = calloc(1, info->alloc_sz);
rsp->free = info->free;
@ -731,7 +778,7 @@ static int ynl_ntf_parse(struct ynl_sock *ys, const struct nlmsghdr *nlh)
yarg.rsp_policy = info->policy;
ret = info->cb(nlh, &yarg);
if (ret <= MNL_CB_STOP)
if (ret <= YNL_PARSE_CB_STOP)
goto err_free;
rsp->family = nlh->nlmsg_type;
@ -740,46 +787,27 @@ static int ynl_ntf_parse(struct ynl_sock *ys, const struct nlmsghdr *nlh)
*ys->ntf_last_next = rsp;
ys->ntf_last_next = &rsp->next;
return MNL_CB_OK;
return YNL_PARSE_CB_OK;
err_free:
info->free(rsp);
return MNL_CB_ERROR;
return YNL_PARSE_CB_ERROR;
}
static int ynl_ntf_trampoline(const struct nlmsghdr *nlh, void *data)
static int
ynl_ntf_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
{
struct ynl_parse_arg *yarg = data;
return ynl_ntf_parse(yarg->ys, nlh);
}
int ynl_ntf_check(struct ynl_sock *ys)
{
struct ynl_parse_arg yarg = { .ys = ys, };
ssize_t len;
int err;
do {
/* libmnl doesn't let us pass flags to the recv to make
* it non-blocking so we need to poll() or peek() :|
*/
struct pollfd pfd = { };
pfd.fd = mnl_socket_get_fd(ys->sock);
pfd.events = POLLIN;
err = poll(&pfd, 1, 1);
if (err < 1)
return err;
len = mnl_socket_recvfrom(ys->sock, ys->rx_buf,
MNL_SOCKET_BUFFER_SIZE);
if (len < 0)
return len;
err = mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid,
ynl_ntf_trampoline, &yarg,
ynl_cb_array, NLMSG_MIN_TYPE);
err = __ynl_sock_read_msgs(&yarg, ynl_ntf_trampoline,
MSG_DONTWAIT);
if (err < 0)
return err;
} while (err > 0);
@ -800,7 +828,7 @@ void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd)
int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg)
{
yerr(yarg->ys, YNL_ERROR_INV_RESP, "Error parsing response: %s", msg);
return MNL_CB_ERROR;
return YNL_PARSE_CB_ERROR;
}
static int
@ -808,27 +836,28 @@ ynl_check_alien(struct ynl_sock *ys, const struct nlmsghdr *nlh, __u32 rsp_cmd)
{
struct genlmsghdr *gehdr;
if (mnl_nlmsg_get_payload_len(nlh) < sizeof(*gehdr)) {
if (ynl_nlmsg_data_len(nlh) < sizeof(*gehdr)) {
yerr(ys, YNL_ERROR_INV_RESP,
"Kernel responded with truncated message");
return -1;
}
gehdr = mnl_nlmsg_get_payload(nlh);
gehdr = ynl_nlmsg_data(nlh);
if (gehdr->cmd != rsp_cmd)
return ynl_ntf_parse(ys, nlh);
return 0;
}
static int ynl_req_trampoline(const struct nlmsghdr *nlh, void *data)
static
int ynl_req_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
{
struct ynl_req_state *yrs = data;
struct ynl_req_state *yrs = (void *)yarg;
int ret;
ret = ynl_check_alien(yrs->yarg.ys, nlh, yrs->rsp_cmd);
if (ret)
return ret < 0 ? MNL_CB_ERROR : MNL_CB_OK;
return ret < 0 ? YNL_PARSE_CB_ERROR : YNL_PARSE_CB_OK;
return yrs->cb(nlh, &yrs->yarg);
}
@ -836,43 +865,34 @@ static int ynl_req_trampoline(const struct nlmsghdr *nlh, void *data)
int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
struct ynl_req_state *yrs)
{
ssize_t len;
int err;
err = mnl_socket_sendto(ys->sock, req_nlh, req_nlh->nlmsg_len);
err = send(ys->socket, req_nlh, req_nlh->nlmsg_len, 0);
if (err < 0)
return err;
do {
len = mnl_socket_recvfrom(ys->sock, ys->rx_buf,
MNL_SOCKET_BUFFER_SIZE);
if (len < 0)
return len;
err = mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid,
ynl_req_trampoline, yrs,
ynl_cb_array, NLMSG_MIN_TYPE);
if (err < 0)
return err;
err = ynl_sock_read_msgs(&yrs->yarg, ynl_req_trampoline);
} while (err > 0);
return 0;
return err;
}
static int ynl_dump_trampoline(const struct nlmsghdr *nlh, void *data)
static int
ynl_dump_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *data)
{
struct ynl_dump_state *ds = data;
struct ynl_dump_state *ds = (void *)data;
struct ynl_dump_list_type *obj;
struct ynl_parse_arg yarg = {};
int ret;
ret = ynl_check_alien(ds->ys, nlh, ds->rsp_cmd);
ret = ynl_check_alien(ds->yarg.ys, nlh, ds->rsp_cmd);
if (ret)
return ret < 0 ? MNL_CB_ERROR : MNL_CB_OK;
return ret < 0 ? YNL_PARSE_CB_ERROR : YNL_PARSE_CB_OK;
obj = calloc(1, ds->alloc_sz);
if (!obj)
return MNL_CB_ERROR;
return YNL_PARSE_CB_ERROR;
if (!ds->first)
ds->first = obj;
@ -880,8 +900,7 @@ static int ynl_dump_trampoline(const struct nlmsghdr *nlh, void *data)
ds->last->next = obj;
ds->last = obj;
yarg.ys = ds->ys;
yarg.rsp_policy = ds->rsp_policy;
yarg = ds->yarg;
yarg.data = &obj->data;
return ds->cb(nlh, &yarg);
@ -899,22 +918,14 @@ static void *ynl_dump_end(struct ynl_dump_state *ds)
int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
struct ynl_dump_state *yds)
{
ssize_t len;
int err;
err = mnl_socket_sendto(ys->sock, req_nlh, req_nlh->nlmsg_len);
err = send(ys->socket, req_nlh, req_nlh->nlmsg_len, 0);
if (err < 0)
return err;
do {
len = mnl_socket_recvfrom(ys->sock, ys->rx_buf,
MNL_SOCKET_BUFFER_SIZE);
if (len < 0)
goto err_close_list;
err = mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid,
ynl_dump_trampoline, yds,
ynl_cb_array, NLMSG_MIN_TYPE);
err = ynl_sock_read_msgs(&yds->yarg, ynl_dump_trampoline);
if (err < 0)
goto err_close_list;
} while (err > 0);

View File

@ -12,6 +12,7 @@ enum ynl_error_code {
YNL_ERROR_NONE = 0,
__YNL_ERRNO_END = 4096,
YNL_ERROR_INTERNAL,
YNL_ERROR_DUMP_INTER,
YNL_ERROR_EXPECT_ACK,
YNL_ERROR_EXPECT_MSG,
YNL_ERROR_UNEXPECT_MSG,
@ -58,7 +59,7 @@ struct ynl_sock {
/* private: */
const struct ynl_family *family;
struct mnl_socket *sock;
int socket;
__u32 seq;
__u32 portid;
__u16 family_id;

View File

@ -9,7 +9,7 @@ ifeq ("$(DEBUG)","1")
CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan
endif
LDLIBS=-lmnl ../lib/ynl.a ../generated/protos.a
LDLIBS=../lib/ynl.a ../generated/protos.a
SRCS=$(wildcard *.c)
BINS=$(patsubst %.c,%,${SRCS})

View File

@ -40,14 +40,6 @@ class BaseNlLib:
def get_family_id(self):
return 'ys->family_id'
def parse_cb_run(self, cb, data, is_dump=False, indent=1):
ind = '\n\t\t' + '\t' * indent + ' '
if is_dump:
return f"mnl_cb_run2(ys->rx_buf, len, 0, 0, {cb}, {data},{ind}ynl_cb_array, NLMSG_MIN_TYPE)"
else:
return f"mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid,{ind}{cb}, {data},{ind}" + \
"ynl_cb_array, NLMSG_MIN_TYPE)"
class Type(SpecAttr):
def __init__(self, family, attr_set, attr, value):
@ -168,15 +160,6 @@ class Type(SpecAttr):
spec = self._attr_policy(policy)
cw.p(f"\t[{self.enum_name}] = {spec},")
def _mnl_type(self):
# mnl does not have helpers for signed integer types
# turn signed type into unsigned
# this only makes sense for scalar types
t = self.type
if t[0] == 's':
t = 'u' + t[1:]
return t
def _attr_typol(self):
raise Exception(f"Type policy not implemented for class type {self.type}")
@ -192,7 +175,7 @@ class Type(SpecAttr):
ri.cw.p(f"{line};")
def _attr_put_simple(self, ri, var, put_type):
line = f"mnl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name})"
line = f"ynl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name})"
self._attr_put_line(ri, var, line)
def attr_put(self, ri, var):
@ -217,7 +200,7 @@ class Type(SpecAttr):
if not self.is_multi_val():
ri.cw.p("if (ynl_attr_validate(yarg, attr))")
ri.cw.p("return MNL_CB_ERROR;")
ri.cw.p("return YNL_PARSE_CB_ERROR;")
if self.presence_type() == 'bit':
ri.cw.p(f"{var}->_present.{self.c_name} = 1;")
@ -264,7 +247,7 @@ class TypeUnused(Type):
return []
def _attr_get(self, ri, var):
return ['return MNL_CB_ERROR;'], None, None
return ['return YNL_PARSE_CB_ERROR;'], None, None
def _attr_typol(self):
return '.type = YNL_PT_REJECT, '
@ -357,9 +340,6 @@ class TypeScalar(Type):
else:
self.type_name = '__' + self.type
def mnl_type(self):
return self._mnl_type()
def _attr_policy(self, policy):
if 'flags-mask' in self.checks or self.is_bitfield:
if self.is_bitfield:
@ -387,10 +367,10 @@ class TypeScalar(Type):
return [f'{self.type_name} {self.c_name}{self.byte_order_comment}']
def attr_put(self, ri, var):
self._attr_put_simple(ri, var, self.mnl_type())
self._attr_put_simple(ri, var, self.type)
def _attr_get(self, ri, var):
return f"{var}->{self.c_name} = mnl_attr_get_{self.mnl_type()}(attr);", None, None
return f"{var}->{self.c_name} = ynl_attr_get_{self.type}(attr);", None, None
def _setter_lines(self, ri, member, presence):
return [f"{member} = {self.c_name};"]
@ -404,7 +384,7 @@ class TypeFlag(Type):
return '.type = YNL_PT_FLAG, '
def attr_put(self, ri, var):
self._attr_put_line(ri, var, f"mnl_attr_put(nlh, {self.enum_name}, 0, NULL)")
self._attr_put_line(ri, var, f"ynl_attr_put(nlh, {self.enum_name}, NULL, 0)")
def _attr_get(self, ri, var):
return [], None, None
@ -446,15 +426,15 @@ class TypeString(Type):
cw.p(f"\t[{self.enum_name}] = {spec},")
def attr_put(self, ri, var):
self._attr_put_simple(ri, var, 'strz')
self._attr_put_simple(ri, var, 'str')
def _attr_get(self, ri, var):
len_mem = var + '->_present.' + self.c_name + '_len'
return [f"{len_mem} = len;",
f"{var}->{self.c_name} = malloc(len + 1);",
f"memcpy({var}->{self.c_name}, mnl_attr_get_str(attr), len);",
f"memcpy({var}->{self.c_name}, ynl_attr_get_str(attr), len);",
f"{var}->{self.c_name}[len] = 0;"], \
['len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr));'], \
['len = strnlen(ynl_attr_get_str(attr), ynl_attr_data_len(attr));'], \
['unsigned int len;']
def _setter_lines(self, ri, member, presence):
@ -493,15 +473,15 @@ class TypeBinary(Type):
return mem
def attr_put(self, ri, var):
self._attr_put_line(ri, var, f"mnl_attr_put(nlh, {self.enum_name}, " +
f"{var}->_present.{self.c_name}_len, {var}->{self.c_name})")
self._attr_put_line(ri, var, f"ynl_attr_put(nlh, {self.enum_name}, " +
f"{var}->{self.c_name}, {var}->_present.{self.c_name}_len)")
def _attr_get(self, ri, var):
len_mem = var + '->_present.' + self.c_name + '_len'
return [f"{len_mem} = len;",
f"{var}->{self.c_name} = malloc(len);",
f"memcpy({var}->{self.c_name}, mnl_attr_get_payload(attr), len);"], \
['len = mnl_attr_get_payload_len(attr);'], \
f"memcpy({var}->{self.c_name}, ynl_attr_data(attr), len);"], \
['len = ynl_attr_data_len(attr);'], \
['unsigned int len;']
def _setter_lines(self, ri, member, presence):
@ -526,11 +506,11 @@ class TypeBitfield32(Type):
return f"NLA_POLICY_BITFIELD32({mask})"
def attr_put(self, ri, var):
line = f"mnl_attr_put(nlh, {self.enum_name}, sizeof(struct nla_bitfield32), &{var}->{self.c_name})"
line = f"ynl_attr_put(nlh, {self.enum_name}, &{var}->{self.c_name}, sizeof(struct nla_bitfield32))"
self._attr_put_line(ri, var, line)
def _attr_get(self, ri, var):
return f"memcpy(&{var}->{self.c_name}, mnl_attr_get_payload(attr), sizeof(struct nla_bitfield32));", None, None
return f"memcpy(&{var}->{self.c_name}, ynl_attr_data(attr), sizeof(struct nla_bitfield32));", None, None
def _setter_lines(self, ri, member, presence):
return [f"memcpy(&{member}, {self.c_name}, sizeof(struct nla_bitfield32));"]
@ -563,7 +543,7 @@ class TypeNest(Type):
def _attr_get(self, ri, var):
get_lines = [f"if ({self.nested_render_name}_parse(&parg, attr))",
"return MNL_CB_ERROR;"]
"return YNL_PARSE_CB_ERROR;"]
init_lines = [f"parg.rsp_policy = &{self.nested_render_name}_nest;",
f"parg.data = &{var}->{self.c_name};"]
return get_lines, init_lines, None
@ -589,9 +569,6 @@ class TypeMultiAttr(Type):
def presence_type(self):
return 'count'
def mnl_type(self):
return self._mnl_type()
def _complex_member_type(self, ri):
if 'type' not in self.attr or self.attr['type'] == 'nest':
return self.nested_struct_type
@ -625,9 +602,9 @@ class TypeMultiAttr(Type):
def attr_put(self, ri, var):
if self.attr['type'] in scalars:
put_type = self.mnl_type()
put_type = self.type
ri.cw.p(f"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)")
ri.cw.p(f"mnl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name}[i]);")
ri.cw.p(f"ynl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name}[i]);")
elif 'type' not in self.attr or self.attr['type'] == 'nest':
ri.cw.p(f"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)")
self._attr_put_line(ri, var, f"{self.nested_render_name}_put(nlh, " +
@ -665,7 +642,7 @@ class TypeArrayNest(Type):
def _attr_get(self, ri, var):
local_vars = ['const struct nlattr *attr2;']
get_lines = [f'attr_{self.c_name} = attr;',
'mnl_attr_for_each_nested(attr2, attr)',
'ynl_attr_for_each_nested(attr2, attr)',
f'\t{var}->n_{self.c_name}++;']
return get_lines, None, local_vars
@ -690,8 +667,8 @@ class TypeNestTypeValue(Type):
local_vars += [f'__u32 {", ".join(tv_names)};']
for level in self.attr["type-value"]:
level = c_lower(level)
get_lines += [f'attr_{level} = mnl_attr_get_payload({prev});']
get_lines += [f'{level} = mnl_attr_get_type(attr_{level});']
get_lines += [f'attr_{level} = ynl_attr_data({prev});']
get_lines += [f'{level} = ynl_attr_type(attr_{level});']
prev = 'attr_' + level
tv_args = f", {', '.join(tv_names)}"
@ -1550,7 +1527,7 @@ def _put_enum_to_str_helper(cw, render_name, map_name, arg_name, enum=None):
cw.block_start()
if enum and enum.type == 'flags':
cw.p(f'{arg_name} = ffs({arg_name}) - 1;')
cw.p(f'if ({arg_name} < 0 || {arg_name} >= (int)MNL_ARRAY_SIZE({map_name}))')
cw.p(f'if ({arg_name} < 0 || {arg_name} >= (int)YNL_ARRAY_SIZE({map_name}))')
cw.p('return NULL;')
cw.p(f'return {map_name}[{arg_name}];')
cw.block_end()
@ -1612,12 +1589,12 @@ def put_req_nested(ri, struct):
ri.cw.block_start()
ri.cw.write_func_lvar('struct nlattr *nest;')
ri.cw.p("nest = mnl_attr_nest_start(nlh, attr_type);")
ri.cw.p("nest = ynl_attr_nest_start(nlh, attr_type);")
for _, arg in struct.member_list():
arg.attr_put(ri, "obj")
ri.cw.p("mnl_attr_nest_end(nlh, nest);")
ri.cw.p("ynl_attr_nest_end(nlh, nest);")
ri.cw.nl()
ri.cw.p('return 0;')
@ -1627,11 +1604,11 @@ def put_req_nested(ri, struct):
def _multi_parse(ri, struct, init_lines, local_vars):
if struct.nested:
iter_line = "mnl_attr_for_each_nested(attr, nested)"
iter_line = "ynl_attr_for_each_nested(attr, nested)"
else:
if ri.fixed_hdr:
local_vars += ['void *hdr;']
iter_line = "mnl_attr_for_each(attr, nlh, yarg->ys->family->hdr_len)"
iter_line = "ynl_attr_for_each(attr, nlh, yarg->ys->family->hdr_len)"
array_nests = set()
multi_attrs = set()
@ -1665,7 +1642,7 @@ def _multi_parse(ri, struct, init_lines, local_vars):
ri.cw.p(f'dst->{arg} = {arg};')
if ri.fixed_hdr:
ri.cw.p('hdr = mnl_nlmsg_get_payload_offset(nlh, sizeof(struct genlmsghdr));')
ri.cw.p('hdr = ynl_nlmsg_data_offset(nlh, sizeof(struct genlmsghdr));')
ri.cw.p(f"memcpy(&dst->_hdr, hdr, sizeof({ri.fixed_hdr}));")
for anest in sorted(all_multi):
aspec = struct[anest]
@ -1674,7 +1651,7 @@ def _multi_parse(ri, struct, init_lines, local_vars):
ri.cw.nl()
ri.cw.block_start(line=iter_line)
ri.cw.p('unsigned int type = mnl_attr_get_type(attr);')
ri.cw.p('unsigned int type = ynl_attr_type(attr);')
ri.cw.nl()
first = True
@ -1694,10 +1671,10 @@ def _multi_parse(ri, struct, init_lines, local_vars):
ri.cw.p(f"dst->n_{aspec.c_name} = n_{aspec.c_name};")
ri.cw.p('i = 0;')
ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;")
ri.cw.block_start(line=f"mnl_attr_for_each_nested(attr, attr_{aspec.c_name})")
ri.cw.block_start(line=f"ynl_attr_for_each_nested(attr, attr_{aspec.c_name})")
ri.cw.p(f"parg.data = &dst->{aspec.c_name}[i];")
ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr, mnl_attr_get_type(attr)))")
ri.cw.p('return MNL_CB_ERROR;')
ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr, ynl_attr_type(attr)))")
ri.cw.p('return YNL_PARSE_CB_ERROR;')
ri.cw.p('i++;')
ri.cw.block_end()
ri.cw.block_end()
@ -1712,13 +1689,13 @@ def _multi_parse(ri, struct, init_lines, local_vars):
if 'nested-attributes' in aspec:
ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;")
ri.cw.block_start(line=iter_line)
ri.cw.block_start(line=f"if (mnl_attr_get_type(attr) == {aspec.enum_name})")
ri.cw.block_start(line=f"if (ynl_attr_type(attr) == {aspec.enum_name})")
if 'nested-attributes' in aspec:
ri.cw.p(f"parg.data = &dst->{aspec.c_name}[i];")
ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr))")
ri.cw.p('return MNL_CB_ERROR;')
ri.cw.p('return YNL_PARSE_CB_ERROR;')
elif aspec.type in scalars:
ri.cw.p(f"dst->{aspec.c_name}[i] = mnl_attr_get_{aspec.mnl_type()}(attr);")
ri.cw.p(f"dst->{aspec.c_name}[i] = ynl_attr_get_{aspec.type}(attr);")
else:
raise Exception('Nest parsing type not supported yet')
ri.cw.p('i++;')
@ -1730,7 +1707,7 @@ def _multi_parse(ri, struct, init_lines, local_vars):
if struct.nested:
ri.cw.p('return 0;')
else:
ri.cw.p('return MNL_CB_OK;')
ri.cw.p('return YNL_PARSE_CB_OK;')
ri.cw.block_end()
ri.cw.nl()
@ -1760,10 +1737,9 @@ def parse_rsp_msg(ri, deref=False):
return
func_args = ['const struct nlmsghdr *nlh',
'void *data']
'struct ynl_parse_arg *yarg']
local_vars = [f'{type_name(ri, "reply", deref=deref)} *dst;',
'struct ynl_parse_arg *yarg = data;',
'const struct nlattr *attr;']
init_lines = ['dst = yarg->data;']
@ -1774,7 +1750,7 @@ def parse_rsp_msg(ri, deref=False):
else:
# Empty reply
ri.cw.block_start()
ri.cw.p('return MNL_CB_OK;')
ri.cw.p('return YNL_PARSE_CB_OK;')
ri.cw.block_end()
ri.cw.nl()
@ -1809,7 +1785,7 @@ def print_req(ri):
if ri.fixed_hdr:
ri.cw.p("hdr_len = sizeof(req->_hdr);")
ri.cw.p("hdr = mnl_nlmsg_put_extra_header(nlh, hdr_len);")
ri.cw.p("hdr = ynl_nlmsg_put_extra_header(nlh, hdr_len);")
ri.cw.p("memcpy(hdr, &req->_hdr, hdr_len);")
ri.cw.nl()
@ -1859,20 +1835,21 @@ def print_dump(ri):
ri.cw.write_func_lvar(local_vars)
ri.cw.p('yds.ys = ys;')
ri.cw.p('yds.yarg.ys = ys;')
ri.cw.p(f"yds.yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;")
ri.cw.p("yds.yarg.data = NULL;")
ri.cw.p(f"yds.alloc_sz = sizeof({type_name(ri, rdir(direction))});")
ri.cw.p(f"yds.cb = {op_prefix(ri, 'reply', deref=True)}_parse;")
if ri.op.value is not None:
ri.cw.p(f'yds.rsp_cmd = {ri.op.enum_name};')
else:
ri.cw.p(f'yds.rsp_cmd = {ri.op.rsp_value};')
ri.cw.p(f"yds.rsp_policy = &{ri.struct['reply'].render_name}_nest;")
ri.cw.nl()
ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);")
if ri.fixed_hdr:
ri.cw.p("hdr_len = sizeof(req->_hdr);")
ri.cw.p("hdr = mnl_nlmsg_put_extra_header(nlh, hdr_len);")
ri.cw.p("hdr = ynl_nlmsg_put_extra_header(nlh, hdr_len);")
ri.cw.p("memcpy(hdr, &req->_hdr, hdr_len);")
ri.cw.nl()
@ -2584,7 +2561,7 @@ def render_user_family(family, cw, prototype):
cw.p('.hdr_len\t= sizeof(struct genlmsghdr),')
if family.ntfs:
cw.p(f".ntf_info\t= {family['name']}_ntf_info,")
cw.p(f".ntf_info_size\t= MNL_ARRAY_SIZE({family['name']}_ntf_info),")
cw.p(f".ntf_info_size\t= YNL_ARRAY_SIZE({family['name']}_ntf_info),")
cw.block_end(line=';')
@ -2700,7 +2677,6 @@ def main():
if args.mode == "user":
if not args.header:
cw.p("#include <libmnl/libmnl.h>")
cw.p("#include <linux/genetlink.h>")
cw.nl()
for one in args.user_header: