* [PATCH net-next] tools: ynl: make ynl.c more c++ friendly
@ 2025-08-14 16:44 Stanislav Fomichev
2025-08-14 21:29 ` Jacob Keller
2025-08-14 22:27 ` Jakub Kicinski
0 siblings, 2 replies; 5+ messages in thread
From: Stanislav Fomichev @ 2025-08-14 16:44 UTC (permalink / raw)
To: netdev
Cc: davem, edumazet, kuba, pabeni, donald.hunter, horms, jstancek,
sdf, jacob.e.keller, linux-kernel
Compiling ynl.c in a C++ code base requires invoking C compiler and
using extern "C" for the headers. To make it easier, we can add
small changes to the ynl.c file to make it palatable to the native
C++ compiler. The changes are:
- avoid using void* pointer arithmetic, use char* instead
- avoid implicit void* type casts, add c-style explicit casts
- avoid implicit int->enum type casts, add c-style explicit casts
- avoid anonymous structs (for type casts)
- namespacify cpp version, this should let us compile both ynl.c
as c and ynl.c as cpp in the same binary (YNL_CPP can be used
to enable/disable namespacing)
Also add test_cpp rule to make sure ynl.c won't break C++ in the future.
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
---
tools/net/ynl/lib/Makefile | 5 +++-
tools/net/ynl/lib/ynl-priv.h | 11 ++++++-
tools/net/ynl/lib/ynl.c | 58 +++++++++++++++++++++---------------
tools/net/ynl/lib/ynl.h | 19 +++++++++---
4 files changed, 63 insertions(+), 30 deletions(-)
diff --git a/tools/net/ynl/lib/Makefile b/tools/net/ynl/lib/Makefile
index 4b2b98704ff9..94f8dc4a31d1 100644
--- a/tools/net/ynl/lib/Makefile
+++ b/tools/net/ynl/lib/Makefile
@@ -11,7 +11,7 @@ OBJS=$(patsubst %.c,%.o,${SRCS})
include $(wildcard *.d)
-all: ynl.a
+all: ynl.a test_cpp
ynl.a: $(OBJS)
@echo -e "\tAR $@"
@@ -23,6 +23,9 @@ ynl.a: $(OBJS)
distclean: clean
rm -f *.a
+test_cpp: ynl.c
+ $(COMPILE.cpp) -DYNL_CPP -o ynl.cc.o $<
+
%.o: %.c
$(COMPILE.c) -MMD -c -o $@ $<
diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h
index 824777d7e05e..1dbb14e760e6 100644
--- a/tools/net/ynl/lib/ynl-priv.h
+++ b/tools/net/ynl/lib/ynl-priv.h
@@ -6,6 +6,10 @@
#include <stddef.h>
#include <linux/types.h>
+#if defined(__cplusplus) && defined(YNL_CPP)
+namespace ynl_cpp {
+#endif
+
struct ynl_parse_arg;
/*
@@ -224,7 +228,7 @@ static inline void *ynl_attr_data_end(const struct nlattr *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))
+ (attr) = ynl_attr_next((char *)start + len, attr))
static inline struct nlattr *
ynl_attr_if_good(const void *end, struct nlattr *attr)
@@ -467,4 +471,9 @@ ynl_attr_put_sint(struct nlmsghdr *nlh, __u16 type, __s64 data)
else
ynl_attr_put_s64(nlh, type, data);
}
+
+#if defined(__cplusplus) && defined(YNL_CPP)
+} // namespace ynl_cpp
+#endif
+
#endif
diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c
index 2a169c3c0797..9155b4d5b9f9 100644
--- a/tools/net/ynl/lib/ynl.c
+++ b/tools/net/ynl/lib/ynl.c
@@ -11,6 +11,10 @@
#include "ynl.h"
+#if defined(__cplusplus) && defined(YNL_CPP)
+namespace ynl_cpp {
+#endif
+
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(*arr))
#define __yerr_msg(yse, _msg...) \
@@ -23,13 +27,13 @@
} \
})
-#define __yerr_code(yse, _code...) \
- ({ \
- struct ynl_error *_yse = (yse); \
- \
- if (_yse) { \
- _yse->code = _code; \
- } \
+#define __yerr_code(yse, _code...) \
+ ({ \
+ struct ynl_error *_yse = (yse); \
+ \
+ if (_yse) { \
+ _yse->code = (enum ynl_error_code)_code; \
+ } \
})
#define __yerr(yse, _code, _msg...) \
@@ -149,7 +153,7 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off,
return n;
}
- data_len = end - start;
+ data_len = (char *)end - (char *)start;
ynl_attr_for_each_payload(start, data_len, attr) {
astart_off = (char *)attr - (char *)start;
@@ -192,7 +196,7 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off,
off -= sizeof(struct nlattr);
start = ynl_attr_data(attr);
- end = start + ynl_attr_data_len(attr);
+ end = (char *)start + ynl_attr_data_len(attr);
return n + ynl_err_walk(ys, start, end, off, next_pol,
&str[n], str_sz - n, nest_pol);
@@ -325,12 +329,12 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
static int
ynl_cb_error(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
{
- const struct nlmsgerr *err = ynl_nlmsg_data(nlh);
+ const struct nlmsgerr *err = (struct nlmsgerr *)ynl_nlmsg_data(nlh);
unsigned int hlen;
int code;
code = err->error >= 0 ? err->error : -err->error;
- yarg->ys->err.code = code;
+ yarg->ys->err.code = (enum ynl_error_code)code;
errno = code;
hlen = sizeof(*err);
@@ -348,7 +352,7 @@ static int ynl_cb_done(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
err = *(int *)NLMSG_DATA(nlh);
if (err < 0) {
- yarg->ys->err.code = -err;
+ yarg->ys->err.code = (enum ynl_error_code)-err;
errno = -err;
ynl_ext_ack_check(yarg->ys, nlh, sizeof(int));
@@ -366,7 +370,7 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr)
unsigned int type, len;
unsigned char *data;
- data = ynl_attr_data(attr);
+ data = (unsigned char *)ynl_attr_data(attr);
len = ynl_attr_data_len(attr);
type = ynl_attr_type(attr);
if (type > yarg->rsp_policy->max_attr) {
@@ -463,7 +467,7 @@ int ynl_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name,
static void ynl_err_reset(struct ynl_sock *ys)
{
- ys->err.code = 0;
+ ys->err.code = YNL_ERROR_NONE;
ys->err.attr_offs = 0;
ys->err.msg[0] = 0;
}
@@ -643,8 +647,8 @@ ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts)
if (!ys->n_mcast_groups)
return 0;
- ys->mcast_groups = calloc(ys->n_mcast_groups,
- sizeof(*ys->mcast_groups));
+ ys->mcast_groups = (struct ynl_sock_mcast *)calloc(
+ ys->n_mcast_groups, sizeof(*ys->mcast_groups));
if (!ys->mcast_groups)
return YNL_PARSE_CB_ERROR;
@@ -741,7 +745,8 @@ ynl_sock_create(const struct ynl_family *yf, struct ynl_error *yse)
int sock_type;
int one = 1;
- ys = malloc(sizeof(*ys) + 2 * YNL_SOCKET_BUFFER_SIZE);
+ ys = (struct ynl_sock *)malloc(sizeof(*ys) +
+ 2 * YNL_SOCKET_BUFFER_SIZE);
if (!ys)
return NULL;
memset(ys, 0, sizeof(*ys));
@@ -878,7 +883,7 @@ static int ynl_ntf_parse(struct ynl_sock *ys, const struct nlmsghdr *nlh)
} else {
struct genlmsghdr *gehdr;
- gehdr = ynl_nlmsg_data(nlh);
+ gehdr = (struct genlmsghdr *)ynl_nlmsg_data(nlh);
cmd = gehdr->cmd;
}
@@ -888,7 +893,7 @@ static int ynl_ntf_parse(struct ynl_sock *ys, const struct nlmsghdr *nlh)
if (!info->cb)
return YNL_PARSE_CB_ERROR;
- rsp = calloc(1, info->alloc_sz);
+ rsp = (struct ynl_ntf_base_type *)calloc(1, info->alloc_sz);
rsp->free = info->free;
yarg.data = rsp->data;
yarg.rsp_policy = info->policy;
@@ -933,7 +938,8 @@ int ynl_ntf_check(struct ynl_sock *ys)
/* YNL specific helpers used by the auto-generated code */
-struct ynl_dump_list_type *YNL_LIST_END = (void *)(0xb4d123);
+struct ynl_dump_list_type *YNL_LIST_END =
+ (struct ynl_dump_list_type *)(void *)(0xb4d123);
void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd)
{
@@ -962,7 +968,7 @@ ynl_check_alien(struct ynl_sock *ys, const struct nlmsghdr *nlh, __u32 rsp_cmd)
return -1;
}
- gehdr = ynl_nlmsg_data(nlh);
+ gehdr = (struct genlmsghdr *)ynl_nlmsg_data(nlh);
if (gehdr->cmd != rsp_cmd)
return ynl_ntf_parse(ys, nlh);
}
@@ -973,7 +979,7 @@ ynl_check_alien(struct ynl_sock *ys, const struct nlmsghdr *nlh, __u32 rsp_cmd)
static
int ynl_req_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg)
{
- struct ynl_req_state *yrs = (void *)yarg;
+ struct ynl_req_state *yrs = (struct ynl_req_state *)yarg;
int ret;
ret = ynl_check_alien(yrs->yarg.ys, nlh, yrs->rsp_cmd);
@@ -1006,7 +1012,7 @@ int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
static int
ynl_dump_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *data)
{
- struct ynl_dump_state *ds = (void *)data;
+ struct ynl_dump_state *ds = (struct ynl_dump_state *)data;
struct ynl_dump_list_type *obj;
struct ynl_parse_arg yarg = {};
int ret;
@@ -1015,7 +1021,7 @@ ynl_dump_trampoline(const struct nlmsghdr *nlh, struct ynl_parse_arg *data)
if (ret)
return ret < 0 ? YNL_PARSE_CB_ERROR : YNL_PARSE_CB_OK;
- obj = calloc(1, ds->alloc_sz);
+ obj = (struct ynl_dump_list_type *)calloc(1, ds->alloc_sz);
if (!obj)
return YNL_PARSE_CB_ERROR;
@@ -1066,3 +1072,7 @@ int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
yds->first = ynl_dump_end(yds);
return -1;
}
+
+#if defined(__cplusplus) && defined(YNL_CPP)
+} // namespace ynl_cpp
+#endif
diff --git a/tools/net/ynl/lib/ynl.h b/tools/net/ynl/lib/ynl.h
index db7c0591a63f..47a8652f056f 100644
--- a/tools/net/ynl/lib/ynl.h
+++ b/tools/net/ynl/lib/ynl.h
@@ -9,6 +9,10 @@
#include "ynl-priv.h"
+#if defined(__cplusplus) && defined(YNL_CPP)
+namespace ynl_cpp {
+#endif
+
enum ynl_error_code {
YNL_ERROR_NONE = 0,
__YNL_ERRNO_END = 4096,
@@ -56,6 +60,11 @@ struct ynl_family {
unsigned int ntf_info_size;
};
+struct ynl_sock_mcast {
+ unsigned int id;
+ char name[GENL_NAMSIZ];
+};
+
/**
* struct ynl_sock - YNL wrapped netlink socket
* @err: YNL error descriptor, cleared on every request.
@@ -71,10 +80,7 @@ struct ynl_sock {
__u16 family_id;
unsigned int n_mcast_groups;
- struct {
- unsigned int id;
- char name[GENL_NAMSIZ];
- } *mcast_groups;
+ struct ynl_sock_mcast *mcast_groups;
struct ynl_ntf_base_type *ntf_first;
struct ynl_ntf_base_type **ntf_last_next;
@@ -140,4 +146,9 @@ static inline bool ynl_has_ntf(struct ynl_sock *ys)
struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys);
void ynl_ntf_free(struct ynl_ntf_base_type *ntf);
+
+#if defined(__cplusplus) && defined(YNL_CPP)
+} // namespace ynl_cpp
+#endif
+
#endif
--
2.50.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH net-next] tools: ynl: make ynl.c more c++ friendly
2025-08-14 16:44 [PATCH net-next] tools: ynl: make ynl.c more c++ friendly Stanislav Fomichev
@ 2025-08-14 21:29 ` Jacob Keller
2025-08-14 22:27 ` Jakub Kicinski
1 sibling, 0 replies; 5+ messages in thread
From: Jacob Keller @ 2025-08-14 21:29 UTC (permalink / raw)
To: Stanislav Fomichev, netdev
Cc: davem, edumazet, kuba, pabeni, donald.hunter, horms, jstancek,
linux-kernel
[-- Attachment #1.1: Type: text/plain, Size: 1181 bytes --]
On 8/14/2025 9:44 AM, Stanislav Fomichev wrote:
> Compiling ynl.c in a C++ code base requires invoking C compiler and
> using extern "C" for the headers. To make it easier, we can add
> small changes to the ynl.c file to make it palatable to the native
> C++ compiler. The changes are:
> - avoid using void* pointer arithmetic, use char* instead
> - avoid implicit void* type casts, add c-style explicit casts
> - avoid implicit int->enum type casts, add c-style explicit casts
> - avoid anonymous structs (for type casts)
> - namespacify cpp version, this should let us compile both ynl.c
> as c and ynl.c as cpp in the same binary (YNL_CPP can be used
> to enable/disable namespacing)
>
The changes seem ok to me. Obviously these violate several of the usual
kernel style guidelines.. But this is a library which has a lot more
reason to be compiled with C++.
> Also add test_cpp rule to make sure ynl.c won't break C++ in the future.
>
Thanks. Is this run in some part of automation so we can catch issues
from future patches? Ah. I see it is run as part of the normal "all"
target. Ok.
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net-next] tools: ynl: make ynl.c more c++ friendly
2025-08-14 16:44 [PATCH net-next] tools: ynl: make ynl.c more c++ friendly Stanislav Fomichev
2025-08-14 21:29 ` Jacob Keller
@ 2025-08-14 22:27 ` Jakub Kicinski
2025-08-14 23:36 ` Stanislav Fomichev
1 sibling, 1 reply; 5+ messages in thread
From: Jakub Kicinski @ 2025-08-14 22:27 UTC (permalink / raw)
To: Stanislav Fomichev
Cc: netdev, davem, edumazet, pabeni, donald.hunter, horms, jstancek,
jacob.e.keller, linux-kernel
On Thu, 14 Aug 2025 09:44:13 -0700 Stanislav Fomichev wrote:
> Compiling ynl.c in a C++ code base requires invoking C compiler and
> using extern "C" for the headers. To make it easier, we can add
> small changes to the ynl.c file to make it palatable to the native
> C++ compiler. The changes are:
> - avoid using void* pointer arithmetic, use char* instead
> - avoid implicit void* type casts, add c-style explicit casts
> - avoid implicit int->enum type casts, add c-style explicit casts
> - avoid anonymous structs (for type casts)
> - namespacify cpp version, this should let us compile both ynl.c
> as c and ynl.c as cpp in the same binary (YNL_CPP can be used
> to enable/disable namespacing)
>
> Also add test_cpp rule to make sure ynl.c won't break C++ in the future.
As I mentioned in person, ynl-cpp is a separate thing, and you'd all
benefit from making it more C++ than going the other way and massaging
YNL C.
With that said, commenting below on the few that I think would be okay.
> @@ -224,7 +228,7 @@ static inline void *ynl_attr_data_end(const struct nlattr *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))
> + (attr) = ynl_attr_next((char *)start + len, attr))
okay
> @@ -149,7 +153,7 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off,
> return n;
> }
>
> - data_len = end - start;
> + data_len = (char *)end - (char *)start;
can we make the arguments char * instead of the casts?
> static void ynl_err_reset(struct ynl_sock *ys)
> {
> - ys->err.code = 0;
> + ys->err.code = YNL_ERROR_NONE;
sure
> @@ -56,6 +60,11 @@ struct ynl_family {
> unsigned int ntf_info_size;
> };
>
> +struct ynl_sock_mcast {
struct ynl_mcast_grp
> + unsigned int id;
> + char name[GENL_NAMSIZ];
> +};
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net-next] tools: ynl: make ynl.c more c++ friendly
2025-08-14 22:27 ` Jakub Kicinski
@ 2025-08-14 23:36 ` Stanislav Fomichev
2025-08-15 0:05 ` Jakub Kicinski
0 siblings, 1 reply; 5+ messages in thread
From: Stanislav Fomichev @ 2025-08-14 23:36 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Stanislav Fomichev, netdev, davem, edumazet, pabeni,
donald.hunter, horms, jstancek, jacob.e.keller, linux-kernel
On 08/14, Jakub Kicinski wrote:
> On Thu, 14 Aug 2025 09:44:13 -0700 Stanislav Fomichev wrote:
> > Compiling ynl.c in a C++ code base requires invoking C compiler and
> > using extern "C" for the headers. To make it easier, we can add
> > small changes to the ynl.c file to make it palatable to the native
> > C++ compiler. The changes are:
> > - avoid using void* pointer arithmetic, use char* instead
> > - avoid implicit void* type casts, add c-style explicit casts
> > - avoid implicit int->enum type casts, add c-style explicit casts
> > - avoid anonymous structs (for type casts)
> > - namespacify cpp version, this should let us compile both ynl.c
> > as c and ynl.c as cpp in the same binary (YNL_CPP can be used
> > to enable/disable namespacing)
> >
> > Also add test_cpp rule to make sure ynl.c won't break C++ in the future.
>
> As I mentioned in person, ynl-cpp is a separate thing, and you'd all
> benefit from making it more C++ than going the other way and massaging
> YNL C.
>
> With that said, commenting below on the few that I think would be okay.
Ok, and the rest (typecasts mostly and the namespace) - you're not supper
happy about? I can drop that test_cpp if that helps :-)
> > @@ -224,7 +228,7 @@ static inline void *ynl_attr_data_end(const struct nlattr *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))
> > + (attr) = ynl_attr_next((char *)start + len, attr))
>
> okay
>
> > @@ -149,7 +153,7 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off,
> > return n;
> > }
> >
> > - data_len = end - start;
> > + data_len = (char *)end - (char *)start;
>
> can we make the arguments char * instead of the casts?
Let me try. That might require to char-ify helpers like ynl_nlmsg_data_offset
and ynl_nlmsg_end_addr.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net-next] tools: ynl: make ynl.c more c++ friendly
2025-08-14 23:36 ` Stanislav Fomichev
@ 2025-08-15 0:05 ` Jakub Kicinski
0 siblings, 0 replies; 5+ messages in thread
From: Jakub Kicinski @ 2025-08-15 0:05 UTC (permalink / raw)
To: Stanislav Fomichev
Cc: Stanislav Fomichev, netdev, davem, edumazet, pabeni,
donald.hunter, horms, jstancek, jacob.e.keller, linux-kernel
On Thu, 14 Aug 2025 16:36:25 -0700 Stanislav Fomichev wrote:
> > As I mentioned in person, ynl-cpp is a separate thing, and you'd all
> > benefit from making it more C++ than going the other way and massaging
> > YNL C.
> >
> > With that said, commenting below on the few that I think would be okay.
>
> Ok, and the rest (typecasts mostly and the namespace) - you're not supper
> happy about? I can drop that test_cpp if that helps :-)
No, they are illogical from C's standpoint :(
I really don't get the need for the adjustments, the code generator is
obviously different for C++, and that's a major effort. The ynl.c casts
are trivial in comparison.
> > > @@ -149,7 +153,7 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off,
> > > return n;
> > > }
> > >
> > > - data_len = end - start;
> > > + data_len = (char *)end - (char *)start;
> >
> > can we make the arguments char * instead of the casts?
>
> Let me try. That might require to char-ify helpers like ynl_nlmsg_data_offset
> and ynl_nlmsg_end_addr.
Hm, then probably let's leave it as void *
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-08-15 0:05 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-14 16:44 [PATCH net-next] tools: ynl: make ynl.c more c++ friendly Stanislav Fomichev
2025-08-14 21:29 ` Jacob Keller
2025-08-14 22:27 ` Jakub Kicinski
2025-08-14 23:36 ` Stanislav Fomichev
2025-08-15 0:05 ` Jakub Kicinski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).