netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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).