Commit a68c0320 authored by Jakub Kicinski's avatar Jakub Kicinski

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.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 3bfe9052 7c4a38bf
......@@ -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)
{
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)
{
if (mnl_attr_get_payload_len(attr) == 4)
return mnl_attr_get_u32(attr);
return mnl_attr_get_u64(attr);
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
This diff is collapsed.
......@@ -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;
......
......@@ -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})
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment