lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed,  4 Mar 2020 21:25:06 +0100 (CET)
From:   Michal Kubecek <mkubecek@...e.cz>
To:     John Linville <linville@...driver.com>, netdev@...r.kernel.org
Cc:     Andrew Lunn <andrew@...n.ch>,
        Florian Fainelli <f.fainelli@...il.com>
Subject: [PATCH ethtool v2 06/25] netlink: introduce the netlink interface

Initial part of netlink interface based on genetlink and libmnl. The
netlink interface is available in kernel since 5.6-rc1. This commit only
adds the generic infrastructure but does not override any ethtool command
so that there is no actual change in behaviour.

Netlink handlers for ethtool commands are added as nlfunc members to args
array in ethtool.c. A netlink handler is used if it is available (i.e.
nlfunc is not null) and ethtool succeeds to initialize netlink socket.
If netlink implementation exists for a command but the request is not
supported by kernel (e.g. when new ethtool is used on older kernel), ioctl
implementation is also used as fallback.

Running configure with --disable-netlink completely disables the netlink
interface.

v2:
  - change type of nl_context::suppress_nlerr
  - add nl_context::rtnl_socket

Signed-off-by: Michal Kubecek <mkubecek@...e.cz>
---
 Makefile.am       | 18 +++++++++--
 configure.ac      | 14 ++++++++-
 ethtool.c         | 76 +++++++++++++++++++++++++++++++++++------------
 internal.h        | 12 ++++++++
 netlink/extapi.h  | 31 +++++++++++++++++++
 netlink/netlink.c | 36 ++++++++++++++++++++++
 netlink/netlink.h | 26 ++++++++++++++++
 7 files changed, 191 insertions(+), 22 deletions(-)
 create mode 100644 netlink/extapi.h
 create mode 100644 netlink/netlink.c
 create mode 100644 netlink/netlink.h

diff --git a/Makefile.am b/Makefile.am
index 05beb22be669..b510c3ec8a03 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -7,6 +7,8 @@ EXTRA_DIST = LICENSE ethtool.8 ethtool.spec.in aclocal.m4 ChangeLog autogen.sh
 sbin_PROGRAMS = ethtool
 ethtool_SOURCES = ethtool.c uapi/linux/ethtool.h internal.h \
 		  uapi/linux/net_tstamp.h rxclass.c
+ethtool_CFLAGS = $(AM_CFLAGS)
+ethtool_LDADD = $(LDADD)
 if ETHTOOL_ENABLE_PRETTY_DUMP
 ethtool_SOURCES += \
 		  amd8111e.c de2104x.c dsa.c e100.c e1000.c et131x.c igb.c	\
@@ -22,12 +24,24 @@ bashcompletiondir = $(BASH_COMPLETION_DIR)
 dist_bashcompletion_DATA = shell-completion/bash/ethtool
 endif
 
+if ETHTOOL_ENABLE_NETLINK
+ethtool_SOURCES += \
+		  netlink/netlink.c netlink/netlink.h netlink/extapi.h \
+		  uapi/linux/ethtool_netlink.h \
+		  uapi/linux/netlink.h uapi/linux/genetlink.h \
+		  uapi/linux/rtnetlink.h uapi/linux/if_link.h
+ethtool_CFLAGS += @MNL_CFLAGS@
+ethtool_LDADD += @MNL_LIBS@
+endif
+
 TESTS = test-cmdline test-features
 check_PROGRAMS = test-cmdline test-features
 test_cmdline_SOURCES = test-cmdline.c test-common.c $(ethtool_SOURCES) 
-test_cmdline_CFLAGS = $(AM_FLAGS) -DTEST_ETHTOOL
+test_cmdline_CFLAGS = $(ethtool_CFLAGS) -DTEST_ETHTOOL
+test_cmdline_LDADD = $(ethtool_LDADD)
 test_features_SOURCES = test-features.c test-common.c $(ethtool_SOURCES) 
-test_features_CFLAGS = $(AM_FLAGS) -DTEST_ETHTOOL
+test_features_CFLAGS = $(ethtool_CFLAGS) -DTEST_ETHTOOL
+test_features_LDADD = $(ethtool_LDADD)
 
 dist-hook:
 	cp $(top_srcdir)/ethtool.spec $(distdir)
diff --git a/configure.ac b/configure.ac
index a5c1469f9b63..19e7fcb44fb5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script.
 AC_INIT(ethtool, 5.4, netdev@...r.kernel.org)
 AC_PREREQ(2.52)
 AC_CONFIG_SRCDIR([ethtool.c])
-AM_INIT_AUTOMAKE([gnu])
+AM_INIT_AUTOMAKE([gnu subdir-objects])
 AC_CONFIG_HEADERS([ethtool-config.h])
 
 AM_MAINTAINER_MODE
