Commit 51c352bd authored by Edward Cree's avatar Edward Cree Committed by Jakub Kicinski
Browse files

netlink: add support for formatted extack messages



Include an 80-byte buffer in struct netlink_ext_ack that can be used
 for scnprintf()ed messages.  This does mean that the resulting string
 can't be enumerated, translated etc. in the way NL_SET_ERR_MSG() was
 designed to allow.

Signed-off-by: default avatarEdward Cree <ecree.xilinx@gmail.com>
Reviewed-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent a526a3cc
Loading
Loading
Loading
Loading
+27 −2
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg)

/* this can be increased when necessary - don't expose to userland */
#define NETLINK_MAX_COOKIE_LEN	20
#define NETLINK_MAX_FMTMSG_LEN	80

/**
 * struct netlink_ext_ack - netlink extended ACK report struct
@@ -75,6 +76,8 @@ netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg)
 * @miss_nest: nest missing an attribute (%NULL if missing top level attr)
 * @cookie: cookie data to return to userspace (for success)
 * @cookie_len: actual cookie data length
 * @_msg_buf: output buffer for formatted message strings - don't access
 *	directly, use %NL_SET_ERR_MSG_FMT
 */
struct netlink_ext_ack {
	const char *_msg;
@@ -84,13 +87,13 @@ struct netlink_ext_ack {
	u16 miss_type;
	u8 cookie[NETLINK_MAX_COOKIE_LEN];
	u8 cookie_len;
	char _msg_buf[NETLINK_MAX_FMTMSG_LEN];
};

/* Always use this macro, this allows later putting the
 * message into a separate section or such for things
 * like translation or listing all possible messages.
 * Currently string formatting is not supported (due
 * to the lack of an output buffer.)
 * If string formatting is needed use NL_SET_ERR_MSG_FMT.
 */
#define NL_SET_ERR_MSG(extack, msg) do {		\
	static const char __msg[] = msg;		\
@@ -102,9 +105,31 @@ struct netlink_ext_ack {
		__extack->_msg = __msg;			\
} while (0)

/* We splice fmt with %s at each end even in the snprintf so that both calls
 * can use the same string constant, avoiding its duplication in .ro
 */
#define NL_SET_ERR_MSG_FMT(extack, fmt, args...) do {			       \
	struct netlink_ext_ack *__extack = (extack);			       \
									       \
	if (!__extack)							       \
		break;							       \
	if (snprintf(__extack->_msg_buf, NETLINK_MAX_FMTMSG_LEN,	       \
		     "%s" fmt "%s", "", ##args, "") >=			       \
	    NETLINK_MAX_FMTMSG_LEN)					       \
		net_warn_ratelimited("%s" fmt "%s", "truncated extack: ",      \
				     ##args, "\n");			       \
									       \
	do_trace_netlink_extack(__extack->_msg_buf);			       \
									       \
	__extack->_msg = __extack->_msg_buf;				       \
} while (0)

#define NL_SET_ERR_MSG_MOD(extack, msg)			\
	NL_SET_ERR_MSG((extack), KBUILD_MODNAME ": " msg)

#define NL_SET_ERR_MSG_FMT_MOD(extack, fmt, args...)	\
	NL_SET_ERR_MSG_FMT((extack), KBUILD_MODNAME ": " fmt, ##args)

#define NL_SET_BAD_ATTR_POLICY(extack, attr, pol) do {	\
	if ((extack)) {					\
		(extack)->bad_attr = (attr);		\