@@ -66,5 +66,17 @@ AC_SUBST([BASH_COMPLETION_DIR])
 AM_CONDITIONAL([ENABLE_BASH_COMPLETION],
 	       [test "x$with_bash_completion_dir" != xno])
 
+AC_ARG_ENABLE(netlink,
+	      [  --enable-netlink	  enable netlink interface (enabled by default)],
+	      ,
+	      enable_netlink=yes)
+if test x$enable_netlink = xyes; then
+    PKG_PROG_PKG_CONFIG
+    PKG_CHECK_MODULES([MNL], [libmnl])
+    AC_DEFINE(ETHTOOL_ENABLE_NETLINK, 1,
+	      Define this to support netlink interface to talk to kernel.)
+fi
+AM_CONDITIONAL([ETHTOOL_ENABLE_NETLINK], [test x$enable_netlink = xyes])
+
 AC_CONFIG_FILES([Makefile ethtool.spec ethtool.8])
 AC_OUTPUT
diff --git a/ethtool.c b/ethtool.c
index 3186a72644fd..5d1ef537f692 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -48,6 +48,8 @@
 #include <linux/sockios.h>
 #include <linux/netlink.h>
 
+#include "netlink/extapi.h"
+
 #ifndef MAX_ADDR_LEN
 #define MAX_ADDR_LEN	32
 #endif
@@ -5292,6 +5294,7 @@ struct option {
 	const char	*opts;
 	bool		no_dev;
 	int		(*func)(struct cmd_context *);
+	int		(*nlfunc)(struct cmd_context *);
 	const char	*help;
 	const char	*xhelp;
 };
@@ -5856,11 +5859,36 @@ static int do_perqueue(struct cmd_context *ctx)
 	return 0;
 }
 
+static int ioctl_init(struct cmd_context *ctx, bool no_dev)
+{
+	if (no_dev) {
+		ctx->fd = -1;
+		return 0;
+	}
+
+	/* Setup our control structures. */
+	memset(&ctx->ifr, 0, sizeof(ctx->ifr));
+	strcpy(ctx->ifr.ifr_name, ctx->devname);
+
+	/* Open control socket. */
+	ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (ctx->fd < 0)
+		ctx->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+	if (ctx->fd < 0) {
+		perror("Cannot get control socket");
+		return 70;
+	}
+
+	return 0;
+}
+
 int main(int argc, char **argp)
 {
+	int (*nlfunc)(struct cmd_context *) = NULL;
 	int (*func)(struct cmd_context *);
-	struct cmd_context ctx;
+	struct cmd_context ctx = {};
 	bool no_dev;
+	int ret;
 	int k;
 
 	init_global_link_mode_masks();
@@ -5869,7 +5897,6 @@ int main(int argc, char **argp)
 	argp++;
 	argc--;
 
-	ctx.debug = 0;
 	if (*argp && !strcmp(*argp, "--debug")) {
 		char *eptr;
 
@@ -5895,6 +5922,7 @@ int main(int argc, char **argp)
 		argp++;
 		argc--;
 		func = args[k].func;
+		nlfunc = args[k].nlfunc;
 		no_dev = args[k].no_dev;
 		goto opt_found;
 	}
@@ -5904,33 +5932,43 @@ int main(int argc, char **argp)
 	no_dev = false;
 
 opt_found:
+	if (nlfunc) {
+		if (netlink_init(&ctx))
+			nlfunc = NULL;		/* fallback to ioctl() */
+	}
+
 	if (!no_dev) {
 		ctx.devname = *argp++;
 		argc--;
 
-		if (ctx.devname == NULL)
-			exit_bad_args();
-		if (strlen(ctx.devname) >= IFNAMSIZ)
+		/* netlink supports altnames, we will have to recheck against
+		 * IFNAMSIZ later in case of fallback to ioctl
+		 */
+		if (!ctx.devname || strlen(ctx.devname) >= ALTIFNAMSIZ) {
+			netlink_done(&ctx);
 			exit_bad_args();
-
-		/* Setup our control structures. */
-		memset(&ctx.ifr, 0, sizeof(ctx.ifr));
-		strcpy(ctx.ifr.ifr_name, ctx.devname);
-
-		/* Open control socket. */
-		ctx.fd = socket(AF_INET, SOCK_DGRAM, 0);
-		if (ctx.fd < 0)
-			ctx.fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
-		if (ctx.fd < 0) {
-			perror("Cannot get control socket");
-			return 70;
 		}
-	} else {
-		ctx.fd = -1;
 	}
 
 	ctx.argc = argc;
 	ctx.argp = argp;
 
+	if (nlfunc) {
+		ret = nlfunc(&ctx);
+		netlink_done(&ctx);
+		if ((ret != -EOPNOTSUPP) || !func)
+			return (ret >= 0) ? ret : 1;
+	}
+
+	if (ctx.devname && strlen(ctx.devname) >= IFNAMSIZ) {
+		fprintf(stderr,
+			"ethtool: device names longer than %u characters are only allowed with netlink\n",
+			IFNAMSIZ - 1);
+		exit_bad_args();
+	}
+	ret = ioctl_init(&ctx, no_dev);
+	if (ret)
+		return ret;
+
 	return func(&ctx);
 }
diff --git a/internal.h b/internal.h
index 9ec145f55dcb..72a04e638a13 100644
--- a/internal.h
+++ b/internal.h
@@ -25,6 +25,11 @@
 
 #define maybe_unused __attribute__((__unused__))
 
+/* internal for netlink interface */
+#ifdef ETHTOOL_ENABLE_NETLINK
+struct nl_context;
+#endif
+
 /* ethtool.h expects these to be defined by <linux/types.h> */
 #ifndef HAVE_BE_TYPES
 typedef uint16_t __be16;
@@ -44,6 +49,10 @@ typedef int32_t s32;
 #define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
 #endif
 
+#ifndef ALTIFNAMSIZ
+#define ALTIFNAMSIZ 128
+#endif
+
 #include <linux/ethtool.h>
 #include <linux/net_tstamp.h>
 
@@ -203,6 +212,9 @@ struct cmd_context {
 	int argc;		/* number of arguments to the sub-command */
 	char **argp;		/* arguments to the sub-command */
 	unsigned long debug;	/* debugging mask */
+#ifdef ETHTOOL_ENABLE_NETLINK
+	struct nl_context *nlctx;	/* netlink context (opaque) */
+#endif
 };
 
 #ifdef TEST_ETHTOOL
diff --git a/netlink/extapi.h b/netlink/extapi.h
new file mode 100644
index 000000000000..898dc6cfee71
--- /dev/null
+++ b/netlink/extapi.h
@@ -0,0 +1,31 @@
+/*
+ * extapi.h - external interface of netlink code
+ *
+ * Declarations needed by non-netlink code (mostly ethtool.c).
+ */
+
+#ifndef ETHTOOL_EXTAPI_H__
+#define ETHTOOL_EXTAPI_H__
+
+struct cmd_context;
+struct nl_context;
+
+#ifdef ETHTOOL_ENABLE_NETLINK
+
+int netlink_init(struct cmd_context *ctx);
+void netlink_done(struct cmd_context *ctx);
+
+#else /* ETHTOOL_ENABLE_NETLINK */
+
+static inline int netlink_init(struct cmd_context *ctx maybe_unused)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline void netlink_done(struct cmd_context *ctx maybe_unused)
+{
+}
+
+#endif /* ETHTOOL_ENABLE_NETLINK */
+
+#endif /* ETHTOOL_EXTAPI_H__ */
diff --git a/netlink/netlink.c b/netlink/netlink.c
new file mode 100644
index 000000000000..84e188119989
--- /dev/null
+++ b/netlink/netlink.c
@@ -0,0 +1,36 @@
+/*
+ * netlink.c - basic infrastructure for netlink code
+ *
+ * Heart of the netlink interface implementation.
+ */
+
+#include <errno.h>
+
+#include "../internal.h"
+#include "netlink.h"
+#include "extapi.h"
+
+/* initialization */
+
+int netlink_init(struct cmd_context *ctx)
+{
+	struct nl_context *nlctx;
+
+	nlctx = calloc(1, sizeof(*nlctx));
+	if (!nlctx)
+		return -ENOMEM;
+	nlctx->ctx = ctx;
+
+	ctx->nlctx = nlctx;
+
+	return 0;
+}
+
+void netlink_done(struct cmd_context *ctx)
+{
+	if (!ctx->nlctx)
+		return;
+
+	free(ctx->nlctx);
+	ctx->nlctx = NULL;
+}
diff --git a/netlink/netlink.h b/netlink/netlink.h
new file mode 100644
index 000000000000..99636ac8d9c4
--- /dev/null
+++ b/netlink/netlink.h
@@ -0,0 +1,26 @@
+/*
+ * netlink.h - common interface for all netlink code
+ *
+ * Declarations of data structures, global data and helpers for netlink code
+ */
+
+#ifndef ETHTOOL_NETLINK_INT_H__
+#define ETHTOOL_NETLINK_INT_H__
+
+#include <libmnl/libmnl.h>
+#include <linux/netlink.h>
+#include <linux/genetlink.h>
+#include <linux/ethtool_netlink.h>
+
+#define WILDCARD_DEVNAME "*"
+
+struct nl_context {
+	struct cmd_context	*ctx;
+	void			*cmd_private;
+	const char		*devname;
+	bool			is_dump;
+	int			exit_code;
+	unsigned int		suppress_nlerr;
+};
+
+#endif /* ETHTOOL_NETLINK_INT_H__ */
-- 
2.25.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