Netdev List
 help / color / mirror / Atom feed
* Re: [RFC PATCH net-next v2 09/17] ethtool: implement GET_DRVINFO message
From: Michal Kubecek @ 2018-07-30 14:46 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: netdev, linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <20180730142825.GL13198@lunn.ch>

On Mon, Jul 30, 2018 at 04:28:25PM +0200, Andrew Lunn wrote:
> On Mon, Jul 30, 2018 at 02:53:27PM +0200, Michal Kubecek wrote:
> 
> > +    ETHA_DRVINFO_FWVERSION	(string)	firmware version
> > +    ETHA_DRVINFO_BUSINFO	(string)	device bus address
> > +    ETHA_DRVINFO_EROM_VER	(string)	expansion ROM version
> > +    ETHA_DRVINFO_N_PRIV_FLAGS	(u32)		number of private flags
> > +    ETHA_DRVINFO_N_STATS	(u32)		number of device stats
> 
> I know there is at least one driver that has somewhat dynamic number
> of statistics. It would be better to have the strings and the values
> in the same message, so there is no need to first get the number of
> strings, allocate the memory, get the strings, then get the values.
> 
> > +    ETHA_DRVINFO_TESTINFO_LEN	(u32)		number of test results
> 
> In theory, this also does not need to be fixed. 

This is interesting. It would mean current (ioctl) ethtool approach with
string set may not work correctly either. On the other hand, this should
not be a problem for netlink interface. Statistics are unlikely to
appear in notifications and daemons collecting them periodically will
have to learn with it. Adding test name to notification "test started"
or "test finished" seems quite natural.

> > +    ETHA_DRVINFO_EEDUMP_LEN	(u32)		EEPROM dump size
> > +    ETHA_DRVINFO_REGDUMP_LEN	(u32)		register dump size
> 
> I would suggest removing all these _LEN properties, and let netlink
> return what it needs to return.

Agreed.

Michal Kubecek

^ permalink raw reply

* Re: [net-next 10/13] net/mlx5e: Add support for XDP_REDIRECT in device-out side
From: Tariq Toukan @ 2018-07-30 13:09 UTC (permalink / raw)
  To: Jesper Dangaard Brouer, Saeed Mahameed
  Cc: David S. Miller, netdev, Eugenia Emantayev
In-Reply-To: <20180730150637.0336d65b@redhat.com>



On 30/07/2018 4:06 PM, Jesper Dangaard Brouer wrote:
> 
> On Mon, 30 Jul 2018 14:10:21 +0200 Jesper Dangaard Brouer <brouer@redhat.com> wrote:
> 
>> On Thu, 26 Jul 2018 15:56:44 -0700 Saeed Mahameed <saeedm@mellanox.com> wrote:
>>
>>> +int mlx5e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
>>> +		   u32 flags)
>>> +{
> [...]
>>> +		xdpi.dma_addr = dma_map_single(sq->pdev, xdpf->data, xdpf->len,
>>> +					       DMA_TO_DEVICE);
>>> +		if (unlikely(dma_mapping_error(sq->pdev, xdpi.dma_addr))) {
>>> +			drops++;
>>
>> I think you are missing a xdp_return_frame_rx_napi(xdpf) here.
> 
> I see it already got applied... I'll send a fixup later...
> 

Yes it is applied, I can do it myself. Just let me know what you prefer.

^ permalink raw reply

* Re: [net-next 10/13] net/mlx5e: Add support for XDP_REDIRECT in device-out side
From: Jesper Dangaard Brouer @ 2018-07-30 13:06 UTC (permalink / raw)
  To: Saeed Mahameed
  Cc: David S. Miller, netdev, Tariq Toukan, Eugenia Emantayev, brouer
In-Reply-To: <20180730141021.78b8260f@redhat.com>


On Mon, 30 Jul 2018 14:10:21 +0200 Jesper Dangaard Brouer <brouer@redhat.com> wrote:

> On Thu, 26 Jul 2018 15:56:44 -0700 Saeed Mahameed <saeedm@mellanox.com> wrote:
> 
> > +int mlx5e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
> > +		   u32 flags)
> > +{
[...]
> > +		xdpi.dma_addr = dma_map_single(sq->pdev, xdpf->data, xdpf->len,
> > +					       DMA_TO_DEVICE);
> > +		if (unlikely(dma_mapping_error(sq->pdev, xdpi.dma_addr))) {
> > +			drops++;  
> 
> I think you are missing a xdp_return_frame_rx_napi(xdpf) here.

I see it already got applied... I'll send a fixup later...

-- 
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  LinkedIn: http://www.linkedin.com/in/brouer

^ permalink raw reply

* Re: [net-next 10/13] net/mlx5e: Add support for XDP_REDIRECT in device-out side
From: Tariq Toukan @ 2018-07-30 13:05 UTC (permalink / raw)
  To: Jesper Dangaard Brouer, Saeed Mahameed
  Cc: David S. Miller, netdev, Eugenia Emantayev
In-Reply-To: <20180730141021.78b8260f@redhat.com>



On 30/07/2018 3:10 PM, Jesper Dangaard Brouer wrote:
> On Thu, 26 Jul 2018 15:56:44 -0700 Saeed Mahameed <saeedm@mellanox.com> wrote:
> 
>> +int mlx5e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
>> +		   u32 flags)
>> +{
>> +	struct mlx5e_priv *priv = netdev_priv(dev);
>> +	struct mlx5e_xdpsq *sq;
>> +	int drops = 0;
>> +	int sq_num;
>> +	int i;
>> +
>> +	if (unlikely(!test_bit(MLX5E_STATE_OPENED, &priv->state)))
>> +		return -ENETDOWN;
>> +
>> +	if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
>> +		return -EINVAL;
>> +
>> +	sq_num = smp_processor_id();
>> +
>> +	if (unlikely(sq_num >= priv->channels.num))
>> +		return -ENXIO;
>> +
>> +	sq = &priv->channels.c[sq_num]->xdpsq;
>> +
>> +	if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state)))
>> +		return -ENETDOWN;
>> +
>> +	for (i = 0; i < n; i++) {
>> +		struct xdp_frame *xdpf = frames[i];
>> +		struct mlx5e_xdp_info xdpi;
>> +
>> +		xdpi.dma_addr = dma_map_single(sq->pdev, xdpf->data, xdpf->len,
>> +					       DMA_TO_DEVICE);
>> +		if (unlikely(dma_mapping_error(sq->pdev, xdpi.dma_addr))) {
>> +			drops++;
> 
> I think you are missing a xdp_return_frame_rx_napi(xdpf) here.
> 

Thanks for spotting this!
I'll fix.

>> +			continue;
>> +		}
>> +
>> +		xdpi.xdpf = xdpf;
>> +
>> +		if (unlikely(!mlx5e_xmit_xdp_frame(sq, &xdpi))) {
>> +			xdp_return_frame_rx_napi(xdpf);
>> +			drops++;
>> +		}
>> +	}
>> +
>> +	if (flags & XDP_XMIT_FLUSH)
>> +		mlx5e_xmit_xdp_doorbell(sq);
>> +
>> +	return n - drops;
>> +}
> 
> 

^ permalink raw reply

* [PATCH 4/4] dt-bindings: net: phy: mscc: vsc8531: factorize vsc8531,led-N-mode
From: Quentin Schulz @ 2018-07-30 13:02 UTC (permalink / raw)
  To: andrew, f.fainelli, davem, robh+dt, mark.rutland, devicetree
  Cc: netdev, alexandre.belloni, linux-kernel, thomas.petazzoni,
	Quentin Schulz
In-Reply-To: <20180730130236.3837-1-quentin.schulz@bootlin.com>

VSC8584 supports 4 LEDs while VSC8531 only supports 2. Let's factorize
the documentation for LED mode properties and give the 4 default values
(the first two being shared between VSC8531 and VSC8584).

Signed-off-by: Quentin Schulz <quentin.schulz@bootlin.com>
---
 .../devicetree/bindings/net/mscc-phy-vsc8531.txt | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt b/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt
index 4c7d1d384df0..4d3f8b07a286 100644
--- a/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt
+++ b/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt
@@ -22,14 +22,16 @@ Optional properties:
 			  'vddmac'.
 			  Default value is 0%.
 			  Ref: Table:1 - Edge rate change (below).
-- vsc8531,led-0-mode	: LED mode. Specify how the LED[0] should behave.
-			  Allowed values are define in
+- vsc8531,led-[N]-mode	: LED mode. Specify how the LED[N] should behave.
+			  N depends on the number of LEDs supported by a
+			  PHY.
+			  Allowed values are defined in
 			  "include/dt-bindings/net/mscc-phy-vsc8531.h".
-			  Default value is VSC8531_LINK_1000_ACTIVITY (1).
-- vsc8531,led-1-mode	: LED mode. Specify how the LED[1] should behave.
-			  Allowed values are define in
-			  "include/dt-bindings/net/mscc-phy-vsc8531.h".
-			  Default value is VSC8531_LINK_100_ACTIVITY (2).
+			  Default values are VSC8531_LINK_1000_ACTIVITY (1),
+			  VSC8531_LINK_100_ACTIVITY (2),
+			  VSC8531_LINK_ACTIVITY (0) and
+			  VSC8531_DUPLEX_COLLISION (8).
+
 
 Table: 1 - Edge rate change
 ----------------------------------------------------------------|
-- 
2.17.1

^ permalink raw reply related

* Re: [RFC PATCH net-next v2 09/17] ethtool: implement GET_DRVINFO message
From: Michal Kubecek @ 2018-07-30 14:37 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: netdev, linux-kernel, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <20180730132107.GB10626@nanopsycho>

On Mon, Jul 30, 2018 at 03:21:07PM +0200, Jiri Pirko wrote:
> Mon, Jul 30, 2018 at 02:53:27PM CEST, mkubecek@suse.cz wrote:
> 
> [...]
> 
> >+/* GET_DRVINFO / SET_DRVINFO */
> >+
> >+enum {
> >+	ETHA_DRVINFO_UNSPEC,
> >+	ETHA_DRVINFO_DEV,			/* nest - ETHA_DEV_* */
> >+	ETHA_DRVINFO_DRIVER,			/* string */
> >+	ETHA_DRVINFO_VERSION,			/* string */
> >+	ETHA_DRVINFO_FWVERSION,			/* string */
> >+	ETHA_DRVINFO_BUSINFO,			/* string */
> >+	ETHA_DRVINFO_EROM_VER,			/* string */
> >+	ETHA_DRVINFO_N_PRIV_FLAGS,		/* u32 */
> >+	ETHA_DRVINFO_N_STATS,			/* u32 */
> >+	ETHA_DRVINFO_TESTINFO_LEN,		/* u32 */
> >+	ETHA_DRVINFO_EEDUMP_LEN,		/* u32 */
> >+	ETHA_DRVINFO_REGDUMP_LEN,		/* u32 */
> 
> This is a nice example of why 1:1 ioctl->netlink conversion would be
> a big mistake.
> 
> I understand that for ioclt, getting lengths of various things is
> important. Userspace can prepare buffer for next ioctl which would
> actually do dump transfer. However in netlink, this is totally pointless
> as the dump goes into userspace in multiple netlink messages.

Right, I already mentioned this in the ToDo part of cover letter. It
makes indeed little sense to put this information here - and even less
to put only dome of the counts and lengths.

Michal Kubecek

^ permalink raw reply

* [RFC PATCH ethtool v2 20/23] netlink: add netlink handler for spause (-A)
From: Michal Kubecek @ 2018-07-30 12:57 UTC (permalink / raw)
  To: netdev; +Cc: linux-kernel, John W. Linville
In-Reply-To: <cover.1532954671.git.mkubecek@suse.cz>

Implement "ethtool -A <dev>" subcommand using netlink interface command
ETHNL_CMD_SET_PARAMS.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 ethtool.c        |  3 ++-
 netlink/extapi.h |  1 +
 netlink/params.c | 28 ++++++++++++++++++++++++++++
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/ethtool.c b/ethtool.c
index 792283c46d35..b6e322af9c8a 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -4887,6 +4887,7 @@ static int show_usage(struct cmd_context *ctx);
 #define nl_gfec		NULL
 #define nl_scoalesce	NULL
 #define nl_sring	NULL
+#define nl_spause	NULL
 #endif
 
 static const struct option {
@@ -4912,7 +4913,7 @@ static const struct option {
 	  "		[ msglvl %d[/%d] | type on|off ... [--] ]\n" },
 	{ "-a|--show-pause", 1, do_gpause, nl_gpause,
 	  "Show pause options" },
-	{ "-A|--pause", 1, do_spause, NULL,
+	{ "-A|--pause", 1, do_spause, nl_spause,
 	  "Set pause options",
 	  "		[ autoneg on|off ]\n"
 	  "		[ rx on|off ]\n"
diff --git a/netlink/extapi.h b/netlink/extapi.h
index d6d01ee9eae3..8cf1d0093aaa 100644
--- a/netlink/extapi.h
+++ b/netlink/extapi.h
@@ -26,6 +26,7 @@ int nl_geee(struct cmd_context *ctx);
 int nl_gfec(struct cmd_context *ctx);
 int nl_scoalesce(struct cmd_context *ctx);
 int nl_sring(struct cmd_context *ctx);
+int nl_spause(struct cmd_context *ctx);
 int nl_monitor(struct cmd_context *ctx);
 
 void monitor_usage();
diff --git a/netlink/params.c b/netlink/params.c
index ee0d5e0c51c6..953678a0b227 100644
--- a/netlink/params.c
+++ b/netlink/params.c
@@ -544,3 +544,31 @@ int nl_sring(struct cmd_context *ctx)
 	return nl_set_param(ctx, "-G", sring_params, ETHA_PARAMS_RING,
 			    ETHA_RING_MAX);
 }
+
+static const struct param_parser spause_params[] = {
+	{
+		.arg		= "autoneg",
+		.type		= ETHA_PAUSE_AUTONEG,
+		.handler	= nl_parse_bool,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "rx",
+		.type		= ETHA_PAUSE_RX,
+		.handler	= nl_parse_bool,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "tx",
+		.type		= ETHA_PAUSE_TX,
+		.handler	= nl_parse_bool,
+		.min_argc	= 1,
+	},
+	{}
+};
+
+int nl_spause(struct cmd_context *ctx)
+{
+	return nl_set_param(ctx, "-A", spause_params, ETHA_PARAMS_PAUSE,
+			    ETHA_PAUSE_MAX);
+}
-- 
2.18.0

^ permalink raw reply related

* [RFC PATCH ethtool v2 10/23] netlink: add netlink handler for gfeatures (-k)
From: Michal Kubecek @ 2018-07-30 12:56 UTC (permalink / raw)
  To: netdev; +Cc: linux-kernel, John W. Linville
In-Reply-To: <cover.1532954671.git.mkubecek@suse.cz>

Implement "ethtool -k <dev>" subcommand using netlink interface command
ETHNL_CMD_GET_SETTINGS with ETH_SETTINGS_IM_FEATURES mask.

The implementation tries to emulate legacy flags but the result is not
exactly equal to the ioctl code. In particular, we map netdev features to
legacy flags based on name patterns in off_flag_def[] but this mapping is
slightly different from mapping used by kernel ioctl code.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 common.c           |  30 ++++++
 common.h           |  21 +++++
 ethtool.c          |  70 +++-----------
 netlink/extapi.h   |   1 +
 netlink/monitor.c  |   6 ++
 netlink/settings.c | 226 +++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 296 insertions(+), 58 deletions(-)

diff --git a/common.c b/common.c
index 59897acd2512..db9a360ffae6 100644
--- a/common.c
+++ b/common.c
@@ -283,3 +283,33 @@ void dump_mdix(u8 mdix, u8 mdix_ctrl)
 		fprintf(stdout, "\n");
 	}
 }
+
+const struct off_flag_def off_flag_def[OFF_FLAG_DEF_SIZE] = {
+	{ "rx",     "rx-checksumming",		    "rx-checksum",
+	  ETHTOOL_GRXCSUM, ETHTOOL_SRXCSUM, ETH_FLAG_RXCSUM,	0 },
+	{ "tx",     "tx-checksumming",		    "tx-checksum-*",
+	  ETHTOOL_GTXCSUM, ETHTOOL_STXCSUM, ETH_FLAG_TXCSUM,	0 },
+	{ "sg",     "scatter-gather",		    "tx-scatter-gather*",
+	  ETHTOOL_GSG,	   ETHTOOL_SSG,     ETH_FLAG_SG,	0 },
+	{ "tso",    "tcp-segmentation-offload",	    "tx-tcp*-segmentation",
+	  ETHTOOL_GTSO,	   ETHTOOL_STSO,    ETH_FLAG_TSO,	0 },
+	{ "ufo",    "udp-fragmentation-offload",    "tx-udp-fragmentation",
+	  ETHTOOL_GUFO,	   ETHTOOL_SUFO,    ETH_FLAG_UFO,	0 },
+	{ "gso",    "generic-segmentation-offload", "tx-generic-segmentation",
+	  ETHTOOL_GGSO,	   ETHTOOL_SGSO,    ETH_FLAG_GSO,	0 },
+	{ "gro",    "generic-receive-offload",	    "rx-gro",
+	  ETHTOOL_GGRO,	   ETHTOOL_SGRO,    ETH_FLAG_GRO,	0 },
+	{ "lro",    "large-receive-offload",	    "rx-lro",
+	  0,		   0,		    ETH_FLAG_LRO,
+	  KERNEL_VERSION(2,6,24) },
+	{ "rxvlan", "rx-vlan-offload",		    "rx-vlan-hw-parse",
+	  0,		   0,		    ETH_FLAG_RXVLAN,
+	  KERNEL_VERSION(2,6,37) },
+	{ "txvlan", "tx-vlan-offload",		    "tx-vlan-hw-insert",
+	  0,		   0,		    ETH_FLAG_TXVLAN,
+	  KERNEL_VERSION(2,6,37) },
+	{ "ntuple", "ntuple-filters",		    "rx-ntuple-filter",
+	  0,		   0,		    ETH_FLAG_NTUPLE,	0 },
+	{ "rxhash", "receive-hashing",		    "rx-hashing",
+	  0,		   0,		    ETH_FLAG_RXHASH,	0 },
+};
diff --git a/common.h b/common.h
index a980b844a0ed..36f96ddaa3bd 100644
--- a/common.h
+++ b/common.h
@@ -1,6 +1,8 @@
 #ifndef ETHTOOL_COMMON_H__
 #define ETHTOOL_COMMON_H__
 
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+
 struct flag_info {
 	const char *name;
 	u32 value;
@@ -25,6 +27,25 @@ struct link_mode_info {
 	u8			duplex;
 };
 
+struct off_flag_def {
+	const char *short_name;
+	const char *long_name;
+	const char *kernel_name;
+	u32 get_cmd, set_cmd;
+	u32 value;
+	/* For features exposed through ETHTOOL_GFLAGS, the oldest
+	 * kernel version for which we can trust the result.  Where
+	 * the flag was added at the same time the kernel started
+	 * supporting the feature, this is 0 (to allow for backports).
+	 * Where the feature was supported before the flag was added,
+	 * it is the version that introduced the flag.
+	 */
+	u32 min_kernel_ver;
+};
+
+#define OFF_FLAG_DEF_SIZE 12
+extern const struct off_flag_def off_flag_def[OFF_FLAG_DEF_SIZE];
+
 extern const struct link_mode_info link_modes[];
 extern const unsigned int link_modes_count;
 
diff --git a/ethtool.c b/ethtool.c
index 0b40b96cf9bf..b29086bbabde 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -61,8 +61,6 @@
 #define NETLINK_GENERIC	16
 #endif
 
-#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
-
 static void exit_bad_args(void) __attribute__((noreturn));
 
 static void exit_bad_args(void)
@@ -104,51 +102,6 @@ struct cmdline_info {
 	void *seen_val;
 };
 
-struct off_flag_def {
-	const char *short_name;
-	const char *long_name;
-	const char *kernel_name;
-	u32 get_cmd, set_cmd;
-	u32 value;
-	/* For features exposed through ETHTOOL_GFLAGS, the oldest
-	 * kernel version for which we can trust the result.  Where
-	 * the flag was added at the same time the kernel started
-	 * supporting the feature, this is 0 (to allow for backports).
-	 * Where the feature was supported before the flag was added,
-	 * it is the version that introduced the flag.
-	 */
-	u32 min_kernel_ver;
-};
-static const struct off_flag_def off_flag_def[] = {
-	{ "rx",     "rx-checksumming",		    "rx-checksum",
-	  ETHTOOL_GRXCSUM, ETHTOOL_SRXCSUM, ETH_FLAG_RXCSUM,	0 },
-	{ "tx",     "tx-checksumming",		    "tx-checksum-*",
-	  ETHTOOL_GTXCSUM, ETHTOOL_STXCSUM, ETH_FLAG_TXCSUM,	0 },
-	{ "sg",     "scatter-gather",		    "tx-scatter-gather*",
-	  ETHTOOL_GSG,	   ETHTOOL_SSG,     ETH_FLAG_SG,	0 },
-	{ "tso",    "tcp-segmentation-offload",	    "tx-tcp*-segmentation",
-	  ETHTOOL_GTSO,	   ETHTOOL_STSO,    ETH_FLAG_TSO,	0 },
-	{ "ufo",    "udp-fragmentation-offload",    "tx-udp-fragmentation",
-	  ETHTOOL_GUFO,	   ETHTOOL_SUFO,    ETH_FLAG_UFO,	0 },
-	{ "gso",    "generic-segmentation-offload", "tx-generic-segmentation",
-	  ETHTOOL_GGSO,	   ETHTOOL_SGSO,    ETH_FLAG_GSO,	0 },
-	{ "gro",    "generic-receive-offload",	    "rx-gro",
-	  ETHTOOL_GGRO,	   ETHTOOL_SGRO,    ETH_FLAG_GRO,	0 },
-	{ "lro",    "large-receive-offload",	    "rx-lro",
-	  0,		   0,		    ETH_FLAG_LRO,
-	  KERNEL_VERSION(2,6,24) },
-	{ "rxvlan", "rx-vlan-offload",		    "rx-vlan-hw-parse",
-	  0,		   0,		    ETH_FLAG_RXVLAN,
-	  KERNEL_VERSION(2,6,37) },
-	{ "txvlan", "tx-vlan-offload",		    "tx-vlan-hw-insert",
-	  0,		   0,		    ETH_FLAG_TXVLAN,
-	  KERNEL_VERSION(2,6,37) },
-	{ "ntuple", "ntuple-filters",		    "rx-ntuple-filter",
-	  0,		   0,		    ETH_FLAG_NTUPLE,	0 },
-	{ "rxhash", "receive-hashing",		    "rx-hashing",
-	  0,		   0,		    ETH_FLAG_RXHASH,	0 },
-};
-
 struct feature_def {
 	char name[ETH_GSTRING_LEN];
 	int off_flag_index; /* index in off_flag_def; negative if none match */
@@ -157,7 +110,7 @@ struct feature_def {
 struct feature_defs {
 	size_t n_features;
 	/* Number of features each offload flag is associated with */
-	unsigned int off_flag_matched[ARRAY_SIZE(off_flag_def)];
+	unsigned int off_flag_matched[OFF_FLAG_DEF_SIZE];
 	/* Name and offload flag index for each feature */
 	struct feature_def def[0];
 };
@@ -1325,7 +1278,7 @@ static void dump_features(const struct feature_defs *defs,
 	int indent;
 	int i, j;
 
-	for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
+	for (i = 0; i < OFF_FLAG_DEF_SIZE; i++) {
 		/* Don't show features whose state is unknown on this
 		 * kernel version
 		 */
@@ -1640,7 +1593,7 @@ static struct feature_defs *get_feature_defs(struct cmd_context *ctx)
 		defs->def[i].off_flag_index = -1;
 
 		for (j = 0;
-		     j < ARRAY_SIZE(off_flag_def) &&
+		     j < OFF_FLAG_DEF_SIZE &&
 			     defs->def[i].off_flag_index < 0;
 		     j++) {
 			const char *pattern =
@@ -2082,7 +2035,7 @@ get_features(struct cmd_context *ctx, const struct feature_defs *defs)
 
 	state->off_flags = 0;
 
-	for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
+	for (i = 0; i < OFF_FLAG_DEF_SIZE; i++) {
 		value = off_flag_def[i].value;
 		if (!off_flag_def[i].get_cmd)
 			continue;
@@ -2198,14 +2151,14 @@ static int do_sfeatures(struct cmd_context *ctx)
 	/* Generate cmdline_info for legacy flags and kernel-named
 	 * features, and parse our arguments.
 	 */
-	cmdline_features = calloc(ARRAY_SIZE(off_flag_def) + defs->n_features,
+	cmdline_features = calloc(OFF_FLAG_DEF_SIZE + defs->n_features,
 				  sizeof(cmdline_features[0]));
 	if (!cmdline_features) {
 		perror("Cannot parse arguments");
 		rc = 1;
 		goto err;
 	}
-	for (i = 0; i < ARRAY_SIZE(off_flag_def); i++)
+	for (i = 0; i < OFF_FLAG_DEF_SIZE; i++)
 		flag_to_cmdline_info(off_flag_def[i].short_name,
 				     off_flag_def[i].value,
 				     &off_flags_wanted, &off_flags_mask,
@@ -2215,9 +2168,9 @@ static int do_sfeatures(struct cmd_context *ctx)
 			defs->def[i].name, FEATURE_FIELD_FLAG(i),
 			&FEATURE_WORD(efeatures->features, i, requested),
 			&FEATURE_WORD(efeatures->features, i, valid),
-			&cmdline_features[ARRAY_SIZE(off_flag_def) + i]);
+			&cmdline_features[OFF_FLAG_DEF_SIZE + i]);
 	parse_generic_cmdline(ctx, &any_changed, cmdline_features,
-			      ARRAY_SIZE(off_flag_def) + defs->n_features);
+			      OFF_FLAG_DEF_SIZE + defs->n_features);
 	free(cmdline_features);
 
 	if (!any_changed) {
@@ -2237,7 +2190,7 @@ static int do_sfeatures(struct cmd_context *ctx)
 		 * related features that the user did not specify and that
 		 * are not fixed.  Warn if all related features are fixed.
 		 */
-		for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
+		for (i = 0; i < OFF_FLAG_DEF_SIZE; i++) {
 			int fixed = 1;
 
 			if (!(off_flags_mask & off_flag_def[i].value))
@@ -2278,7 +2231,7 @@ static int do_sfeatures(struct cmd_context *ctx)
 			goto err;
 		}
 	} else {
-		for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
+		for (i = 0; i < OFF_FLAG_DEF_SIZE; i++) {
 			if (!off_flag_def[i].set_cmd)
 				continue;
 			if (off_flags_mask & off_flag_def[i].value) {
@@ -4924,6 +4877,7 @@ static int show_usage(struct cmd_context *ctx);
 #define nl_gdrv		NULL
 #define nl_gset		NULL
 #define nl_sset		NULL
+#define nl_gfeatures	NULL
 #endif
 
 static const struct option {
@@ -4988,7 +4942,7 @@ static const struct option {
 	  "		[ rx-mini N ]\n"
 	  "		[ rx-jumbo N ]\n"
 	  "		[ tx N ]\n" },
-	{ "-k|--show-features|--show-offload", 1, do_gfeatures, NULL,
+	{ "-k|--show-features|--show-offload", 1, do_gfeatures, nl_gfeatures,
 	  "Get state of protocol offload and other features" },
 	{ "-K|--features|--offload", 1, do_sfeatures, NULL,
 	  "Set protocol offload and other features",
diff --git a/netlink/extapi.h b/netlink/extapi.h
index 66573f0b4304..c656ff862687 100644
--- a/netlink/extapi.h
+++ b/netlink/extapi.h
@@ -16,6 +16,7 @@ int netlink_done(struct cmd_context *ctx);
 int nl_gdrv(struct cmd_context *ctx);
 int nl_gset(struct cmd_context *ctx);
 int nl_sset(struct cmd_context *ctx);
+int nl_gfeatures(struct cmd_context *ctx);
 int nl_monitor(struct cmd_context *ctx);
 
 void monitor_usage();
diff --git a/netlink/monitor.c b/netlink/monitor.c
index 32d842611011..e3b8bb46f561 100644
--- a/netlink/monitor.c
+++ b/netlink/monitor.c
@@ -127,6 +127,12 @@ static struct monitor_option monitor_opts[] = {
 				  ETH_SETTINGS_IM_WOLINFO |
 				  ETH_SETTINGS_IM_LINK,
 	},
+	{
+		.pattern	= "-k|--show-features|--show-offload"
+				  "|-K|--features|--offload",
+		.cmd		= ETHNL_CMD_SET_SETTINGS,
+		.info_mask	= ETH_SETTINGS_IM_FEATURES,
+	},
 };
 
 static bool pattern_match(const char *s, const char *pattern)
diff --git a/netlink/settings.c b/netlink/settings.c
index b077a96325e5..51a01b400224 100644
--- a/netlink/settings.c
+++ b/netlink/settings.c
@@ -5,6 +5,7 @@
 #include "../internal.h"
 #include "../common.h"
 #include "netlink.h"
+#include "strset.h"
 #include "parser.h"
 
 /* GET_SETTINGS */
@@ -34,6 +35,219 @@ err:
 	return ret;
 }
 
+uint32_t *get_compact_bitset_value(const struct nlattr *bitset)
+{
+        const struct nlattr *tb[ETHA_BITSET_MAX + 1] = {};
+        DECLARE_ATTR_TB_INFO(tb);
+	unsigned int count;
+        int ret;
+
+        ret = mnl_attr_parse_nested(bitset, attr_cb, &tb_info);
+        if (ret < 0 || !tb[ETHA_BITSET_SIZE] || !tb[ETHA_BITSET_VALUE])
+		return NULL;
+	count = mnl_attr_get_u32(tb[ETHA_BITSET_SIZE]);
+	if (32 * mnl_attr_get_payload_len(tb[ETHA_BITSET_VALUE]) < count)
+		return NULL;
+
+	return mnl_attr_get_payload(tb[ETHA_BITSET_VALUE]);
+}
+
+uint32_t *get_compact_bitset_mask(const struct nlattr *bitset)
+{
+        const struct nlattr *tb[ETHA_BITSET_MAX + 1] = {};
+        DECLARE_ATTR_TB_INFO(tb);
+	unsigned int count;
+        int ret;
+
+        ret = mnl_attr_parse_nested(bitset, attr_cb, &tb_info);
+        if (ret < 0 || !tb[ETHA_BITSET_SIZE] || !tb[ETHA_BITSET_MASK])
+		return NULL;
+	count = mnl_attr_get_u32(tb[ETHA_BITSET_SIZE]);
+	if (32 * mnl_attr_get_payload_len(tb[ETHA_BITSET_MASK]) < count)
+		return NULL;
+
+	return mnl_attr_get_payload(tb[ETHA_BITSET_MASK]);
+}
+
+struct feature_results {
+	uint32_t	*hw;
+	uint32_t	*wanted;
+	uint32_t	*active;
+	uint32_t	*nochange;
+	unsigned int	count;
+	unsigned int	words;
+};
+
+static int prepare_feature_results(const struct nlattr *bitset,
+				   struct feature_results *dest)
+{
+	const struct nlattr *tb[ETHA_FEATURES_MAX + 1] = {};
+	DECLARE_ATTR_TB_INFO(tb);
+	unsigned int count;
+	int ret;
+
+	memset(dest, '\0', sizeof(*dest));
+	ret = mnl_attr_parse_nested(bitset, attr_cb, &tb_info);
+	if (ret < 0)
+		return ret;
+	if (!tb[ETHA_FEATURES_HW] || !tb[ETHA_FEATURES_WANTED] ||
+	    !tb[ETHA_FEATURES_ACTIVE] || !tb[ETHA_FEATURES_NOCHANGE])
+		return -EFAULT;
+	count = bitset_get_count(tb[ETHA_FEATURES_HW], &ret);
+	if (ret < 0)
+		return -EFAULT;
+	if ((bitset_get_count(tb[ETHA_FEATURES_WANTED], &ret) != count) ||
+	    (bitset_get_count(tb[ETHA_FEATURES_ACTIVE], &ret) != count) ||
+	    (bitset_get_count(tb[ETHA_FEATURES_NOCHANGE], &ret) != count))
+		return -EFAULT;
+	dest->hw = get_compact_bitset_value(tb[ETHA_FEATURES_HW]);
+	dest->wanted = get_compact_bitset_value(tb[ETHA_FEATURES_WANTED]);
+	dest->active = get_compact_bitset_value(tb[ETHA_FEATURES_ACTIVE]);
+	dest->nochange = get_compact_bitset_value(tb[ETHA_FEATURES_NOCHANGE]);
+	if (!dest->hw || !dest->wanted || !dest->active || !dest->nochange)
+		return -EFAULT;
+	dest->count = count;
+	dest->words = (count + 31) / 32;
+
+	return 0;
+}
+
+static bool feature_on(const uint32_t *bitmap, unsigned int idx)
+{
+	return bitmap[idx / 32] & (1 << (idx % 32));
+}
+
+static void dump_feature(const struct feature_results *results,
+			 const uint32_t *ref, const uint32_t *ref_mask,
+			 unsigned int idx, const char *name, const char *prefix)
+{
+	const char *suffix = "";
+
+	if (!name || !*name)
+		return;
+	if (ref) {
+		if (ref_mask && !feature_on(ref_mask, idx))
+			return;
+		if ((!ref_mask || feature_on(ref_mask, idx)) &&
+		    (feature_on(results->active, idx) == feature_on(ref, idx)))
+			return;
+	}
+
+	if (!feature_on(results->hw, idx) || feature_on(results->nochange, idx))
+		suffix = " [fixed]";
+	else if (feature_on(results->active, idx) !=
+		 feature_on(results->wanted, idx))
+		suffix = feature_on(results->wanted, idx) ?
+			 " [requested on]" : " [requested off]";
+	printf("%s%s: %s%s\n", prefix, name,
+	       feature_on(results->active, idx) ? "on" : "off", suffix);
+}
+
+/* this assumes pattern contains no more than one asterisk */
+static bool _flag_pattern_match(const char *name, const char *pattern)
+{
+	const char *p_ast = strchr(pattern, '*');
+
+	if (p_ast) {
+		size_t name_len = strlen(name);
+		size_t pattern_len = strlen(pattern);
+
+		if (name_len + 1 < pattern_len)
+			return false;
+		if (strncmp(name, pattern, p_ast - pattern))
+			return false;
+		pattern_len -= (p_ast - pattern) + 1;
+		name += name_len  - pattern_len;
+		pattern = p_ast + 1;
+	}
+	return !strcmp(name, pattern);
+}
+
+static bool flag_pattern_match(const char *name, const char *pattern)
+{
+	bool ret = _flag_pattern_match(name, pattern);
+
+	return ret;
+}
+
+int dump_features(const struct nlattr *bitset)
+{
+	const struct stringset *feature_names;
+	struct feature_results results;
+	unsigned int i, j;
+	int *feature_flags = NULL;
+	int ret;
+
+	ret = prepare_feature_results(bitset, &results);
+	if (ret < 0)
+		return -EFAULT;
+
+	ret = -ENOMEM;
+	feature_flags = calloc(results.count, sizeof(feature_flags[0]));
+	if (!feature_flags)
+	       goto out_free;
+	feature_names = global_stringset(ETH_SS_FEATURES);
+
+	/* map netdev features to legacy flags */
+	for (i = 0; i < results.count; i++) {
+		const char *name = get_string(feature_names, i);
+		feature_flags[i] = -1;
+
+		if (!name || !*name)
+			continue;
+		for (j = 0; j < OFF_FLAG_DEF_SIZE; j++) {
+			const char *flag_name = off_flag_def[j].kernel_name;
+
+			if (flag_pattern_match(name, flag_name)) {
+				feature_flags[i] = j;
+				break;
+			}
+		}
+	}
+	/* show legacy flags and their matching features first */
+	for (i = 0; i < OFF_FLAG_DEF_SIZE; i++) {
+		unsigned int n_match = 0;
+		bool flag_value = false;
+
+		for (j = 0; j < results.count; j++) {
+			if (feature_flags[j] == i) {
+				n_match++;
+				flag_value = flag_value ||
+					     feature_on(results.active, j);
+			}
+		}
+		if (n_match != 1)
+			printf("%s: %s\n", off_flag_def[i].long_name,
+			       flag_value ? "on" : "off");
+		if (n_match == 0)
+			continue;
+		for (j = 0; j < results.count; j++) {
+			const char *name = get_string(feature_names, j);
+
+			if (feature_flags[j] != i)
+				continue;
+			if (n_match == 1)
+				dump_feature(&results, NULL, NULL, j,
+					     off_flag_def[i].long_name, "");
+			else
+				dump_feature(&results, NULL, NULL, j, name,
+					     "\t");
+		}
+	}
+	/* and, finally, remaining netdev_features not matching legacy flags */
+	for (i = 0; i < results.count; i++) {
+		const char *name = get_string(feature_names, i);
+
+		if (!name || !*name || feature_flags[i] >= 0)
+			continue;
+		dump_feature(&results, NULL, NULL, i, name, "");
+	}
+
+out_free:
+	free(feature_flags);
+	return 0;
+}
+
 int settings_reply_cb(const struct nlmsghdr *nlhdr, void *data)
 {
 	const struct nlattr *tb[ETHA_SETTINGS_MAX + 1] = {};
@@ -262,6 +476,15 @@ int settings_reply_cb(const struct nlmsghdr *nlhdr, void *data)
 		printf("\tLink detected: %s\n", link ? "yes" : "no");
 		allfail = false;
 	};
+	if (tb[ETHA_SETTINGS_FEATURES] &&
+	    mask_ok(nlctx, ETH_SETTINGS_IM_FEATURES)) {
+		int ret;
+
+		printf("Features for %s:\n", nlctx->devname);
+		ret = dump_features(tb[ETHA_SETTINGS_FEATURES]);
+		if (ret == 0)
+			allfail = false;
+	}
 
 	if (allfail && !nlctx->is_monitor) {
 		fputs("No data available\n", stdout);
@@ -299,6 +522,9 @@ int nl_gset(struct cmd_context *ctx)
 				     ETH_SETTINGS_IM_LINK);
 }
 
+int nl_gfeatures(struct cmd_context *ctx)
+{
+	return settings_request(ctx, ETH_SETTINGS_IM_FEATURES);
 }
 
 /* SET_SETTINGS */
-- 
2.18.0

^ permalink raw reply related

* [RFC PATCH ethtool v2 09/23] netlink: add netlink handler for sset (-s)
From: Michal Kubecek @ 2018-07-30 12:56 UTC (permalink / raw)
  To: netdev; +Cc: linux-kernel, John W. Linville
In-Reply-To: <cover.1532954671.git.mkubecek@suse.cz>

Implement "ethtool -s <dev>" subcommand using netlink interface command
ETHNL_CMD_SET_SETTINGS.

Add specific parsers for wol modes and MAC address (used for wake-on-lan
password here).

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 ethtool.c          |   9 +-
 netlink/extapi.h   |   1 +
 netlink/netlink.c  |   9 ++
 netlink/netlink.h  |   1 +
 netlink/parser.c   |  34 ++++++-
 netlink/parser.h   |   4 +
 netlink/settings.c | 216 +++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 269 insertions(+), 5 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index bc7969f829f6..0b40b96cf9bf 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -4923,6 +4923,7 @@ static int show_usage(struct cmd_context *ctx);
  */
 #define nl_gdrv		NULL
 #define nl_gset		NULL
+#define nl_sset		NULL
 #endif
 
 static const struct option {
@@ -4933,19 +4934,19 @@ static const struct option {
 	char *help;
 	char *opthelp;
 } args[] = {
-	{ "-s|--change", 1, do_sset, NULL,
+	{ "-s|--change", 1, do_sset, nl_sset,
 	  "Change generic options",
 	  "		[ speed %d ]\n"
 	  "		[ duplex half|full ]\n"
 	  "		[ port tp|aui|bnc|mii|fibre ]\n"
 	  "		[ mdix auto|on|off ]\n"
 	  "		[ autoneg on|off ]\n"
-	  "		[ advertise %x ]\n"
+	  "		[ advertise %x[/%x] | mode on|off ... [--] ]\n"
 	  "		[ phyad %d ]\n"
 	  "		[ xcvr internal|external ]\n"
-	  "		[ wol p|u|m|b|a|g|s|d... ]\n"
+	  "		[ wol %d[/%d] |  p|u|m|b|a|g|s|d...[/p|u|m|b|a|g|s|d...] ]\n"
 	  "		[ sopass %x:%x:%x:%x:%x:%x ]\n"
-	  "		[ msglvl %d | msglvl type on|off ... ]\n" },
+	  "		[ msglvl %d[/%d] | type on|off ... [--] ]\n" },
 	{ "-a|--show-pause", 1, do_gpause, NULL,
 	  "Show pause options" },
 	{ "-A|--pause", 1, do_spause, NULL,
diff --git a/netlink/extapi.h b/netlink/extapi.h
index 20c9b03b2d3c..66573f0b4304 100644
--- a/netlink/extapi.h
+++ b/netlink/extapi.h
@@ -15,6 +15,7 @@ int netlink_done(struct cmd_context *ctx);
 
 int nl_gdrv(struct cmd_context *ctx);
 int nl_gset(struct cmd_context *ctx);
+int nl_sset(struct cmd_context *ctx);
 int nl_monitor(struct cmd_context *ctx);
 
 void monitor_usage();
diff --git a/netlink/netlink.c b/netlink/netlink.c
index fc87577191f0..8b3dce970fd1 100644
--- a/netlink/netlink.c
+++ b/netlink/netlink.c
@@ -573,6 +573,15 @@ static int get_ethnl_family(struct nl_context *nlctx)
 	return (nlctx->ethnl_fam ? 0 : -EADDRNOTAVAIL);
 }
 
+int nomsg_reply_cb(const struct nlmsghdr *nlhdr, void *data)
+{
+	const struct genlmsghdr *ghdr = (const struct genlmsghdr *)(nlhdr + 1);
+
+	fprintf(stderr, "received unexpected message: len=%u type=%u cmd=%u\n",
+	       nlhdr->nlmsg_len, nlhdr->nlmsg_type, ghdr->cmd);
+	return MNL_CB_OK;
+}
+
 /* initialization */
 
 static int nlctx_init(struct nl_context *nlctx)
diff --git a/netlink/netlink.h b/netlink/netlink.h
index 32c2f9f33ba1..9c23526da627 100644
--- a/netlink/netlink.h
+++ b/netlink/netlink.h
@@ -72,6 +72,7 @@ int attr_cb(const struct nlattr *attr, void *data);
 int ethnl_prep_get_request(struct cmd_context *ctx, unsigned int nlcmd,
 			   uint16_t dev_attrtype);
 int ethnl_send_get_request(struct nl_context *nlctx, mnl_cb_t cb);
+int nomsg_reply_cb(const struct nlmsghdr *nlhdr, void *data);
 int __init_aux_nlctx(struct nl_context *nlctx);
 
 /* put data wrappers */
diff --git a/netlink/parser.c b/netlink/parser.c
index 589004d1f9f9..d1536ecb1d52 100644
--- a/netlink/parser.c
+++ b/netlink/parser.c
@@ -69,7 +69,7 @@ static int parse_x32(const char *arg, u32 *result)
 	return __parse_u32(arg, result, 0, 0xffffffff, 16);
 }
 
-static int parse_u32(const char *arg, u32 *result)
+int parse_u32(const char *arg, u32 *result)
 {
 	if (!arg)
 		return -EINVAL;
@@ -485,6 +485,38 @@ int nl_parse_bitset(struct nl_context *nlctx, uint16_t type, const void *data)
 		return nl_parse_bitset_list(nlctx, type, data);
 }
 
+int nl_parse_mac_addr(struct nl_context *nlctx, uint16_t type, const void *data)
+{
+	const char *arg = *nlctx->argp;
+	u8 val[ETH_ALEN];
+	unsigned int i;
+	const char *p;
+
+	nlctx->argp++;
+	nlctx->argc--;
+
+	p = arg;
+	i = 0;
+	while (i < ETH_ALEN && *p) {
+		char *endp;
+		unsigned long byte = strtoul(p, &endp, 16);
+
+		if ((endp - p > 2) || (*endp && *endp != ':'))
+			goto err;
+		val[i++] = (u8) byte;
+		p = endp + (*endp ? 1 : 0);
+	}
+	if (i < ETH_ALEN)
+		goto err;
+
+	return ethnla_put(nlctx, type, ETH_ALEN, val);
+
+err:
+	fprintf(stderr, "ethtool (%s): invalid value '%s' of parameter '%s'\n",
+		nlctx->cmd, arg, nlctx->param);
+	return -EINVAL;
+}
+
 int nl_parser(struct cmd_context *ctx, const struct param_parser *params,
 	      unsigned int max_type)
 {
diff --git a/netlink/parser.h b/netlink/parser.h
index 7308da25f093..2fd9a8bb23d9 100644
--- a/netlink/parser.h
+++ b/netlink/parser.h
@@ -28,6 +28,8 @@ struct param_parser {
 	unsigned int		min_argc;
 };
 
+int parse_u32(const char *arg, u32 *result);
+
 int nl_parse_direct_u32(struct nl_context *nlctx, uint16_t type,
 			const void *data);
 int nl_parse_direct_u8(struct nl_context *nlctx, uint16_t type,
@@ -38,6 +40,8 @@ int nl_parse_lookup_u8(struct nl_context *nlctx, uint16_t type,
 int nl_parse_bitfield32(struct nl_context *nlctx, uint16_t type,
 			const void *data);
 int nl_parse_bitset(struct nl_context *nlctx, uint16_t type, const void *data);
+int nl_parse_mac_addr(struct nl_context *nlctx, uint16_t type,
+		      const void *data);
 
 int nl_parser(struct cmd_context *ctx, const struct param_parser *params,
 	      unsigned int max_type);
diff --git a/netlink/settings.c b/netlink/settings.c
index 120fc95aad19..b077a96325e5 100644
--- a/netlink/settings.c
+++ b/netlink/settings.c
@@ -5,6 +5,7 @@
 #include "../internal.h"
 #include "../common.h"
 #include "netlink.h"
+#include "parser.h"
 
 /* GET_SETTINGS */
 
@@ -299,3 +300,218 @@ int nl_gset(struct cmd_context *ctx)
 }
 
 }
+
+/* SET_SETTINGS */
+
+enum {
+	WAKE_PHY_BIT		= 0,
+	WAKE_UCAST_BIT		= 1,
+	WAKE_MCAST_BIT		= 2,
+	WAKE_BCAST_BIT		= 3,
+	WAKE_ARP_BIT		= 4,
+	WAKE_MAGIC_BIT		= 5,
+	WAKE_MAGICSECURE_BIT	= 6,
+};
+
+#define WAKE_ALL (WAKE_PHY | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_ARP | \
+		  WAKE_MAGIC | WAKE_MAGICSECURE)
+
+char wol_modes[32] = {
+	[WAKE_PHY_BIT]		= 'p',
+	[WAKE_UCAST_BIT]	= 'u',
+	[WAKE_MCAST_BIT]	= 'm',
+	[WAKE_BCAST_BIT]	= 'b',
+	[WAKE_ARP_BIT]		= 'a',
+	[WAKE_MAGIC_BIT]	= 'g',
+	[WAKE_MAGICSECURE_BIT]	= 's',
+};
+
+static int __nl_parse_wol_modes(struct nl_context *nlctx, const char *str,
+				u32 *result)
+{
+	unsigned int i;
+	const char *p;
+	int ret;
+
+	ret = parse_u32(str, result);
+	if (ret == 0)
+		return 0;
+
+	*result = 0;
+	if (str[0] == 'd' && !str[1])
+		return 0;
+
+	p = str;
+	while (*p) {
+		for (i = 0; i < 32; i++) {
+			if (wol_modes[i] == *p) {
+				*result |= (1U << i);
+				break;
+			}
+		}
+		if (i == 32) {
+			fprintf(stderr,
+				"ethtool (%s): invalid wol modes '%s'\n",
+				nlctx->cmd, str);
+			return -EINVAL;
+		}
+		p++;
+	}
+
+	return 0;
+}
+
+static int nl_parse_wol_modes(struct nl_context *nlctx, uint16_t type,
+			      const void *data)
+{
+	const char *arg = *nlctx->argp;
+	char *mask = strchr(arg, '/');
+	u32 value, selector;
+	int ret;
+
+	nlctx->argp++;
+	nlctx->argc--;
+	if (mask) {
+		*mask = '\0';
+		mask++;
+	}
+
+	ret = __nl_parse_wol_modes(nlctx, arg, &value);
+	if (ret < 0)
+		return ret;
+
+	if (!mask) {
+		selector = ~(u32)0;
+	} else {
+		ret = __nl_parse_wol_modes(nlctx, mask, &selector);
+		if (ret < 0)
+			return ret;
+	}
+
+	return ethnla_put_bitfield32(nlctx, type, value, selector);
+}
+
+static const struct lookup_entry_u32 duplex_values[] = {
+	{ .arg = "half",	.val = DUPLEX_HALF },
+	{ .arg = "full",	.val = DUPLEX_FULL },
+	{}
+};
+
+static const struct lookup_entry_u8 port_values[] = {
+	{ .arg = "tp",		.val = PORT_TP },
+	{ .arg = "aui",		.val = PORT_AUI },
+	{ .arg = "bnc",		.val = PORT_BNC },
+	{ .arg = "mii",		.val = PORT_MII },
+	{ .arg = "fibre",	.val = PORT_FIBRE },
+	{}
+};
+
+static const struct lookup_entry_u8 mdix_values[] = {
+	{ .arg = "auto",	.val = ETH_TP_MDI_AUTO },
+	{ .arg = "on",		.val = ETH_TP_MDI_X },
+	{ .arg = "off",		.val = ETH_TP_MDI },
+	{}
+};
+
+static const struct lookup_entry_u8 autoneg_values[] = {
+	{ .arg = "off",		.val = AUTONEG_DISABLE },
+	{ .arg = "on",		.val = AUTONEG_ENABLE },
+	{}
+};
+
+static const struct param_parser sset_params[] = {
+	{
+		.arg		= "speed",
+		.type		= ETHA_SETTINGS_SPEED,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "duplex",
+		.type		= ETHA_SETTINGS_DUPLEX,
+		.handler	= nl_parse_lookup_u8,
+		.handler_data	= duplex_values,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "port",
+		.type		= ETHA_SETTINGS_PORT,
+		.handler	= nl_parse_lookup_u8,
+		.handler_data	= port_values,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "mdix",
+		.type		= ETHA_SETTINGS_TP_MDIX_CTRL,
+		.handler	= nl_parse_lookup_u8,
+		.handler_data	= mdix_values,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "autoneg",
+		.type		= ETHA_SETTINGS_AUTONEG,
+		.handler	= nl_parse_lookup_u8,
+		.handler_data	= autoneg_values,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "advertise",
+		.type		= ETHA_SETTINGS_LINK_MODES,
+		.handler	= nl_parse_bitset,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "phyad",
+		.type		= ETHA_SETTINGS_PHYADDR,
+		.handler	= nl_parse_direct_u8,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "wol",
+		.type		= ETHA_SETTINGS_WOL_MODES,
+		.handler	= nl_parse_wol_modes,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "sopass",
+		.type		= ETHA_SETTINGS_SOPASS,
+		.handler	= nl_parse_mac_addr,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "msglvl",
+		.type		= ETHA_SETTINGS_MSGLVL,
+		.handler	= nl_parse_bitfield32,
+		.handler_data	= flags_msglvl,
+		.min_argc	= 1,
+	},
+	{}
+};
+
+int nl_sset(struct cmd_context *ctx)
+{
+	struct nl_context *nlctx = ctx->nlctx;
+	int ret;
+
+	nlctx->cmd = "-s";
+	nlctx->argp = ctx->argp;
+	nlctx->argc = ctx->argc;
+	ret = msg_init(nlctx, ETHNL_CMD_SET_SETTINGS,
+		       NLM_F_REQUEST | NLM_F_ACK);
+	if (ret < 0)
+		return 2;
+	if (ethnla_put_dev(nlctx, ETHA_SETTINGS_DEV, ctx->devname))
+		return -EMSGSIZE;
+
+	ret = nl_parser(ctx, sset_params, ETHA_SETTINGS_MAX);
+	if (ret < 0)
+		return 2;
+
+	ret = ethnl_sendmsg(nlctx);
+	if (ret < 0)
+		return 75;
+	ret = ethnl_process_reply(nlctx, nomsg_reply_cb);
+	if (ret == 0)
+		return 0;
+	return nlctx->exit_code ?: 75;
+}
-- 
2.18.0

^ permalink raw reply related

* [RFC PATCH ethtool v2 04/23] netlink: add support for string sets
From: Michal Kubecek @ 2018-07-30 12:56 UTC (permalink / raw)
  To: netdev; +Cc: linux-kernel, John W. Linville
In-Reply-To: <cover.1532954671.git.mkubecek@suse.cz>

Add infrastructure for querying kernel string sets (analog to ioct commands
ETHTOOL_GSSET_INFO and ETHTOOL_GSTRINGS).

Let notification monitor request string sets on start so that it can
resolve bit indices to names when processing bitsets in compact format.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Makefile.am      |   1 +
 netlink/strset.c | 265 +++++++++++++++++++++++++++++++++++++++++++++++
 netlink/strset.h |  16 +++
 3 files changed, 282 insertions(+)
 create mode 100644 netlink/strset.c
 create mode 100644 netlink/strset.h

diff --git a/Makefile.am b/Makefile.am
index bdb4f4df2b0f..6a4d7083919e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -22,6 +22,7 @@ endif
 if ETHTOOL_ENABLE_NETLINK
 ethtool_SOURCES += \
 		  netlink/netlink.c netlink/netlink.h netlink/extapi.h \
+		  netlink/strset.c netlink/strset.h \
 		  uapi/linux/ethtool_netlink.h \
 		  uapi/linux/netlink.h uapi/linux/genetlink.h
 ethtool_CFLAGS += @MNL_CFLAGS@
diff --git a/netlink/strset.c b/netlink/strset.c
new file mode 100644
index 000000000000..9ea456748531
--- /dev/null
+++ b/netlink/strset.c
@@ -0,0 +1,265 @@
+#include <errno.h>
+#include <string.h>
+
+#include "../internal.h"
+#include "netlink.h"
+
+struct stringset {
+	const char		**strings;
+	void			*raw_data;
+	unsigned int		count;
+};
+
+struct perdev_strings {
+	char			devname[IFNAMSIZ];
+	struct stringset	strings[ETH_SS_MAX + 1];
+	struct perdev_strings	*next;
+};
+
+/* universal string sets */
+static struct stringset global_strings[ETH_SS_MAX + 1];
+/* linked list of string sets related to network devices */
+static struct perdev_strings *device_strings;
+
+static void drop_stringset(struct stringset *set)
+{
+	free(set->strings);
+	free(set->raw_data);
+	set->count = 0;
+}
+
+static int import_stringset(struct stringset *dest, const struct nlattr *nest)
+{
+	const struct nlattr *tb_stringset[ETHA_STRINGSET_MAX + 1] = {};
+	DECLARE_ATTR_TB_INFO(tb_stringset);
+	const struct nlattr *string;
+	unsigned int size;
+	unsigned int count;
+	unsigned int idx;
+	int ret;
+
+	ret = mnl_attr_parse_nested(nest, attr_cb, &tb_stringset_info);
+	if (ret < 0)
+		return ret;
+	if (!tb_stringset[ETHA_STRINGSET_ID] ||
+	    !tb_stringset[ETHA_STRINGSET_COUNT] ||
+	    !tb_stringset[ETHA_STRINGSET_STRINGS])
+		return -EFAULT;
+	idx = mnl_attr_get_u32(tb_stringset[ETHA_STRINGSET_ID]);
+	if (idx > ETH_SS_MAX)
+		return 0;
+	count = mnl_attr_get_u32(tb_stringset[ETHA_STRINGSET_COUNT]);
+	if (count == 0)
+		return 0;
+
+	size = mnl_attr_get_len(tb_stringset[ETHA_STRINGSET_STRINGS]);
+	ret = -ENOMEM;
+	dest[idx].raw_data = malloc(size);
+	if (!dest[idx].raw_data)
+		goto err;
+	memcpy(dest[idx].raw_data, tb_stringset[ETHA_STRINGSET_STRINGS], size);
+	dest[idx].strings = malloc(count * sizeof(dest[idx].strings[0]));
+	if (!dest[idx].strings)
+		goto err;
+	dest[idx].count = count;
+
+	nest = dest[idx].raw_data;
+	mnl_attr_for_each_nested(string, nest) {
+		const struct nlattr *tb[ETHA_STRING_MAX + 1] = {};
+		DECLARE_ATTR_TB_INFO(tb);
+		unsigned int i;
+
+		if (mnl_attr_get_type(string) != ETHA_STRINGS_STRING)
+			continue;
+		ret = mnl_attr_parse_nested(string, attr_cb, &tb_info);
+		if (ret < 0)
+			goto err;
+		ret = -EFAULT;
+		if (!tb[ETHA_STRING_INDEX] || !tb[ETHA_STRING_VALUE])
+			goto err;
+
+		i = mnl_attr_get_u32(tb[ETHA_STRING_INDEX]);
+		if (i >= count)
+			goto err;
+		dest[idx].strings[i] =
+			mnl_attr_get_payload(tb[ETHA_STRING_VALUE]);
+	}
+
+	return 0;
+err:
+	drop_stringset(&dest[idx]);
+	return ret;
+}
+
+static const char *stringset_names[] = {
+	[ETH_SS_TEST] = "test",
+	[ETH_SS_STATS] = "stats",
+	[ETH_SS_PRIV_FLAGS] = "priv-flags",
+	[ETH_SS_NTUPLE_FILTERS] = "ntuple-filters",
+	[ETH_SS_FEATURES] = "features",
+	[ETH_SS_RSS_HASH_FUNCS] = "rss-hash-funcs",
+	[ETH_SS_TUNABLES] = "tunables",
+	[ETH_SS_PHY_STATS] = "phy-stats",
+	[ETH_SS_PHY_TUNABLES] = "phy-tunables",
+	[ETH_SS_LINK_MODES] = "link-modes",
+};
+
+void debug_stringsets(const struct stringset *sets)
+{
+	unsigned int i;
+
+	for (i = 0; i <= ETH_SS_MAX; i++) {
+		if (sets[i].count > 0) {
+			printf("    set %s, count %u\n", stringset_names[i],
+			       sets[i].count);
+		}
+	}
+}
+
+void debug_strings()
+{
+	struct perdev_strings *pd;
+
+	fputs("global strings:\n", stdout);
+	debug_stringsets(global_strings);
+
+	for (pd = device_strings; pd; pd = pd->next) {
+		printf("strings for %s:\n", pd->devname);
+		debug_stringsets(pd->strings);
+	}
+}
+
+static int strset_reply_cb(const struct nlmsghdr *nlhdr, void *data)
+{
+	const struct nlattr *tb[ETHA_STRSET_MAX + 1] = {};
+	DECLARE_ATTR_TB_INFO(tb);
+	struct nl_context *nlctx = data;
+	struct stringset *dest;
+	struct nlattr *attr;
+	unsigned int i;
+	int ret;
+
+	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
+	if (ret < 0)
+		return ret;
+	nlctx->devname = get_dev_name(tb[ETHA_STRSET_DEV]);
+	if (!dev_ok(nlctx))
+		return MNL_CB_OK;
+
+	if (nlctx->devname) {
+		struct perdev_strings *perdev = device_strings;
+
+		while (perdev && strcmp(perdev->devname, nlctx->devname))
+			perdev = perdev->next;
+		if (perdev) {
+			for (i = 0; i <= ETH_SS_MAX; i++)
+				drop_stringset(&perdev->strings[i]);
+		} else {
+			perdev = calloc(sizeof(*perdev), 1);
+			if (!perdev)
+				return -ENOMEM;
+			strncpy(perdev->devname, nlctx->devname, IFNAMSIZ);
+			perdev->devname[IFNAMSIZ - 1] = '\0';
+			perdev->next = device_strings;
+			device_strings = perdev;
+		}
+		dest = perdev->strings;
+	} else {
+		for (i = 0; i <= ETH_SS_MAX; i++)
+			drop_stringset(&global_strings[i]);
+		dest = global_strings;
+	}
+
+	mnl_attr_for_each(attr, nlhdr, GENL_HDRLEN) {
+		if (mnl_attr_get_type(attr) == ETHA_STRSET_STRINGSET)
+			import_stringset(dest, attr);
+	}
+
+	return MNL_CB_OK;
+}
+
+/* interface */
+
+const struct stringset *global_stringset(unsigned int type)
+{
+	if (type > ETH_SS_MAX)
+		return NULL;
+	return &global_strings[type];
+}
+
+const struct stringset *perdev_stringset(const char *dev, unsigned int type)
+{
+	const struct perdev_strings *p;
+
+	if (type > ETH_SS_MAX)
+		return NULL;
+	for (p = device_strings; p; p = p->next)
+		if (!strcmp(p->devname, dev))
+			return &p->strings[type];
+
+	return NULL;
+}
+
+unsigned int get_count(const struct stringset *set)
+{
+	return set->count;
+}
+
+const char *get_string(const struct stringset *set, unsigned int idx)
+{
+	if (idx > set->count)
+		return NULL;
+	return set->strings[idx];
+}
+
+int load_global_strings(struct nl_context *nlctx)
+{
+	int ret;
+
+	ret = msg_init(nlctx, ETHNL_CMD_GET_STRSET, NLM_F_REQUEST | NLM_F_ACK);
+	if (ret < 0)
+		return ret;
+	ret = ethnl_send_get_request(nlctx, strset_reply_cb);
+	return ret;
+}
+
+int load_perdev_strings(struct nl_context *nlctx, const char *dev)
+{
+	int ret;
+
+	ret = msg_init(nlctx, ETHNL_CMD_GET_STRSET,
+		       NLM_F_REQUEST | NLM_F_ACK | (dev ? 0 : NLM_F_DUMP));
+	if (ret < 0)
+		return ret;
+	if (dev) {
+		if (ethnla_put_dev(nlctx, ETHA_STRSET_DEV, dev))
+			return -EMSGSIZE;
+	}
+	ret = ethnl_send_get_request(nlctx, strset_reply_cb);
+	return ret;
+}
+
+void free_perdev_strings(const char *devname)
+{
+	struct perdev_strings **p = &device_strings;
+	unsigned int i;
+
+	p = &device_strings;
+	while (*p) {
+		struct perdev_strings *perdev = *p;
+
+		if (devname && strcmp(perdev->devname, devname)) {
+			p = &((*p)->next);
+			continue;
+		}
+		*p = perdev->next;
+		for (i = 0; i <= ETH_SS_MAX; i++)
+			drop_stringset(&perdev->strings[i]);
+		free(perdev);
+	}
+
+	if (!devname) {
+		for (i = 0; i <= ETH_SS_MAX; i++)
+			drop_stringset(&global_strings[i]);
+	}
+}
diff --git a/netlink/strset.h b/netlink/strset.h
new file mode 100644
index 000000000000..81ddf33a5d15
--- /dev/null
+++ b/netlink/strset.h
@@ -0,0 +1,16 @@
+#ifndef ETHTOOL_NETLINK_STRSET_H__
+#define ETHTOOL_NETLINK_STRSET_H__
+
+struct stringset;
+
+const struct stringset *global_stringset(unsigned int type);
+const struct stringset *perdev_stringset(const char *dev, unsigned int type);
+
+unsigned int get_count(const struct stringset *set);
+const char *get_string(const struct stringset *set, unsigned int idx);
+
+int load_global_strings(struct nl_context *nlctx);
+int load_perdev_strings(struct nl_context *nlctx, const char *dev);
+void free_perdev_strings(const char *devname);
+
+#endif /* ETHTOOL_NETLINK_STRSET_H__ */
-- 
2.18.0

^ permalink raw reply related

* Re: [PATCH 3/3] ptp_qoriq: convert to use module parameters for initialization
From: Richard Cochran @ 2018-07-30 14:30 UTC (permalink / raw)
  To: Yangbo Lu
  Cc: netdev, madalin.bucur, Rob Herring, Shawn Guo, David S . Miller,
	devicetree, linuxppc-dev, linux-arm-kernel, linux-kernel
In-Reply-To: <20180730100154.27906-3-yangbo.lu@nxp.com>

On Mon, Jul 30, 2018 at 06:01:54PM +0800, Yangbo Lu wrote:
> The ptp_qoriq driver initialized the 1588 timer with the
> configurations provided by the properties of device tree
> node. For example,
> 
>   fsl,tclk-period = <5>;
>   fsl,tmr-prsc    = <2>;
>   fsl,tmr-add     = <0xaaaaaaab>;
>   fsl,tmr-fiper1  = <999999995>;
>   fsl,tmr-fiper2  = <99990>;
>   fsl,max-adj     = <499999999>;
> 
> These things actually were runtime configurations which
> were not proper to be put into dts.

That is debatable.  While I agree that the dts isn't ideal for these,
still it is the lesser of two or more evils.

> This patch is to convert
> to use module parameters for 1588 timer initialization, and
> to support initial register values calculation.

It is hard for me to understand how using module parameters improves
the situation.

> If the parameters are not provided, the driver will calculate
> register values with a set of default parameters. With this
> patch, those dts properties are no longer needed for new
> platform to support 1588 timer, and many QorIQ DPAA platforms
> (some P series and T series platforms of PowerPC, and some
> LS series platforms of ARM64) could use this driver for their
> fman ptp timer with default module parameters. However, this
> patch didn't remove the dts method. Because there were still
> many old platforms using the dts method. We need to clean up
> their dts files, verify module parameters on them, and convert
> them to the new method gradually in case of breaking any
> function.

In addition, like it or not, because the dts is an ABI, you must
continue support of the dts values as a legacy option.

Thanks,
Richard

^ permalink raw reply

* [RFC PATCH net-next v2 16/17] ethtool: implement SET_PARAMS notification
From: Michal Kubecek @ 2018-07-30 12:54 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

SET_PARAMS notification message has the same format as response to
GET_PARAMS request and is broadcasted on change of relevant fields. Info
mask can be used to limit the information passed to userspace.

Also trigger the notification on analogous changes performed via the legacy
ioctl interface.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 net/ethtool/ioctl.c   | 42 ++++++++++++++++++++++++++++++++++++------
 net/ethtool/netlink.c |  3 +++
 net/ethtool/params.c  | 40 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 79 insertions(+), 6 deletions(-)

diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 2754d3f6fd75..1dc1459dff6e 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -1337,6 +1337,7 @@ static int ethtool_get_eee(struct net_device *dev, char __user *useraddr)
 static int ethtool_set_eee(struct net_device *dev, char __user *useraddr)
 {
 	struct ethtool_eee edata;
+	int ret;
 
 	if (!dev->ethtool_ops->set_eee)
 		return -EOPNOTSUPP;
@@ -1344,7 +1345,11 @@ static int ethtool_set_eee(struct net_device *dev, char __user *useraddr)
 	if (copy_from_user(&edata, useraddr, sizeof(edata)))
 		return -EFAULT;
 
-	return dev->ethtool_ops->set_eee(dev, &edata);
+	ret = dev->ethtool_ops->set_eee(dev, &edata);
+	if (ret >= 0)
+		netdev_ethtool_info_change(dev, NULL, ETHNL_CMD_SET_PARAMS,
+					   ETH_PARAMS_IM_EEE);
+	return ret;
 }
 
 static int ethtool_nway_reset(struct net_device *dev)
@@ -1499,6 +1504,7 @@ static noinline_for_stack int ethtool_set_coalesce(struct net_device *dev,
 						   void __user *useraddr)
 {
 	struct ethtool_coalesce coalesce;
+	int ret;
 
 	if (!dev->ethtool_ops->set_coalesce)
 		return -EOPNOTSUPP;
@@ -1506,7 +1512,11 @@ static noinline_for_stack int ethtool_set_coalesce(struct net_device *dev,
 	if (copy_from_user(&coalesce, useraddr, sizeof(coalesce)))
 		return -EFAULT;
 
-	return dev->ethtool_ops->set_coalesce(dev, &coalesce);
+	ret = dev->ethtool_ops->set_coalesce(dev, &coalesce);
+	if (ret >= 0)
+		netdev_ethtool_info_change(dev, NULL, ETHNL_CMD_SET_PARAMS,
+					   ETH_PARAMS_IM_COALESCE);
+	return ret;
 }
 
 static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr)
@@ -1526,6 +1536,7 @@ static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr)
 static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
 {
 	struct ethtool_ringparam ringparam, max = { .cmd = ETHTOOL_GRINGPARAM };
+	int ret;
 
 	if (!dev->ethtool_ops->set_ringparam || !dev->ethtool_ops->get_ringparam)
 		return -EOPNOTSUPP;
@@ -1542,7 +1553,11 @@ static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
 	    ringparam.tx_pending > max.tx_max_pending)
 		return -EINVAL;
 
-	return dev->ethtool_ops->set_ringparam(dev, &ringparam);
+	ret = dev->ethtool_ops->set_ringparam(dev, &ringparam);
+	if (ret >= 0)
+		netdev_ethtool_info_change(dev, NULL, ETHNL_CMD_SET_PARAMS,
+					   ETH_PARAMS_IM_RING);
+	return ret;
 }
 
 static noinline_for_stack int ethtool_get_channels(struct net_device *dev,
@@ -1565,6 +1580,7 @@ static noinline_for_stack int ethtool_set_channels(struct net_device *dev,
 {
 	struct ethtool_channels channels, max = { .cmd = ETHTOOL_GCHANNELS };
 	u32 max_rx_in_use = 0;
+	int ret;
 
 	if (!dev->ethtool_ops->set_channels || !dev->ethtool_ops->get_channels)
 		return -EOPNOTSUPP;
@@ -1588,7 +1604,11 @@ static noinline_for_stack int ethtool_set_channels(struct net_device *dev,
 	    (channels.combined_count + channels.rx_count) <= max_rx_in_use)
 	    return -EINVAL;
 
-	return dev->ethtool_ops->set_channels(dev, &channels);
+	ret = dev->ethtool_ops->set_channels(dev, &channels);
+	if (ret >= 0)
+		netdev_ethtool_info_change(dev, NULL, ETHNL_CMD_SET_PARAMS,
+					   ETH_PARAMS_IM_CHANNELS);
+	return ret;
 }
 
 static int ethtool_get_pauseparam(struct net_device *dev, void __user *useraddr)
@@ -1608,6 +1628,7 @@ static int ethtool_get_pauseparam(struct net_device *dev, void __user *useraddr)
 static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr)
 {
 	struct ethtool_pauseparam pauseparam;
+	int ret;
 
 	if (!dev->ethtool_ops->set_pauseparam)
 		return -EOPNOTSUPP;
@@ -1615,7 +1636,11 @@ static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr)
 	if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam)))
 		return -EFAULT;
 
-	return dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
+	ret = dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
+	if (ret >= 0)
+		netdev_ethtool_info_change(dev, NULL, ETHNL_CMD_SET_PARAMS,
+					   ETH_PARAMS_IM_PAUSE);
+	return ret;
 }
 
 static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
@@ -2394,6 +2419,7 @@ static int ethtool_get_fecparam(struct net_device *dev, void __user *useraddr)
 static int ethtool_set_fecparam(struct net_device *dev, void __user *useraddr)
 {
 	struct ethtool_fecparam fecparam;
+	int ret;
 
 	if (!dev->ethtool_ops->set_fecparam)
 		return -EOPNOTSUPP;
@@ -2401,7 +2427,11 @@ static int ethtool_set_fecparam(struct net_device *dev, void __user *useraddr)
 	if (copy_from_user(&fecparam, useraddr, sizeof(fecparam)))
 		return -EFAULT;
 
-	return dev->ethtool_ops->set_fecparam(dev, &fecparam);
+	ret = dev->ethtool_ops->set_fecparam(dev, &fecparam);
+	if (ret >= 0)
+		netdev_ethtool_info_change(dev, NULL, ETHNL_CMD_SET_PARAMS,
+					   ETH_PARAMS_IM_FEC);
+	return ret;
 }
 
 /* The main entry point in this file.  Called from net/core/dev_ioctl.c */
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 721101ed2ab6..b24a0e045ec0 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -630,8 +630,11 @@ int ethnl_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
 typedef void (*ethnl_notify_handler_t)(struct netdev_notifier_ethtool_info *);
 
 void ethnl_settings_notify(struct netdev_notifier_ethtool_info *);
+void ethnl_params_notify(struct netdev_notifier_ethtool_info *);
+
 ethnl_notify_handler_t ethnl_notify_handlers[] = {
 	[ETHNL_CMD_SET_SETTINGS]	= ethnl_settings_notify,
+	[ETHNL_CMD_SET_PARAMS]		= ethnl_params_notify,
 };
 
 static void __ethnl_notify(struct netdev_notifier_ethtool_info *info)
diff --git a/net/ethtool/params.c b/net/ethtool/params.c
index 07d4c527abf2..773e13fc1ae6 100644
--- a/net/ethtool/params.c
+++ b/net/ethtool/params.c
@@ -537,3 +537,43 @@ int ethnl_params_done(struct netlink_callback *cb)
 
 	return 0;
 }
+
+void ethnl_params_notify(struct netdev_notifier_ethtool_info *info)
+{
+	struct params_reqinfo req_info = {
+		.dev		= info->info.dev,
+		.req_mask	= info->ethtool_info.req_mask,
+		.compact	= true,
+		.have_rtnl	= true,
+	};
+	struct params_data data;
+	struct sk_buff *skb;
+	int reply_len;
+	void *ehdr;
+	int ret;
+
+	ret = prepare_params(&data, &req_info, NULL, req_info.dev);
+	if (ret < 0)
+		return;
+	reply_len = params_size(&data, &req_info);
+	if (ret < 0)
+		return;
+	skb = genlmsg_new(reply_len, GFP_KERNEL);
+	if (!skb)
+		return;
+	ehdr = genlmsg_put(skb, 0, ++ethnl_bcast_seq, &ethtool_genl_family, 0,
+			   ETHNL_CMD_SET_PARAMS);
+	ret = ethnl_fill_dev(skb, req_info.dev, ETHA_PARAMS_DEV);
+	if (ret < 0)
+		goto err_skb;
+	ret = fill_params(skb, &data, &req_info);
+	if (ret < 0)
+		goto err_skb;
+	genlmsg_end(skb, ehdr);
+
+	genlmsg_multicast(&ethtool_genl_family, skb, 0, ETHNL_MCGRP_MONITOR,
+			  GFP_KERNEL);
+	return;
+err_skb:
+	nlmsg_free(skb);
+}
-- 
2.18.0

^ permalink raw reply related

* [RFC PATCH net-next v2 14/17] ethtool: implement SET_SETTINGS request for features
From: Michal Kubecek @ 2018-07-30 12:53 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

Using ETHNL_SETTINGS_FEATURES attribute, userspace can modify device
features. Actual change is subject to netdev_change_features() sanity
checks so that it can differ from what was requested. Unlike with most
other requests, kernel can reply (if ETHA_FEATURES_WANT_DIFF flag is used)
with a message in the same format but with different semantics: information
about difference between user request and actual result and difference
between old and new state of dev->features.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Documentation/networking/ethtool-netlink.txt |  30 +++--
 include/uapi/linux/ethtool_netlink.h         |   1 +
 net/ethtool/settings.c                       | 127 +++++++++++++++++++
 3 files changed, 150 insertions(+), 8 deletions(-)

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index c7fe4f518972..307d8c6c6c85 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -285,6 +285,9 @@ to be passed with SET_SETTINGS request:
     ETHA_SETTINGS_SOPASS        (binary)        SecureOn(tm) password
     ETHA_SETTINGS_MSGLVL        (bitfield32)    debug level
     ETHA_SETTINGS_LINK_MODES    (bitset)        device link modes
+    ETHA_SETTINGS_FEATURES	(nested)	device features
+        ETHA_FEATURES_WANTED		(bitset)	wanted features
+        ETHA_FEATURES_WANT_DIFF		(flag)		actual diff
 
 For both bitfield32 types, value and selector work the usual way, i.e. bits
 set in selector are set to corresponding bits from value and the rest is
@@ -299,6 +302,17 @@ autoselection is done on ethtool side with ioctl interface, netlink interface
 is supposed to allow requesting changes without knowing what exactly kernel
 supports.
 
+When changing device features, only ETHA_FEATURES_WANTED is passed. As usual,
+mask defines which bits are to be set and value their values. If the request
+has ETHA_FEATURES_WANT_DIFF flag set, reply will contain a message in the same
+format as response to GET request, except only two bitsets are provided.
+ETHA_FEATURES_WANTED shows difference between requested features and actual
+result (dev->features after the operation); mask shows bits which differ and
+value their values from the original request (new values are negated). Value
+shows changes between old dev->features (before the operation) and new (after
+the operation); mask shows bits which have been changed and value their new
+values.
+
 
 Request translation
 -------------------
@@ -328,30 +342,30 @@ ETHTOOL_SRINGPARAM		n/a
 ETHTOOL_GPAUSEPARAM		n/a
 ETHTOOL_SPAUSEPARAM		n/a
 ETHTOOL_GRXCSUM			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_SRXCSUM			n/a
+ETHTOOL_SRXCSUM			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_GTXCSUM			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_STXCSUM			n/a
+ETHTOOL_STXCSUM			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_GSG			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_SSG			n/a
+ETHTOOL_SSG			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_TEST			n/a
 ETHTOOL_GSTRINGS		ETHNL_CMD_GET_STRSET
 ETHTOOL_PHYS_ID			n/a
 ETHTOOL_GSTATS			n/a
 ETHTOOL_GTSO			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_STSO			n/a
+ETHTOOL_STSO			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_GPERMADDR		n/a
 ETHTOOL_GUFO			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_SUFO			n/a
+ETHTOOL_SUFO			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_GGSO			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_SGSO			n/a
+ETHTOOL_SGSO			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_GFLAGS			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_SFLAGS			n/a
+ETHTOOL_SFLAGS			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_GPFLAGS			n/a
 ETHTOOL_SPFLAGS			n/a
 ETHTOOL_GRXFH			n/a
 ETHTOOL_SRXFH			n/a
 ETHTOOL_GGRO			ETHNL_CMD_GET_SETTINGS
-ETHTOOL_SGRO			n/a
+ETHTOOL_SGRO			ETHNL_CMD_SET_SETTINGS
 ETHTOOL_GRXRINGS		n/a
 ETHTOOL_GRXCLSRLCNT		n/a
 ETHTOOL_GRXCLSRULE		n/a
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 06c78b281275..8dfcb9ef4009 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -191,6 +191,7 @@ enum {
 	ETHA_FEATURES_WANTED,			/* bitset */
 	ETHA_FEATURES_ACTIVE,			/* bitset */
 	ETHA_FEATURES_NOCHANGE,			/* bitset */
+	ETHA_FEATURES_WANT_DIFF,		/* flag */
 
 	__ETHA_FEATURES_MAX,
 	ETHA_FEATURES_MAX = (__ETHA_FEATURES_MAX - 1)
diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c
index 678199e621a2..475582b7950c 100644
--- a/net/ethtool/settings.c
+++ b/net/ethtool/settings.c
@@ -1016,6 +1016,122 @@ static int ethnl_update_lsettings(struct genl_info *info, struct nlattr **tb,
 	return 0;
 }
 
+static const struct nla_policy features_policy[ETHA_FEATURES_MAX + 1] = {
+	[ETHA_FEATURES_UNSPEC]		= { .type = NLA_UNSPEC },
+	[ETHA_FEATURES_HW]		= { .type = NLA_NESTED },
+	[ETHA_FEATURES_WANTED]		= { .type = NLA_NESTED },
+	[ETHA_FEATURES_ACTIVE]		= { .type = NLA_NESTED },
+	[ETHA_FEATURES_NOCHANGE]	= { .type = NLA_NESTED },
+	[ETHA_FEATURES_WANT_DIFF]	= { .type = NLA_FLAG },
+};
+
+static void bitmap_from_features(unsigned long *bitmap, netdev_features_t val)
+{
+	const unsigned int words = BITS_TO_LONGS(NETDEV_FEATURE_COUNT);
+	unsigned int i;
+
+	bitmap_zero(bitmap, NETDEV_FEATURE_COUNT);
+	for (i = 0; i < words; i++)
+		bitmap[i] = (unsigned long)(val >> (i * BITS_PER_LONG));
+}
+
+static netdev_features_t features_from_bitmap(unsigned long *bitmap)
+{
+	const unsigned int words = BITS_TO_LONGS(NETDEV_FEATURE_COUNT);
+	netdev_features_t ret = 0;
+	unsigned int i;
+
+	for (i = 0; i < words; i++)
+		ret |= (netdev_features_t)(bitmap[i]) << (i * BITS_PER_LONG);
+	return ret;
+}
+
+int update_features(struct genl_info *info, struct net_device *dev,
+		    const struct nlattr *nest, bool compact)
+{
+	struct nlattr *tb[ETHA_FEATURES_MAX + 1];
+	DECLARE_BITMAP(old_active, NETDEV_FEATURE_COUNT);
+	DECLARE_BITMAP(req_wanted, NETDEV_FEATURE_COUNT);
+	DECLARE_BITMAP(req_mask, NETDEV_FEATURE_COUNT);
+	DECLARE_BITMAP(new_active, NETDEV_FEATURE_COUNT);
+	DECLARE_BITMAP(wanted_diff_mask, NETDEV_FEATURE_COUNT);
+	DECLARE_BITMAP(active_diff_mask, NETDEV_FEATURE_COUNT);
+	struct nlattr *feat_attr;
+	unsigned int reply_len;
+	struct sk_buff *rskb;
+	bool mod = false;
+	void *ehdr;
+	int ret;
+
+	ret = nla_parse_nested(tb, ETHA_FEATURES_MAX, nest, features_policy,
+			       info->extack);
+	if (ret < 0)
+		return ret;
+	if (tb[ETHA_FEATURES_HW] || !tb[ETHA_FEATURES_WANTED] ||
+	    tb[ETHA_FEATURES_ACTIVE] || tb[ETHA_FEATURES_NOCHANGE])
+		return -EINVAL;
+
+	bitmap_from_features(old_active, dev->features);
+	bitmap_copy(req_wanted, old_active, NETDEV_FEATURE_COUNT);
+	bitmap_zero(req_mask, NETDEV_FEATURE_COUNT);
+	mod = ethnl_update_bitset(req_wanted, req_mask, NETDEV_FEATURE_COUNT,
+				  tb[ETHA_FEATURES_WANTED], &ret, feature_names,
+				  info);
+	if (ret < 0 || !mod)
+		return ret;
+
+	dev->wanted_features = features_from_bitmap(req_wanted);
+	netdev_update_features(dev);
+	if (!tb[ETHA_FEATURES_WANT_DIFF])
+		return 0;
+	bitmap_from_features(new_active, dev->features);
+	bitmap_xor(wanted_diff_mask, req_wanted, new_active,
+		   NETDEV_FEATURE_COUNT);
+	bitmap_xor(active_diff_mask, old_active, new_active,
+		   NETDEV_FEATURE_COUNT);
+	bitmap_and(wanted_diff_mask, wanted_diff_mask, req_mask,
+		   NETDEV_FEATURE_COUNT);
+	bitmap_and(req_wanted, req_wanted, wanted_diff_mask,
+		   NETDEV_FEATURE_COUNT);
+	bitmap_and(new_active, new_active, active_diff_mask,
+		   NETDEV_FEATURE_COUNT);
+
+	reply_len = ethnl_bitset_size(compact, NETDEV_FEATURE_COUNT, req_wanted,
+				      wanted_diff_mask, feature_names) +
+		    ethnl_bitset_size(compact, NETDEV_FEATURE_COUNT, new_active,
+				      active_diff_mask, feature_names);
+	reply_len = nla_total_size(reply_len);
+	rskb = ethnl_reply_init(reply_len, dev, ETHNL_CMD_SET_SETTINGS,
+				ETHA_SETTINGS_DEV, info, &ehdr);
+	if (!rskb)
+		goto err;
+	ret = -EMSGSIZE;
+
+	feat_attr = ethnl_nest_start(rskb, ETHA_SETTINGS_FEATURES);
+	if (!feat_attr)
+		goto err;
+	ret = ethnl_put_bitset(rskb, ETHA_FEATURES_WANTED, compact,
+			       NETDEV_FEATURE_COUNT, req_wanted,
+			       wanted_diff_mask, feature_names);
+	if (ret < 0)
+		goto err;
+	ret = ethnl_put_bitset(rskb, ETHA_FEATURES_ACTIVE, compact,
+			       NETDEV_FEATURE_COUNT, new_active,
+			       active_diff_mask, feature_names);
+	if (ret < 0)
+		goto err;
+	nla_nest_end(rskb, feat_attr);
+
+	genlmsg_end(rskb, ehdr);
+	return genlmsg_reply(rskb, info);
+err:
+	WARN_ONCE(ret == -EMSGSIZE,
+		  "calculated message payload length (%d) not sufficient\n",
+		  reply_len);
+	nlmsg_free(rskb);
+	return ret;
+}
+
 int ethnl_set_settings(struct sk_buff *skb, struct genl_info *info)
 {
 	struct nlattr *tb[ETHA_SETTINGS_MAX + 1];
@@ -1092,6 +1208,17 @@ int ethnl_set_settings(struct sk_buff *skb, struct genl_info *info)
 			req_mask |= ETH_SETTINGS_IM_MSGLEVEL;
 		}
 	}
+	if (tb[ETHA_SETTINGS_FEATURES]) {
+		bool compact = tb[ETHA_SETTINGS_COMPACT];
+
+		ret = update_features(info, dev, tb[ETHA_SETTINGS_FEATURES],
+				      compact);
+		if (ret > 0) {
+			req_mask |= ETH_SETTINGS_IM_FEATURES;
+			ret = 0;
+		}
+
+	}
 	ret = 0;
 
 out_unlock:
-- 
2.18.0

^ permalink raw reply related

* Re: [RFC PATCH net-next v2 09/17] ethtool: implement GET_DRVINFO message
From: Andrew Lunn @ 2018-07-30 14:28 UTC (permalink / raw)
  To: Michal Kubecek
  Cc: netdev, linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <4dcd60f25efe368ada4e0c035dc1d7612ab59132.1532953989.git.mkubecek@suse.cz>

On Mon, Jul 30, 2018 at 02:53:27PM +0200, Michal Kubecek wrote:
> Requests the same information as ETHTOOL_GDRVINFO command in ioct
> interface. This is read-only so that corresponding SET_DRVINFO exists but
> is only used in kernel replies.
> 
> Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
> ---
>  Documentation/networking/ethtool-netlink.txt |  38 +++++-
>  include/uapi/linux/ethtool_netlink.h         |  22 ++++
>  net/ethtool/Makefile                         |   4 +-
>  net/ethtool/common.c                         |  43 ++++++
>  net/ethtool/common.h                         |   3 +
>  net/ethtool/drvinfo.c                        | 131 +++++++++++++++++++
>  net/ethtool/ioctl.c                          |  42 +-----
>  net/ethtool/netlink.c                        |   8 ++
>  8 files changed, 252 insertions(+), 39 deletions(-)
>  create mode 100644 net/ethtool/drvinfo.c
> 
> diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
> index 8b43f41a8140..1e3d5ffc97ab 100644
> --- a/Documentation/networking/ethtool-netlink.txt
> +++ b/Documentation/networking/ethtool-netlink.txt
> @@ -121,6 +121,8 @@ List of message types
>      ETHNL_CMD_EVENT			notification only
>      ETHNL_CMD_GET_STRSET
>      ETHNL_CMD_SET_STRSET		response only
> +    ETHNL_CMD_GET_DRVINFO
> +    ETHNL_CMD_SET_DRVINFO		response only
>  
>  All constants use ETHNL_CMD_ prefix, usually followed by "GET", "SET" or "ACT"
>  to indicate the type.
> @@ -156,6 +158,40 @@ and also multiple events of the same type (e.g. two or more newly registered
>  devices).
>  
>  
> +GET_DRVINFO
> +-----------
> +
> +GET_DRVINFO request corresponds to ETHTOOL_GDRVINFO ioctl command and provides
> +basic driver information.
> +
> +Request contents:
> +
> +    ETHA_DRVINFO_DEV		(nested)	device identification
> +
> +Kernel response contents:
> +
> +    ETHA_DRVINFO_DEV		(nested)	device identification
> +    ETHA_DRVINFO_DRIVER		(string)	driver name
> +    ETHA_DRVINFO_VERSION	(string)	driver version

Driver version is generally useless. Is version X.Y.Z of a driver the
same when backported to some ancient enterprise kernel with 1000s of
patches? Now seems like a good opportunity to drop it.

> +    ETHA_DRVINFO_FWVERSION	(string)	firmware version
> +    ETHA_DRVINFO_BUSINFO	(string)	device bus address
> +    ETHA_DRVINFO_EROM_VER	(string)	expansion ROM version
> +    ETHA_DRVINFO_N_PRIV_FLAGS	(u32)		number of private flags
> +    ETHA_DRVINFO_N_STATS	(u32)		number of device stats

I know there is at least one driver that has somewhat dynamic number
of statistics. It would be better to have the strings and the values
in the same message, so there is no need to first get the number of
strings, allocate the memory, get the strings, then get the values.

> +    ETHA_DRVINFO_TESTINFO_LEN	(u32)		number of test results

In theory, this also does not need to be fixed. 

> +    ETHA_DRVINFO_EEDUMP_LEN	(u32)		EEPROM dump size
> +    ETHA_DRVINFO_REGDUMP_LEN	(u32)		register dump size

I would suggest removing all these _LEN properties, and let netlink
return what it needs to return.

       Andrew

^ permalink raw reply

* [RFC PATCH net-next v2 09/17] ethtool: implement GET_DRVINFO message
From: Michal Kubecek @ 2018-07-30 12:53 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

Requests the same information as ETHTOOL_GDRVINFO command in ioct
interface. This is read-only so that corresponding SET_DRVINFO exists but
is only used in kernel replies.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Documentation/networking/ethtool-netlink.txt |  38 +++++-
 include/uapi/linux/ethtool_netlink.h         |  22 ++++
 net/ethtool/Makefile                         |   4 +-
 net/ethtool/common.c                         |  43 ++++++
 net/ethtool/common.h                         |   3 +
 net/ethtool/drvinfo.c                        | 131 +++++++++++++++++++
 net/ethtool/ioctl.c                          |  42 +-----
 net/ethtool/netlink.c                        |   8 ++
 8 files changed, 252 insertions(+), 39 deletions(-)
 create mode 100644 net/ethtool/drvinfo.c

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 8b43f41a8140..1e3d5ffc97ab 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -121,6 +121,8 @@ List of message types
     ETHNL_CMD_EVENT			notification only
     ETHNL_CMD_GET_STRSET
     ETHNL_CMD_SET_STRSET		response only
+    ETHNL_CMD_GET_DRVINFO
+    ETHNL_CMD_SET_DRVINFO		response only
 
 All constants use ETHNL_CMD_ prefix, usually followed by "GET", "SET" or "ACT"
 to indicate the type.
@@ -156,6 +158,40 @@ and also multiple events of the same type (e.g. two or more newly registered
 devices).
 
 
+GET_DRVINFO
+-----------
+
+GET_DRVINFO request corresponds to ETHTOOL_GDRVINFO ioctl command and provides
+basic driver information.
+
+Request contents:
+
+    ETHA_DRVINFO_DEV		(nested)	device identification
+
+Kernel response contents:
+
+    ETHA_DRVINFO_DEV		(nested)	device identification
+    ETHA_DRVINFO_DRIVER		(string)	driver name
+    ETHA_DRVINFO_VERSION	(string)	driver version
+    ETHA_DRVINFO_FWVERSION	(string)	firmware version
+    ETHA_DRVINFO_BUSINFO	(string)	device bus address
+    ETHA_DRVINFO_EROM_VER	(string)	expansion ROM version
+    ETHA_DRVINFO_N_PRIV_FLAGS	(u32)		number of private flags
+    ETHA_DRVINFO_N_STATS	(u32)		number of device stats
+    ETHA_DRVINFO_TESTINFO_LEN	(u32)		number of test results
+    ETHA_DRVINFO_EEDUMP_LEN	(u32)		EEPROM dump size
+    ETHA_DRVINFO_REGDUMP_LEN	(u32)		register dump size
+
+The meaning of these follows the corresponding fields of ETHTOOL_GDRVINFO
+response.
+
+All information is read only, SET_DRVINFO request is not implemented
+(ETHNL_CMD_SET_DRVINFO messages are sent only by kernel in response to
+GET_DRVINFO requests).
+
+GET_DRVINFO requests allow dumps.
+
+
 Request translation
 -------------------
 
@@ -167,7 +203,7 @@ ioctl command			netlink command
 ---------------------------------------------------------------------
 ETHTOOL_GSET			n/a
 ETHTOOL_SSET			n/a
-ETHTOOL_GDRVINFO		n/a
+ETHTOOL_GDRVINFO		ETHNL_CMD_GET_DRVINFO
 ETHTOOL_GREGS			n/a
 ETHTOOL_GWOL			n/a
 ETHTOOL_SWOL			n/a
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 5177c1940c2b..df4de61fac48 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -10,6 +10,8 @@ enum {
 	ETHNL_CMD_EVENT,		/* only for notifications */
 	ETHNL_CMD_GET_STRSET,
 	ETHNL_CMD_SET_STRSET,		/* only for reply */
+	ETHNL_CMD_GET_DRVINFO,
+	ETHNL_CMD_SET_DRVINFO,		/* only for reply */
 
 	__ETHNL_CMD_MAX,
 	ETHNL_CMD_MAX = (__ETHNL_CMD_MAX - 1)
@@ -124,6 +126,26 @@ enum {
 	ETHA_STRSET_MAX = (__ETHA_STRSET_MAX - 1)
 };
 
+/* GET_DRVINFO / SET_DRVINFO */
+
+enum {
+	ETHA_DRVINFO_UNSPEC,
+	ETHA_DRVINFO_DEV,			/* nest - ETHA_DEV_* */
+	ETHA_DRVINFO_DRIVER,			/* string */
+	ETHA_DRVINFO_VERSION,			/* string */
+	ETHA_DRVINFO_FWVERSION,			/* string */
+	ETHA_DRVINFO_BUSINFO,			/* string */
+	ETHA_DRVINFO_EROM_VER,			/* string */
+	ETHA_DRVINFO_N_PRIV_FLAGS,		/* u32 */
+	ETHA_DRVINFO_N_STATS,			/* u32 */
+	ETHA_DRVINFO_TESTINFO_LEN,		/* u32 */
+	ETHA_DRVINFO_EEDUMP_LEN,		/* u32 */
+	ETHA_DRVINFO_REGDUMP_LEN,		/* u32 */
+
+	__ETHA_DRVINFO_MAX,
+	ETHA_DRVINFO_MAX = (__ETHA_DRVINFO_MAX - 1)
+};
+
 /* generic netlink info */
 #define ETHTOOL_GENL_NAME "ethtool"
 #define ETHTOOL_GENL_VERSION 1
diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile
index ba260d5b53b2..2e840ae0ba1e 100644
--- a/net/ethtool/Makefile
+++ b/net/ethtool/Makefile
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-y				+= ioctl.o
+obj-y				+= ioctl.o common.o
 
 obj-$(CONFIG_ETHTOOL_NETLINK)	+= ethtool_nl.o
 
-ethtool_nl-y	:= netlink.o strset.o
+ethtool_nl-y	:= netlink.o strset.o drvinfo.o
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 208259c51b73..1dc4a6515996 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 
+#include <linux/rtnetlink.h>
 #include "common.h"
 
 const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
@@ -85,3 +86,45 @@ phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
 	[ETHTOOL_PHY_DOWNSHIFT]	= "phy-downshift",
 };
 EXPORT_SYMBOL(phy_tunable_strings);
+
+int __ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	const struct ethtool_ops *ops = dev->ethtool_ops;
+
+	memset(info, 0, sizeof(*info));
+	info->cmd = ETHTOOL_GDRVINFO;
+	if (ops->get_drvinfo) {
+		ops->get_drvinfo(dev, info);
+	} else if (dev->dev.parent && dev->dev.parent->driver) {
+		strlcpy(info->bus_info, dev_name(dev->dev.parent),
+			sizeof(info->bus_info));
+		strlcpy(info->driver, dev->dev.parent->driver->name,
+			sizeof(info->driver));
+	} else {
+		return -EOPNOTSUPP;
+	}
+
+	/* this method of obtaining string set info is deprecated;
+	 * Use ETHTOOL_GSSET_INFO instead.
+	 */
+	if (ops->get_sset_count) {
+		int rc;
+
+		rc = ops->get_sset_count(dev, ETH_SS_TEST);
+		if (rc >= 0)
+			info->testinfo_len = rc;
+		rc = ops->get_sset_count(dev, ETH_SS_STATS);
+		if (rc >= 0)
+			info->n_stats = rc;
+		rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
+		if (rc >= 0)
+			info->n_priv_flags = rc;
+	}
+	if (ops->get_regs_len)
+		info->regdump_len = ops->get_regs_len(dev);
+	if (ops->get_eeprom_len)
+		info->eedump_len = ops->get_eeprom_len(dev);
+
+	return 0;
+}
+EXPORT_SYMBOL(__ethtool_get_drvinfo);
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index 45c6492e4aee..0f768c1be527 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -3,6 +3,7 @@
 #ifndef _ETHTOOL_COMMON_H
 #define _ETHTOOL_COMMON_H
 
+#include <linux/netdevice.h>
 #include <linux/ethtool.h>
 
 extern const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN];
@@ -10,4 +11,6 @@ extern const char rss_hash_func_strings[ETH_RSS_HASH_FUNCS_COUNT][ETH_GSTRING_LE
 extern const char tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN];
 extern const char phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];
 
+int __ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
+
 #endif /* _ETHTOOL_COMMON_H */
diff --git a/net/ethtool/drvinfo.c b/net/ethtool/drvinfo.c
new file mode 100644
index 000000000000..2bdaf6d7f28c
--- /dev/null
+++ b/net/ethtool/drvinfo.c
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#include "netlink.h"
+#include "common.h"
+
+static const struct nla_policy get_drvinfo_policy[ETHA_DRVINFO_MAX + 1] = {
+	[ETHA_DRVINFO_DEV]		= { .type = NLA_NESTED },
+};
+
+static int prepare_drvinfo(struct ethtool_drvinfo *data, struct genl_info *info,
+			   struct net_device *dev)
+{
+	int ret;
+
+	memset(data, '\0', sizeof(*data));
+	rtnl_lock();
+	ret = __ethtool_get_drvinfo(dev, data);
+	rtnl_unlock();
+	if (ret < 0) {
+		ETHNL_SET_ERRMSG(info, "failed to retrieve driver info");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int drvinfo_size(struct ethtool_drvinfo *drvinfo)
+{
+	int len = 0;
+
+	len += ethnl_str_ifne_size(drvinfo->driver);
+	len += ethnl_str_ifne_size(drvinfo->version);
+	len += ethnl_str_ifne_size(drvinfo->fw_version);
+	len += ethnl_str_ifne_size(drvinfo->bus_info);
+	len += ethnl_str_ifne_size(drvinfo->erom_version);
+	/* n_priv_flags, n_stats, testinfo_len, eedump_len, regdump_len */
+	len += 5 * nla_total_size(sizeof(u32));
+
+	return len;
+}
+
+static int fill_drvinfo(struct sk_buff *skb, struct net_device *dev,
+			struct ethtool_drvinfo *drvinfo)
+{
+	int ret;
+
+	ret = -EMSGSIZE;
+	if (ethnl_put_str_ifne(skb, ETHA_DRVINFO_DRIVER, drvinfo->driver) ||
+	    ethnl_put_str_ifne(skb, ETHA_DRVINFO_VERSION, drvinfo->version) ||
+	    ethnl_put_str_ifne(skb, ETHA_DRVINFO_FWVERSION,
+			       drvinfo->fw_version) ||
+	    ethnl_put_str_ifne(skb, ETHA_DRVINFO_BUSINFO, drvinfo->bus_info) ||
+	    ethnl_put_str_ifne(skb, ETHA_DRVINFO_EROM_VER,
+			       drvinfo->erom_version) ||
+	    nla_put_u32(skb, ETHA_DRVINFO_N_PRIV_FLAGS,
+			drvinfo->n_priv_flags) ||
+	    nla_put_u32(skb, ETHA_DRVINFO_N_STATS, drvinfo->n_stats) ||
+	    nla_put_u32(skb, ETHA_DRVINFO_TESTINFO_LEN,
+			drvinfo->testinfo_len) ||
+	    nla_put_u32(skb, ETHA_DRVINFO_EEDUMP_LEN, drvinfo->eedump_len) ||
+	    nla_put_u32(skb, ETHA_DRVINFO_REGDUMP_LEN, drvinfo->regdump_len))
+		return ret;
+
+	return 0;
+}
+
+int ethnl_get_drvinfo(struct sk_buff *skb, struct genl_info *info)
+{
+	struct nlattr *tb[ETHA_DRVINFO_MAX + 1];
+	struct ethtool_drvinfo drvinfo;
+	struct net_device *dev;
+	struct sk_buff *rskb;
+	int reply_len;
+	void *ehdr;
+	int ret;
+
+	ret = genlmsg_parse(info->nlhdr, &ethtool_genl_family, tb,
+			    ETHA_DRVINFO_MAX, get_drvinfo_policy, info->extack);
+	if (ret < 0)
+		return ret;
+	dev = ethnl_dev_get(info, tb[ETHA_DRVINFO_DEV]);
+	if (IS_ERR(dev))
+		return PTR_ERR(dev);
+
+	ret = prepare_drvinfo(&drvinfo, info, dev);
+	if (ret < 0)
+		goto err_dev;
+	reply_len = drvinfo_size(&drvinfo);
+	rskb = ethnl_reply_init(reply_len, dev, ETHNL_CMD_SET_DRVINFO,
+				ETHA_DRVINFO_DEV, info, &ehdr);
+	if (!rskb)
+		return -ENOMEM;
+	ret = fill_drvinfo(rskb, dev, &drvinfo);
+	if (ret < 0)
+		goto err;
+
+	genlmsg_end(rskb, ehdr);
+	dev_put(dev);
+	return genlmsg_reply(rskb, info);
+
+err:
+	WARN_ONCE(ret == -EMSGSIZE,
+		  "calculated message payload length (%d) not sufficient\n",
+		  reply_len);
+	nlmsg_free(rskb);
+err_dev:
+	dev_put(dev);
+	return ret;
+}
+
+static int drvinfo_dump(struct sk_buff *skb, struct netlink_callback *cb,
+			struct net_device *dev)
+{
+	struct ethtool_drvinfo drvinfo;
+	int ret;
+
+	ret = prepare_drvinfo(&drvinfo, NULL, dev);
+	if (ret < 0)
+		return ret;
+	ret = ethnl_fill_dev(skb, dev, ETHA_DRVINFO_DEV);
+	ret = fill_drvinfo(skb, dev, &drvinfo);
+	return ret;
+}
+
+int ethnl_drvinfo_start(struct netlink_callback *cb)
+{
+	cb->args[0] = (long)drvinfo_dump;
+	cb->args[1] = ETHNL_CMD_SET_DRVINFO;
+
+	return 0;
+}
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index a91b597073f8..7b5831d35bca 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -27,6 +27,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/sched/signal.h>
 #include <linux/net.h>
+#include "common.h"
 
 /*
  * Some useful ethtool_ops methods that're device independent.
@@ -768,45 +769,14 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
 						  void __user *useraddr)
 {
 	struct ethtool_drvinfo info;
-	const struct ethtool_ops *ops = dev->ethtool_ops;
-
-	memset(&info, 0, sizeof(info));
-	info.cmd = ETHTOOL_GDRVINFO;
-	if (ops->get_drvinfo) {
-		ops->get_drvinfo(dev, &info);
-	} else if (dev->dev.parent && dev->dev.parent->driver) {
-		strlcpy(info.bus_info, dev_name(dev->dev.parent),
-			sizeof(info.bus_info));
-		strlcpy(info.driver, dev->dev.parent->driver->name,
-			sizeof(info.driver));
-	} else {
-		return -EOPNOTSUPP;
-	}
-
-	/*
-	 * this method of obtaining string set info is deprecated;
-	 * Use ETHTOOL_GSSET_INFO instead.
-	 */
-	if (ops->get_sset_count) {
-		int rc;
-
-		rc = ops->get_sset_count(dev, ETH_SS_TEST);
-		if (rc >= 0)
-			info.testinfo_len = rc;
-		rc = ops->get_sset_count(dev, ETH_SS_STATS);
-		if (rc >= 0)
-			info.n_stats = rc;
-		rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
-		if (rc >= 0)
-			info.n_priv_flags = rc;
-	}
-	if (ops->get_regs_len)
-		info.regdump_len = ops->get_regs_len(dev);
-	if (ops->get_eeprom_len)
-		info.eedump_len = ops->get_eeprom_len(dev);
+	int rc;
 
+	rc = __ethtool_get_drvinfo(dev, &info);
+	if (rc < 0)
+		return rc;
 	if (copy_to_user(useraddr, &info, sizeof(info)))
 		return -EFAULT;
+
 	return 0;
 }
 
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 237a2cb40be4..305baa02ff70 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -670,8 +670,10 @@ static struct notifier_block ethnl_netdev_notifier = {
 /* genetlink setup */
 
 int ethnl_get_strset(struct sk_buff *skb, struct genl_info *info);
+int ethnl_get_drvinfo(struct sk_buff *skb, struct genl_info *info);
 
 int ethnl_strset_start(struct netlink_callback *cb);
+int ethnl_drvinfo_start(struct netlink_callback *cb);
 
 int ethnl_strset_done(struct netlink_callback *cb);
 
@@ -683,6 +685,12 @@ static const struct genl_ops ethtool_genl_ops[] = {
 		.dumpit	= ethnl_dumpit,
 		.done	= ethnl_strset_done,
 	},
+	{
+		.cmd	= ETHNL_CMD_GET_DRVINFO,
+		.doit	= ethnl_get_drvinfo,
+		.start	= ethnl_drvinfo_start,
+		.dumpit	= ethnl_dumpit,
+	},
 };
 
 static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
-- 
2.18.0

^ permalink raw reply related

* [RFC PATCH net-next v2 07/17] ethtool: implement EVENT notifications
From: Michal Kubecek @ 2018-07-30 12:53 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

Two types of netlink notifications are introduced: ETHA_EVENT_NEWDEV to
notify about newly registered network devices and ETHA_EVENT_DELDEV to
notify about unregistered network devices. These are triggered by
NETDEV_REGISTER and NETDEV_UNREGISTER notifiers.

These are intended for applications and daemons monitoring ethtool events
to allow updating the list of existing devices without having to open
another socket for rtnetlink.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Documentation/networking/ethtool-netlink.txt | 22 ++++++++++
 include/uapi/linux/ethtool_netlink.h         | 28 +++++++++++++
 net/ethtool/netlink.c                        | 44 ++++++++++++++++++++
 3 files changed, 94 insertions(+)

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index a49dfe3ef4bb..0e83397f2975 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -118,6 +118,8 @@ which the request applies.
 List of message types
 ---------------------
 
+    ETHNL_CMD_EVENT			notification only
+
 All constants use ETHNL_CMD_ prefix, usually followed by "GET", "SET" or "ACT"
 to indicate the type.
 
@@ -129,9 +131,29 @@ messages marked as "response only" in the table above. "Get" messages with
 NLM_F_DUMP flags and no device identification dump the information for all
 devices supporting the request.
 
+Type ETHNL_CMD_EVENT is special, these messages are never used in userspace
+requests or kernel replies. They are only sent by kernel to sockets listening
+to "monitor" multicast group to inform userspace about certain events.
+
 Later sections describe the format and semantics of these request messages.
 
 
+EVENT
+-----
+
+EVENT messages are only used in kernel multicast notifications. Atributes
+correspond to specific event types, the same type can appear multiple times.
+
+    ETHA_EVENT_NEWDEV		(nested)	new device was registered
+       ETHA_NEWDEV_DEV			(nested)	new device
+    ETHA_EVENT_DELDEV		(nested)	device was unregistered
+       ETHA_DELDEV_DEV			(nested)	removed device
+
+Userspace application must expect multiple events to be present in one message
+and also multiple events of the same type (e.g. two or more newly registered
+devices).
+
+
 Request translation
 -------------------
 
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 444a668e4a08..f162cd6f80d4 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -7,6 +7,7 @@
 
 enum {
 	ETHNL_CMD_NOOP,
+	ETHNL_CMD_EVENT,		/* only for notifications */
 
 	__ETHNL_CMD_MAX,
 	ETHNL_CMD_MAX = (__ETHNL_CMD_MAX - 1)
@@ -54,6 +55,33 @@ enum {
 	ETHA_BITSET_MAX = (__ETHA_BITSET_MAX - 1)
 };
 
+/* events */
+
+enum {
+	ETHA_NEWDEV_UNSPEC,
+	ETHA_NEWDEV_DEV,			/* nest - ETHA_DEV_* */
+
+	__ETHA_NEWDEV_MAX,
+	ETHA_NEWDEV_MAX = (__ETHA_NEWDEV_MAX - 1)
+};
+
+enum {
+	ETHA_DELDEV_UNSPEC,
+	ETHA_DELDEV_DEV,			/* nest - ETHA_DEV_* */
+
+	__ETHA_DELDEV_MAX,
+	ETHA_DELDEV_MAX = (__ETHA_DELDEV_MAX - 1)
+};
+
+enum {
+	ETHA_EVENT_UNSPEC,
+	ETHA_EVENT_NEWDEV,			/* nest - ETHA_NEWDEV_* */
+	ETHA_EVENT_DELDEV,			/* nest - ETHA_DELDEV_* */
+
+	__ETHA_EVENT_MAX,
+	ETHA_EVENT_MAX = (__ETHA_EVENT_MAX - 1)
+};
+
 /* generic netlink info */
 #define ETHTOOL_GENL_NAME "ethtool"
 #define ETHTOOL_GENL_VERSION 1
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index e4a20bb6c1d4..543560778c80 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -607,6 +607,44 @@ void ethnl_notify(struct net_device *dev, struct netlink_ext_ack *extack,
 	return __ethnl_notify(&ethtool_info);
 }
 
+static unsigned int dev_notify_size(void)
+{
+	return nla_total_size(nla_total_size(nla_total_size(sizeof(u32)) +
+					     nla_total_size(IFNAMSIZ)));
+}
+
+static void ethnl_notify_devlist(struct netdev_notifier_info *info,
+				 u16 ev_type, u16 dev_attr)
+{
+	struct net_device *dev = netdev_notifier_info_to_dev(info);
+	struct sk_buff *skb;
+	struct nlattr *nest;
+	void *ehdr;
+	int ret;
+
+	skb = genlmsg_new(dev_notify_size(), GFP_KERNEL);
+	if (!skb)
+		return;
+	ehdr = genlmsg_put(skb, 0, ++ethnl_bcast_seq, &ethtool_genl_family, 0,
+			   ETHNL_CMD_EVENT);
+	if (!ehdr)
+		goto out_skb;
+	nest = ethnl_nest_start(skb, ev_type);
+	if (!nest)
+		goto out_skb;
+	ret = ethnl_fill_dev(skb, dev, dev_attr);
+	if (ret < 0)
+		goto out_skb;
+	nla_nest_end(skb, nest);
+	genlmsg_end(skb, ehdr);
+
+	genlmsg_multicast(&ethtool_genl_family, skb, 0, ETHNL_MCGRP_MONITOR,
+			  GFP_KERNEL);
+	return;
+out_skb:
+	nlmsg_free(skb);
+}
+
 static int ethnl_netdev_event(struct notifier_block *this, unsigned long event,
 			      void *ptr)
 {
@@ -614,6 +652,12 @@ static int ethnl_netdev_event(struct notifier_block *this, unsigned long event,
 	case NETDEV_ETHTOOL:
 		__ethnl_notify(ptr);
 		break;
+	case NETDEV_REGISTER:
+		ethnl_notify_devlist(ptr, ETHA_EVENT_NEWDEV, ETHA_NEWDEV_DEV);
+		break;
+	case NETDEV_UNREGISTER:
+		ethnl_notify_devlist(ptr, ETHA_EVENT_DELDEV, ETHA_DELDEV_DEV);
+		break;
 	}
 
 	return NOTIFY_DONE;
-- 
2.18.0

^ permalink raw reply related

* [RFC PATCH net-next v2 06/17] ethtool: support for netlink notifications
From: Michal Kubecek @ 2018-07-30 12:53 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, Jiri Pirko, David Miller, Florian Fainelli,
	Roopa Prabhu, Jakub Kicinski, John W. Linville
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

Add infrastructure for ethtool netlink notifications. There is only one
multicast group, "monitor" which userspace can use to get notifications.
Notifications are supposed to be broadcasted on every configuration change,
whether it is done using the netlink interface or legacy ioctl one.

To trigger a notification, netlink code calls ethtool_notify(), external
code (ioctl interface) uses NETDEV_ETHTOOL event, preferrably by the means
of netdev_ethtool_info_change() helper. For both, the caller must hold
RTNL (and, obviously, allow sleeping).

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 include/linux/ethtool_netlink.h      |  5 ++
 include/linux/netdevice.h            | 23 ++++++++
 include/uapi/linux/ethtool_netlink.h |  2 +
 net/core/dev.c                       | 24 +++++++-
 net/ethtool/netlink.c                | 82 +++++++++++++++++++++++++++-
 net/ethtool/netlink.h                |  5 ++
 6 files changed, 139 insertions(+), 2 deletions(-)

diff --git a/include/linux/ethtool_netlink.h b/include/linux/ethtool_netlink.h
index 0412adb4f42f..2a15e64a16f3 100644
--- a/include/linux/ethtool_netlink.h
+++ b/include/linux/ethtool_netlink.h
@@ -5,5 +5,10 @@
 
 #include <uapi/linux/ethtool_netlink.h>
 #include <linux/ethtool.h>
+#include <linux/netdevice.h>
+
+enum ethtool_multicast_groups {
+	ETHNL_MCGRP_MONITOR,
+};
 
 #endif /* _LINUX_ETHTOOL_NETLINK_H_ */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index c1295c7a452e..c4b0c575d57e 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2444,6 +2444,7 @@ enum netdev_cmd {
 	NETDEV_CVLAN_FILTER_DROP_INFO,
 	NETDEV_SVLAN_FILTER_PUSH_INFO,
 	NETDEV_SVLAN_FILTER_DROP_INFO,
+	NETDEV_ETHTOOL,
 };
 const char *netdev_cmd_to_name(enum netdev_cmd cmd);
 
@@ -4221,6 +4222,28 @@ struct netdev_notifier_bonding_info {
 void netdev_bonding_info_change(struct net_device *dev,
 				struct netdev_bonding_info *bonding_info);
 
+struct netdev_ethtool_info {
+	unsigned int cmd;
+	u32 req_mask;
+};
+
+struct netdev_notifier_ethtool_info {
+	struct netdev_notifier_info info; /* must be first */
+	struct netdev_ethtool_info ethtool_info;
+};
+
+#if IS_ENABLED(CONFIG_ETHTOOL_NETLINK)
+int netdev_ethtool_info_change(struct net_device *dev,
+			       struct netlink_ext_ack *extack,
+			       unsigned int cmd, u32 req_mask);
+#else
+static inline void netdev_ethtool_info_change(struct net_device *dev,
+					      struct netlink_ext_ack *extack,
+					      unsigned int cmd, u32 req_mask)
+{
+}
+#endif
+
 static inline
 struct sk_buff *skb_gso_segment(struct sk_buff *skb, netdev_features_t features)
 {
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 98d6fae315f3..444a668e4a08 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -58,4 +58,6 @@ enum {
 #define ETHTOOL_GENL_NAME "ethtool"
 #define ETHTOOL_GENL_VERSION 1
 
+#define ETHTOOL_MCGRP_MONITOR_NAME "monitor"
+
 #endif /* _UAPI_LINUX_ETHTOOL_NETLINK_H_ */
diff --git a/net/core/dev.c b/net/core/dev.c
index 87c42c8249ae..8a0773a52dd7 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1585,7 +1585,7 @@ const char *netdev_cmd_to_name(enum netdev_cmd cmd)
 	N(PRECHANGEUPPER) N(CHANGELOWERSTATE) N(UDP_TUNNEL_PUSH_INFO)
 	N(UDP_TUNNEL_DROP_INFO) N(CHANGE_TX_QUEUE_LEN)
 	N(CVLAN_FILTER_PUSH_INFO) N(CVLAN_FILTER_DROP_INFO)
-	N(SVLAN_FILTER_PUSH_INFO) N(SVLAN_FILTER_DROP_INFO)
+	N(SVLAN_FILTER_PUSH_INFO) N(SVLAN_FILTER_DROP_INFO) N(ETHTOOL)
 	}
 #undef N
 	return "UNKNOWN_NETDEV_EVENT";
@@ -7058,6 +7058,28 @@ void netdev_bonding_info_change(struct net_device *dev,
 }
 EXPORT_SYMBOL(netdev_bonding_info_change);
 
+#if IS_ENABLED(CONFIG_ETHTOOL_NETLINK)
+int netdev_ethtool_info_change(struct net_device *dev,
+			       struct netlink_ext_ack *extack,
+			       unsigned int cmd, u32 req_mask)
+{
+	struct netdev_notifier_ethtool_info ethtool_info = {
+		.info = {
+			.dev = dev,
+			.extack = extack,
+		},
+		.ethtool_info = {
+			.cmd = cmd,
+			.req_mask = req_mask,
+		},
+	};
+
+	return call_netdevice_notifiers_info(NETDEV_ETHTOOL,
+					     &ethtool_info.info);
+}
+EXPORT_SYMBOL(netdev_ethtool_info_change);
+#endif
+
 static void netdev_adjacent_add_links(struct net_device *dev)
 {
 	struct netdev_adjacent *iter;
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index df065fd3dc80..e4a20bb6c1d4 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -6,6 +6,8 @@
 #include <linux/ethtool_netlink.h>
 #include "netlink.h"
 
+u32 ethnl_bcast_seq;
+
 static const struct nla_policy dev_policy[ETHA_DEV_MAX + 1] = {
 	[ETHA_DEV_UNSPEC]	= { .type = NLA_UNSPEC },
 	[ETHA_DEV_INDEX]	= { .type = NLA_U32 },
@@ -19,6 +21,11 @@ struct net_device *ethnl_dev_get(struct genl_info *info, struct nlattr *nest)
 	struct net_device *dev;
 	int ret;
 
+	if (!nest) {
+		ETHNL_SET_ERRMSG(info,
+				 "mandatory device identification missing");
+		return ERR_PTR(-EINVAL);
+	}
 	ret = nla_parse_nested(tb, ETHA_DEV_MAX, nest, dev_policy,
 			       info->extack);
 	if (ret < 0)
@@ -562,11 +569,69 @@ int ethnl_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
 	return ret;
 }
 
+/* notifications */
+
+typedef void (*ethnl_notify_handler_t)(struct netdev_notifier_ethtool_info *);
+
+ethnl_notify_handler_t ethnl_notify_handlers[] = {
+};
+
+static void __ethnl_notify(struct netdev_notifier_ethtool_info *info)
+{
+	unsigned int cmd = info->ethtool_info.cmd;
+
+	ASSERT_RTNL();
+	if (likely(cmd < ARRAY_SIZE(ethnl_notify_handlers) &&
+		   ethnl_notify_handlers[cmd]))
+		ethnl_notify_handlers[cmd](info);
+	else
+		WARN_ONCE(1, "notification %u not implemented (dev=%s, req_mask=0x%x\n",
+			  cmd, netdev_name(info->info.dev),
+			  info->ethtool_info.req_mask);
+}
+
+void ethnl_notify(struct net_device *dev, struct netlink_ext_ack *extack,
+		  unsigned int cmd, u32 req_mask)
+{
+	struct netdev_notifier_ethtool_info ethtool_info = {
+		.info = {
+			.dev = dev,
+			.extack = extack,
+		},
+		.ethtool_info = {
+			.cmd = cmd,
+			.req_mask = req_mask,
+		},
+	};
+
+	return __ethnl_notify(&ethtool_info);
+}
+
+static int ethnl_netdev_event(struct notifier_block *this, unsigned long event,
+			      void *ptr)
+{
+	switch(event) {
+	case NETDEV_ETHTOOL:
+		__ethnl_notify(ptr);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block ethnl_netdev_notifier = {
+	.notifier_call = ethnl_netdev_event,
+};
+
 /* genetlink setup */
 
 static const struct genl_ops ethtool_genl_ops[] = {
 };
 
+static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
+	[ETHNL_MCGRP_MONITOR] = { .name = ETHTOOL_MCGRP_MONITOR_NAME },
+};
+
 struct genl_family ethtool_genl_family = {
 	.hdrsize	= 0,
 	.name		= ETHTOOL_GENL_NAME,
@@ -575,17 +640,32 @@ struct genl_family ethtool_genl_family = {
 	.parallel_ops	= true,
 	.ops		= ethtool_genl_ops,
 	.n_ops		= ARRAY_SIZE(ethtool_genl_ops),
+	.mcgrps		= ethtool_nl_mcgrps,
+	.n_mcgrps	= ARRAY_SIZE(ethtool_nl_mcgrps),
 };
 
 /* module setup */
 
 static int __init ethtool_nl_init(void)
 {
-	return genl_register_family(&ethtool_genl_family);
+	int ret;
+
+	ret = genl_register_family(&ethtool_genl_family);
+	if (ret < 0)
+		return ret;
+	ret = register_netdevice_notifier(&ethnl_netdev_notifier);
+	if (ret < 0)
+		goto err_unregister;
+	return 0;
+
+err_unregister:
+	genl_unregister_family(&ethtool_genl_family);
+	return ret;
 }
 
 static void __exit ethtool_nl_exit(void)
 {
+	unregister_netdevice_notifier(&ethnl_netdev_notifier);
 	genl_unregister_family(&ethtool_genl_family);
 }
 
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index 6e9e854eec5d..94c14ec2c3fc 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -11,6 +11,8 @@
 #define ETHNL_SET_ERRMSG(info, msg) \
 	do { if (info) GENL_SET_ERR_MSG(info, msg); } while (0)
 
+extern u32 ethnl_bcast_seq;
+
 extern struct genl_family ethtool_genl_family;
 
 struct net_device *ethnl_dev_get(struct genl_info *info, struct nlattr *nest);
@@ -159,4 +161,7 @@ static inline bool ethnl_is_privileged(struct sk_buff *skb)
 	return netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN);
 }
 
+void ethnl_notify(struct net_device *dev, struct netlink_ext_ack *extack,
+		  unsigned int cmd, u32 req_mask);
+
 #endif /* _NET_ETHTOOL_NETLINK_H */
-- 
2.18.0

^ permalink raw reply related

* KASAN: use-after-free Read in finish_wait (2)
From: syzbot @ 2018-07-30 14:28 UTC (permalink / raw)
  To: davem, kuznet, linux-kernel, netdev, syzkaller-bugs, yoshfuji

Hello,

syzbot found the following crash on:

HEAD commit:    19725496da56 Merge ra.kernel.org:/pub/scm/linux/kernel/git..
git tree:       net-next
console output: https://syzkaller.appspot.com/x/log.txt?x=16ac69a4400000
kernel config:  https://syzkaller.appspot.com/x/.config?x=ee7720ff122639ee
dashboard link: https://syzkaller.appspot.com/bug?extid=0bace015a67c7862c2cb
compiler:       gcc (GCC) 8.0.1 20180413 (experimental)

Unfortunately, I don't have any reproducer for this crash yet.

IMPORTANT: if you fix the bug, please add the following tag to the commit:
Reported-by: syzbot+0bace015a67c7862c2cb@syzkaller.appspotmail.com

==================================================================
BUG: KASAN: use-after-free in __list_del_entry_valid+0xf1/0xf3  
lib/list_debug.c:51
Read of size 8 at addr ffff8801d025f278 by task kworker/0:1/25

CPU: 0 PID: 25 Comm: kworker/0:1 Not tainted 4.18.0-rc6+ #140
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS  
Google 01/01/2011
Workqueue: events smc_tcp_listen_work
Call Trace:
  __dump_stack lib/dump_stack.c:77 [inline]
  dump_stack+0x1c9/0x2b4 lib/dump_stack.c:113
  print_address_description+0x6c/0x20b mm/kasan/report.c:256
  kasan_report_error mm/kasan/report.c:354 [inline]
  kasan_report.cold.7+0x242/0x2fe mm/kasan/report.c:412
  __asan_report_load8_noabort+0x14/0x20 mm/kasan/report.c:433
  __list_del_entry_valid+0xf1/0xf3 lib/list_debug.c:51
  __list_del_entry include/linux/list.h:117 [inline]
  list_del_init include/linux/list.h:159 [inline]
  finish_wait+0x128/0x430 kernel/sched/wait.c:365
  inet_csk_wait_for_connect net/ipv4/inet_connection_sock.c:418 [inline]
  inet_csk_accept+0x6d0/0xe70 net/ipv4/inet_connection_sock.c:451
  inet_accept+0x138/0xa00 net/ipv4/af_inet.c:735
  kernel_accept+0x136/0x310 net/socket.c:3251
  smc_clcsock_accept net/smc/af_smc.c:832 [inline]
  smc_tcp_listen_work+0x222/0xef0 net/smc/af_smc.c:1296
  process_one_work+0xc73/0x1ba0 kernel/workqueue.c:2153
  worker_thread+0x189/0x13c0 kernel/workqueue.c:2296
  kthread+0x345/0x410 kernel/kthread.c:246
  ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:412

Allocated by task 19352:
  save_stack+0x43/0xd0 mm/kasan/kasan.c:448
  set_track mm/kasan/kasan.c:460 [inline]
  kasan_kmalloc+0xc4/0xe0 mm/kasan/kasan.c:553
  kmem_cache_alloc_trace+0x152/0x780 mm/slab.c:3620
  kmalloc include/linux/slab.h:513 [inline]
  sock_alloc_inode+0xbc/0x320 net/socket.c:246
  alloc_inode+0x63/0x190 fs/inode.c:210
  new_inode_pseudo+0x71/0x1a0 fs/inode.c:895
  sock_alloc+0x41/0x270 net/socket.c:567
  __sock_create+0x175/0x940 net/socket.c:1250
  sock_create_kern+0x3b/0x50 net/socket.c:1332
  smc_create+0x141/0x360 net/smc/af_smc.c:1892
  __sock_create+0x53c/0x940 net/socket.c:1286
  sock_create net/socket.c:1326 [inline]
  __sys_socket+0x106/0x260 net/socket.c:1356
  __do_sys_socket net/socket.c:1365 [inline]
  __se_sys_socket net/socket.c:1363 [inline]
  __x64_sys_socket+0x73/0xb0 net/socket.c:1363
  do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290
  entry_SYSCALL_64_after_hwframe+0x49/0xbe

Freed by task 19352:
  save_stack+0x43/0xd0 mm/kasan/kasan.c:448
  set_track mm/kasan/kasan.c:460 [inline]
  __kasan_slab_free+0x11a/0x170 mm/kasan/kasan.c:521
  kasan_slab_free+0xe/0x10 mm/kasan/kasan.c:528
  __cache_free mm/slab.c:3498 [inline]
  kfree+0xd9/0x260 mm/slab.c:3813
  __rcu_reclaim kernel/rcu/rcu.h:173 [inline]
  rcu_do_batch kernel/rcu/tree.c:2558 [inline]
  invoke_rcu_callbacks kernel/rcu/tree.c:2818 [inline]
  __rcu_process_callbacks kernel/rcu/tree.c:2785 [inline]
  rcu_process_callbacks+0x1004/0x1850 kernel/rcu/tree.c:2802
  __do_softirq+0x2e8/0xb17 kernel/softirq.c:292

The buggy address belongs to the object at ffff8801d025f240
  which belongs to the cache kmalloc-128 of size 128
The buggy address is located 56 bytes inside of
  128-byte region [ffff8801d025f240, ffff8801d025f2c0)
The buggy address belongs to the page:
page:ffffea00074097c0 count:1 mapcount:0 mapping:ffff8801dac00640 index:0x0
flags: 0x2fffc0000000100(slab)
raw: 02fffc0000000100 ffffea0006c2a188 ffffea00072ca2c8 ffff8801dac00640
raw: 0000000000000000 ffff8801d025f000 0000000100000015 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
  ffff8801d025f100: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
  ffff8801d025f180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ffff8801d025f200: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
                                                                 ^
  ffff8801d025f280: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
  ffff8801d025f300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================


---
This bug is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

syzbot will keep track of this bug report. See:
https://goo.gl/tpsmEJ#bug-status-tracking for how to communicate with  
syzbot.

^ permalink raw reply

* WARNING: ODEBUG bug in vsock_stream_connect
From: syzbot @ 2018-07-30 14:28 UTC (permalink / raw)
  To: davem, dvlasenk, jhansen, linux-kernel, netdev, stefanha,
	syzkaller-bugs, viro, xiyou.wangcong

Hello,

syzbot found the following crash on:

HEAD commit:    3cfb6772d4cf Merge tag 'ext4_for_linus_stable' of git://gi..
git tree:       upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=12adc770400000
kernel config:  https://syzkaller.appspot.com/x/.config?x=ffb4428fdc82f93b
dashboard link: https://syzkaller.appspot.com/bug?extid=8a9b1bd330476a4f3db6
compiler:       gcc (GCC) 8.0.1 20180413 (experimental)
userspace arch: i386

Unfortunately, I don't have any reproducer for this crash yet.

IMPORTANT: if you fix the bug, please add the following tag to the commit:
Reported-by: syzbot+8a9b1bd330476a4f3db6@syzkaller.appspotmail.com

xt_cluster: you have exceeded the maximum number of cluster nodes  
(2147483647 > 32)
xt_cluster: you have exceeded the maximum number of cluster nodes  
(2147483647 > 32)
------------[ cut here ]------------
ODEBUG: init active (active state 0) object type: timer_list hint:  
delayed_work_timer_fn+0x0/0x90 kernel/workqueue.c:1414
WARNING: CPU: 1 PID: 11518 at lib/debugobjects.c:329  
debug_print_object+0x16a/0x210 lib/debugobjects.c:326
Kernel panic - not syncing: panic_on_warn set ...

CPU: 1 PID: 11518 Comm: syz-executor0 Not tainted 4.18.0-rc6+ #71
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS  
Google 01/01/2011
Call Trace:
  __dump_stack lib/dump_stack.c:77 [inline]
  dump_stack+0x1c9/0x2b4 lib/dump_stack.c:113
  panic+0x238/0x4e7 kernel/panic.c:184
  __warn.cold.8+0x163/0x1ba kernel/panic.c:536
  report_bug+0x252/0x2d0 lib/bug.c:186
  fixup_bug arch/x86/kernel/traps.c:178 [inline]
  do_error_trap+0x1fc/0x4d0 arch/x86/kernel/traps.c:296
  do_invalid_op+0x1b/0x20 arch/x86/kernel/traps.c:316
  invalid_op+0x14/0x20 arch/x86/entry/entry_64.S:992
RIP: 0010:debug_print_object+0x16a/0x210 lib/debugobjects.c:326
Code: 3a 87 48 89 fa 48 c1 ea 03 80 3c 02 00 0f 85 92 00 00 00 48 8b 14 dd  
20 74 3a 87 4c 89 f6 48 c7 c7 c0 69 3a 87 e8 a6 b0 e6 fd <0f> 0b 83 05 89  
e6 29 05 01 48 83 c4 18 5b 41 5c 41 5d 41 5e 41 5f
RSP: 0018:ffff88019a3f7608 EFLAGS: 00010086
RAX: 0000000000000000 RBX: 0000000000000003 RCX: ffffc90002216000
RDX: 00000000000273f5 RSI: ffffffff81632531 RDI: 0000000000000001
RBP: ffff88019a3f7648 R08: ffff8801b31e4280 R09: ffffed003b623ec2
R10: ffffed003b623ec2 R11: ffff8801db11f617 R12: 0000000000000001
R13: ffffffff87f9c9e0 R14: ffffffff873a6fc0 R15: ffffffff81691950
  __debug_object_init+0x8e9/0x12e0 lib/debugobjects.c:403
  debug_object_init+0x16/0x20 lib/debugobjects.c:429
  debug_timer_init kernel/time/timer.c:704 [inline]
  debug_init kernel/time/timer.c:757 [inline]
  init_timer_key+0xa9/0x490 kernel/time/timer.c:806
  vsock_stream_connect+0xc7a/0xfc0 net/vmw_vsock/af_vsock.c:1224
  __sys_connect+0x37d/0x4c0 net/socket.c:1673
  __do_sys_connect net/socket.c:1684 [inline]
  __se_sys_connect net/socket.c:1681 [inline]
  __ia32_sys_connect+0x72/0xb0 net/socket.c:1681
  do_syscall_32_irqs_on arch/x86/entry/common.c:326 [inline]
  do_fast_syscall_32+0x34d/0xfb2 arch/x86/entry/common.c:397
  entry_SYSENTER_compat+0x70/0x7f arch/x86/entry/entry_64_compat.S:139
RIP: 0023:0xf7f9ccb9
Code: 55 08 8b 88 64 cd ff ff 8b 98 68 cd ff ff 89 c8 85 d2 74 02 89 0a 5b  
5d c3 8b 04 24 c3 8b 1c 24 c3 51 52 55 89 e5 0f 34 cd 80 <5d> 5a 59 c3 90  
90 90 90 eb 0d 90 90 90 90 90 90 90 90 90 90 90 90
RSP: 002b:00000000f5f560cc EFLAGS: 00000296 ORIG_RAX: 000000000000016a
RAX: ffffffffffffffda RBX: 0000000000000014 RCX: 0000000020000100
RDX: 0000000000000010 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000
R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000

======================================================
WARNING: possible circular locking dependency detected
4.18.0-rc6+ #71 Not tainted
------------------------------------------------------
syz-executor0/11518 is trying to acquire lock:
00000000f38f30b0 ((console_sem).lock){-.-.}, at: down_trylock+0x13/0x70  
kernel/locking/semaphore.c:136

but task is already holding lock:
00000000356b0a02 (&obj_hash[i].lock){-.-.}, at:  
__debug_object_init+0x127/0x12e0 lib/debugobjects.c:381

which lock already depends on the new lock.


the existing dependency chain (in reverse order) is:

-> #3 (&obj_hash[i].lock){-.-.}:
        __raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:110 [inline]
        _raw_spin_lock_irqsave+0x96/0xc0 kernel/locking/spinlock.c:152
        __debug_object_init+0x127/0x12e0 lib/debugobjects.c:381
        debug_object_init+0x16/0x20 lib/debugobjects.c:429
        debug_hrtimer_init kernel/time/hrtimer.c:410 [inline]
        debug_init kernel/time/hrtimer.c:458 [inline]
        hrtimer_init+0x97/0x480 kernel/time/hrtimer.c:1308
        init_dl_task_timer+0x1b/0x50 kernel/sched/deadline.c:1056
        __sched_fork+0x2ae/0x590 kernel/sched/core.c:2185
        init_idle+0x75/0x7a0 kernel/sched/core.c:5405
        sched_init+0xbf3/0xd2c kernel/sched/core.c:6103
        start_kernel+0x47d/0x949 init/main.c:602
        x86_64_start_reservations+0x29/0x2b arch/x86/kernel/head64.c:452
        x86_64_start_kernel+0x76/0x79 arch/x86/kernel/head64.c:433
        secondary_startup_64+0xa5/0xb0 arch/x86/kernel/head_64.S:242

-> #2 (&rq->lock){-.-.}:
        __raw_spin_lock include/linux/spinlock_api_smp.h:142 [inline]
        _raw_spin_lock+0x2a/0x40 kernel/locking/spinlock.c:144
        rq_lock kernel/sched/sched.h:1812 [inline]
        task_fork_fair+0x93/0x680 kernel/sched/fair.c:9952
        sched_fork+0x446/0xb40 kernel/sched/core.c:2381
        copy_process.part.39+0x1bf5/0x70b0 kernel/fork.c:1796
        copy_process kernel/fork.c:1639 [inline]
        _do_fork+0x291/0x12a0 kernel/fork.c:2122
        kernel_thread+0x34/0x40 kernel/fork.c:2181
        rest_init+0x22/0xe4 init/main.c:408
        start_kernel+0x90e/0x949 init/main.c:738
        x86_64_start_reservations+0x29/0x2b arch/x86/kernel/head64.c:452
        x86_64_start_kernel+0x76/0x79 arch/x86/kernel/head64.c:433
        secondary_startup_64+0xa5/0xb0 arch/x86/kernel/head_64.S:242

-> #1 (&p->pi_lock){-.-.}:
        __raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:110 [inline]
        _raw_spin_lock_irqsave+0x96/0xc0 kernel/locking/spinlock.c:152
        try_to_wake_up+0xd2/0x12a0 kernel/sched/core.c:1985
        wake_up_process+0x10/0x20 kernel/sched/core.c:2148
        __up.isra.1+0x1c0/0x2a0 kernel/locking/semaphore.c:262
        up+0x13c/0x1c0 kernel/locking/semaphore.c:187
        __up_console_sem+0xbe/0x1b0 kernel/printk/printk.c:242
        console_unlock+0x7a2/0x10b0 kernel/printk/printk.c:2411
        vprintk_emit+0x6c6/0xdf0 kernel/printk/printk.c:1907
        vprintk_default+0x28/0x30 kernel/printk/printk.c:1948
        vprintk_func+0x7a/0xe7 kernel/printk/printk_safe.c:382
        printk+0xa7/0xcf kernel/printk/printk.c:1981
        load_umh+0x51/0xbd net/bpfilter/bpfilter_kern.c:98
        do_one_initcall+0x127/0x913 init/main.c:884
        do_initcall_level init/main.c:952 [inline]
        do_initcalls init/main.c:960 [inline]
        do_basic_setup init/main.c:978 [inline]
        kernel_init_freeable+0x49b/0x58e init/main.c:1135
        kernel_init+0x11/0x1b3 init/main.c:1061
        ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:412

-> #0 ((console_sem).lock){-.-.}:
        lock_acquire+0x1e4/0x540 kernel/locking/lockdep.c:3924
        __raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:110 [inline]
        _raw_spin_lock_irqsave+0x96/0xc0 kernel/locking/spinlock.c:152
        down_trylock+0x13/0x70 kernel/locking/semaphore.c:136
        __down_trylock_console_sem+0xae/0x200 kernel/printk/printk.c:225
        console_trylock+0x15/0xa0 kernel/printk/printk.c:2230
        console_trylock_spinning kernel/printk/printk.c:1643 [inline]
        vprintk_emit+0x6ad/0xdf0 kernel/printk/printk.c:1906
        vprintk_default+0x28/0x30 kernel/printk/printk.c:1948
        vprintk_func+0x7a/0xe7 kernel/printk/printk_safe.c:382
        printk+0xa7/0xcf kernel/printk/printk.c:1981
        __warn_printk+0x8c/0xe0 kernel/panic.c:590
        debug_print_object+0x16a/0x210 lib/debugobjects.c:326
        __debug_object_init+0x8e9/0x12e0 lib/debugobjects.c:403
        debug_object_init+0x16/0x20 lib/debugobjects.c:429
        debug_timer_init kernel/time/timer.c:704 [inline]
        debug_init kernel/time/timer.c:757 [inline]
        init_timer_key+0xa9/0x490 kernel/time/timer.c:806
        vsock_stream_connect+0xc7a/0xfc0 net/vmw_vsock/af_vsock.c:1224
        __sys_connect+0x37d/0x4c0 net/socket.c:1673
        __do_sys_connect net/socket.c:1684 [inline]
        __se_sys_connect net/socket.c:1681 [inline]
        __ia32_sys_connect+0x72/0xb0 net/socket.c:1681
        do_syscall_32_irqs_on arch/x86/entry/common.c:326 [inline]
        do_fast_syscall_32+0x34d/0xfb2 arch/x86/entry/common.c:397
        entry_SYSENTER_compat+0x70/0x7f arch/x86/entry/entry_64_compat.S:139

other info that might help us debug this:

Chain exists of:
   (console_sem).lock --> &rq->lock --> &obj_hash[i].lock

  Possible unsafe locking scenario:

        CPU0                    CPU1
        ----                    ----
   lock(&obj_hash[i].lock);
                                lock(&rq->lock);
                                lock(&obj_hash[i].lock);
   lock((console_sem).lock);

  *** DEADLOCK ***

2 locks held by syz-executor0/11518:
  #0: 000000004b97997e (sk_lock-AF_VSOCK){+.+.}, at: lock_sock  
include/net/sock.h:1474 [inline]
  #0: 000000004b97997e (sk_lock-AF_VSOCK){+.+.}, at:  
vsock_stream_connect+0x1e3/0xfc0 net/vmw_vsock/af_vsock.c:1152
  #1: 00000000356b0a02 (&obj_hash[i].lock){-.-.}, at:  
__debug_object_init+0x127/0x12e0 lib/debugobjects.c:381

stack backtrace:
CPU: 1 PID: 11518 Comm: syz-executor0 Not tainted 4.18.0-rc6+ #71
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS  
Google 01/01/2011
Call Trace:
  __dump_stack lib/dump_stack.c:77 [inline]
  dump_stack+0x1c9/0x2b4 lib/dump_stack.c:113
  print_circular_bug.isra.36.cold.57+0x1bd/0x27d  
kernel/locking/lockdep.c:1227
  check_prev_add kernel/locking/lockdep.c:1867 [inline]
  check_prevs_add kernel/locking/lockdep.c:1980 [inline]
  validate_chain kernel/locking/lockdep.c:2421 [inline]
  __lock_acquire+0x3449/0x5020 kernel/locking/lockdep.c:3435
  lock_acquire+0x1e4/0x540 kernel/locking/lockdep.c:3924
  __raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:110 [inline]
  _raw_spin_lock_irqsave+0x96/0xc0 kernel/locking/spinlock.c:152
  down_trylock+0x13/0x70 kernel/locking/semaphore.c:136
  __down_trylock_console_sem+0xae/0x200 kernel/printk/printk.c:225
  console_trylock+0x15/0xa0 kernel/printk/printk.c:2230
  console_trylock_spinning kernel/printk/printk.c:1643 [inline]
  vprintk_emit+0x6ad/0xdf0 kernel/printk/printk.c:1906
  vprintk_default+0x28/0x30 kernel/printk/printk.c:1948
  vprintk_func+0x7a/0xe7 kernel/printk/printk_safe.c:382
  printk+0xa7/0xcf kernel/printk/printk.c:1981
  __warn_printk+0x8c/0xe0 kernel/panic.c:590
  debug_print_object+0x16a/0x210 lib/debugobjects.c:326
  __debug_object_init+0x8e9/0x12e0 lib/debugobjects.c:403
  debug_object_init+0x16/0x20 lib/debugobjects.c:429
  debug_timer_init kernel/time/timer.c:704 [inline]
  debug_init kernel/time/timer.c:757 [inline]
  init_timer_key+0xa9/0x490 kernel/time/timer.c:806
  vsock_stream_connect+0xc7a/0xfc0 net/vmw_vsock/af_vsock.c:1224
  __sys_connect+0x37d/0x4c0 net/socket.c:1673
  __do_sys_connect net/socket.c:1684 [inline]
  __se_sys_connect net/socket.c:1681 [inline]
  __ia32_sys_connect+0x72/0xb0 net/socket.c:1681
  do_syscall_32_irqs_on arch/x86/entry/common.c:326 [inline]
  do_fast_syscall_32+0x34d/0xfb2 arch/x86/entry/common.c:397
  entry_SYSENTER_compat+0x70/0x7f arch/x86/entry/entry_64_compat.S:139
RIP: 0023:0xf7f9ccb9
Code: 55 08 8b 88 64 cd ff ff 8b 98 68 cd ff ff 89 c8 85 d2 74 02 89 0a 5b  
5d c3 8b 04 24 c3 8b 1c 24 c3 51 52 55 89 e5 0f 34 cd 80 <5d> 5a 59 c3 90  
90 90 90 eb 0d 90 90 90 90 90 90 90 90 90 90 90 90
RSP: 002b:00000000f5f560cc EFLAGS: 00000296 ORIG_RAX: 000000000000016a
RAX: ffffffffffffffda RBX: 0000000000000014 RCX: 0000000020000100
RDX: 0000000000000010 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000
R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
Dumping ftrace buffer:
    (ftrace buffer empty)
Kernel Offset: disabled
Rebooting in 86400 seconds..


---
This bug is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

syzbot will keep track of this bug report. See:
https://goo.gl/tpsmEJ#bug-status-tracking for how to communicate with  
syzbot.

^ permalink raw reply

* Re: [RFC bpf-next 0/6] net: xsk: minor improvements around queue handling
From: Björn Töpel @ 2018-07-30 12:49 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Alexei Starovoitov, Daniel Borkmann, Jesper Dangaard Brouer,
	Björn Töpel, Karlsson, Magnus, oss-drivers, Netdev,
	Ilias Apalodimas, Francois Ozog, MykytaI Iziumtsev
In-Reply-To: <20180726214148.2087-1-jakub.kicinski@netronome.com>

Den tors 26 juli 2018 kl 23:44 skrev Jakub Kicinski
<jakub.kicinski@netronome.com>:
>
> Hi!
>

Thanks for spending your time on this, Jakub. I'm (temporarily) back
for a week, so you can expect faster replies now...

> This set tries to make the core take care of error checking for the
> drivers.  In particular making sure that the AF_XDP UMEM is not installed
> on queues which don't exist (or are disabled) and that changing queue
> (AKA ethtool channel) count cannot disable queues with active AF_XDF
> zero-copy sockets.
>
> I'm sending as an RFC because I'm not entirely sure what the desired
> behaviour is here.  Is it Okay to install AF_XDP on queues which don't
> exist?  I presume not?

Your presumption is correct. The idea with the
real_num_rx_queues/real_num_tx_queues check in xsk_bind, is to bail
out if the queue doesn't exist at bind call. Note that we *didn't* add
any code to avoid the bound queue from being removed via set channel
(your patch 6). Our idea was that if you remove a queue, the ingress
frames would simply stop flowing, and the queue config change checking
was "out-of-band".

I think I prefer your approach, i.e. not allowing the channels/queues
to change if they're bound to an AF_XDP socket. However, your
xdp_umem_query used in ethtool only works for ZC enabled drivers, not
for the existing non-ZC/copy case. If we'd like to go the route of
disabling ethtool_set_channels for an AF_XDP enabled queue this
functionality needs to move the query into netdev core, so we have a
consistent behavior.

> Are the AF_XDP queue_ids referring to TX queues
> as well as RX queues in case of the driver?  I presume not?

We've had a lot of discussions about this internally. Ideally, we'd
like to give driver implementors the most freedom, and not enforcing a
certain queue scheme for Tx. OTOH it makes it weird for the userland
application *not* to have the same id, e.g. if a userland application
would like to get stats or configure the AF_XDP bound Tx queue --
which id is it? Should the Tx queue id  for an xsk be exposed in
sysfs? If the id is *not* the same, would it be OK to change the
number of channels and Tx would continue to operate correctly? A
related question; An xsk with *only* Tx, should it be constrained by
the number of (enabled) Rx queues?

I'd be happy to hear some more opinions/thoughts on this...

> Should
> we try to prevent disabling queues which have non zero-copy sockets
> installed as well? :S
>

Yes, the ZC/non-ZC case must be consistent IMO. See comment above.

> Anyway, if any of those patches seem useful and reasonable, please let
> me know I will repost as non-RFC.
>

I definitely think patch 2 and 3 (and probably 1) should go as non-RFC!

Thanks for spotting that we're not holding the rtnl lock when checking
the # queues (patch 4)!


Björn

> Jakub Kicinski (6):
>   net: update real_num_rx_queues even when !CONFIG_SYSFS
>   xsk: refactor xdp_umem_assign_dev()
>   xsk: don't allow umem replace at stack level
>   xsk: don't allow installing UMEM beyond the number of queues
>   ethtool: rename local variable max -> curr
>   ethtool: don't allow disabling queues with umem installed
>
>  include/linux/netdevice.h | 16 +++++++--
>  net/core/ethtool.c        | 19 ++++++----
>  net/xdp/xdp_umem.c        | 73 ++++++++++++++++++++++++---------------
>  3 files changed, 71 insertions(+), 37 deletions(-)
>
> --
> 2.17.1
>

^ permalink raw reply

* Re: [PATCH net-next v5 4/4] act_mirred: use TC_ACT_REINSERT when possible
From: Jiri Pirko @ 2018-07-30 12:42 UTC (permalink / raw)
  To: Paolo Abeni
  Cc: netdev, Jamal Hadi Salim, Cong Wang, Daniel Borkmann,
	Marcelo Ricardo Leitner, Eyal Birger, David S. Miller
In-Reply-To: <bc7518079d9c7f572184eca0cd2d1fc88c731a7f.1532934532.git.pabeni@redhat.com>

Mon, Jul 30, 2018 at 02:30:45PM CEST, pabeni@redhat.com wrote:
>When mirred is invoked from the ingress path, and it wants to redirect
>the processed packet, it can now use the TC_ACT_REINSERT action,
>filling the tcf_result accordingly, and avoiding a per packet
>skb_clone().
>
>Overall this gives a ~10% improvement in forwarding performance for the
>TC S/W data path and TC S/W performances are now comparable to the
>kernel openvswitch datapath.
>
>v1 -> v2: use ACT_MIRRED instead of ACT_REDIRECT
>v2 -> v3: updated after action rename, fixed typo into the commit
>	message
>v3 -> v4: updated again after action rename, added more comments to
>	the code (JiriP), skip the optimization if the control action
>	need to touch the tcf_result (Paolo)
>v4 -> v5: fix sparse warning (kbuild bot)
>
>Signed-off-by: Paolo Abeni <pabeni@redhat.com>

Acked-by: Jiri Pirko <jiri@mellanox.com>

^ permalink raw reply

* KASAN: slab-out-of-bounds Read in sock_hash_ctx_update_elem
From: syzbot @ 2018-07-30 14:19 UTC (permalink / raw)
  To: ast, daniel, linux-kernel, netdev, syzkaller-bugs

Hello,

syzbot found the following crash on:

HEAD commit:    a26fb01c2879 Merge tag 'random_for_linus_stable' of git://..
git tree:       upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=10200bb2400000
kernel config:  https://syzkaller.appspot.com/x/.config?x=ffb4428fdc82f93b
dashboard link: https://syzkaller.appspot.com/bug?extid=4207b2e0c72d65cc775d
compiler:       gcc (GCC) 8.0.1 20180413 (experimental)
syzkaller repro:https://syzkaller.appspot.com/x/repro.syz?x=1545ed62400000
C reproducer:   https://syzkaller.appspot.com/x/repro.c?x=10307368400000

IMPORTANT: if you fix the bug, please add the following tag to the commit:
Reported-by: syzbot+4207b2e0c72d65cc775d@syzkaller.appspotmail.com

random: sshd: uninitialized urandom read (32 bytes read)
random: sshd: uninitialized urandom read (32 bytes read)
random: sshd: uninitialized urandom read (32 bytes read)
nf_conntrack: default automatic helper assignment has been turned off for  
security reasons and CT-based  firewall rule not found. Use the iptables CT  
target to attach helpers instead.
==================================================================
BUG: KASAN: slab-out-of-bounds in __lock_acquire+0x3829/0x5020  
kernel/locking/lockdep.c:3314
Read of size 8 at addr ffff8801ad925e08 by task syz-executor884/4438

CPU: 0 PID: 4438 Comm: syz-executor884 Not tainted 4.18.0-rc6+ #167
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS  
Google 01/01/2011
Call Trace:
  __dump_stack lib/dump_stack.c:77 [inline]
  dump_stack+0x1c9/0x2b4 lib/dump_stack.c:113
  print_address_description+0x6c/0x20b mm/kasan/report.c:256
  kasan_report_error mm/kasan/report.c:354 [inline]
  kasan_report.cold.7+0x242/0x2fe mm/kasan/report.c:412
  __asan_report_load8_noabort+0x14/0x20 mm/kasan/report.c:433
  __lock_acquire+0x3829/0x5020 kernel/locking/lockdep.c:3314
  lock_acquire+0x1e4/0x540 kernel/locking/lockdep.c:3924
  __raw_spin_lock_bh include/linux/spinlock_api_smp.h:135 [inline]
  _raw_spin_lock_bh+0x31/0x40 kernel/locking/spinlock.c:168
  spin_lock_bh include/linux/spinlock.h:315 [inline]
  sock_hash_ctx_update_elem.isra.26+0xbef/0x14d0 kernel/bpf/sockmap.c:2381
  sock_hash_update_elem+0x1e2/0x510 kernel/bpf/sockmap.c:2428
  map_update_elem+0x72d/0xcb0 kernel/bpf/syscall.c:741
  __do_sys_bpf kernel/bpf/syscall.c:2298 [inline]
  __se_sys_bpf kernel/bpf/syscall.c:2269 [inline]
  __x64_sys_bpf+0x32d/0x510 kernel/bpf/syscall.c:2269
  do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290
  entry_SYSCALL_64_after_hwframe+0x49/0xbe
RIP: 0033:0x440449
Code: 18 89 d0 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 48 89 f8 48 89 f7  
48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff  
ff 0f 83 fb 13 fc ff c3 66 2e 0f 1f 84 00 00 00 00
RSP: 002b:00007ffd721a7e58 EFLAGS: 00000203 ORIG_RAX: 0000000000000141
RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 0000000000440449
RDX: 0000000000000020 RSI: 0000000020000180 RDI: 0000000000000002
RBP: 00000000006ca018 R08: 00000000004002c8 R09: 00000000004002c8
R10: 00000000004002c8 R11: 0000000000000203 R12: 0000000000401cd0
R13: 0000000000401d60 R14: 0000000000000000 R15: 0000000000000000

Allocated by task 4438:
  save_stack+0x43/0xd0 mm/kasan/kasan.c:448
  set_track mm/kasan/kasan.c:460 [inline]
  kasan_kmalloc+0xc4/0xe0 mm/kasan/kasan.c:553
  kasan_slab_alloc+0x12/0x20 mm/kasan/kasan.c:490
  kmem_cache_alloc+0x12e/0x760 mm/slab.c:3554
  kmem_cache_zalloc include/linux/slab.h:697 [inline]
  kcm_attach net/kcm/kcmsock.c:1405 [inline]
  kcm_attach_ioctl net/kcm/kcmsock.c:1490 [inline]
  kcm_ioctl+0xd10/0x1930 net/kcm/kcmsock.c:1696
  sock_do_ioctl+0xe4/0x3e0 net/socket.c:969
  sock_ioctl+0x30d/0x680 net/socket.c:1093
  vfs_ioctl fs/ioctl.c:46 [inline]
  file_ioctl fs/ioctl.c:500 [inline]
  do_vfs_ioctl+0x1de/0x1720 fs/ioctl.c:684
  ksys_ioctl+0xa9/0xd0 fs/ioctl.c:701
  __do_sys_ioctl fs/ioctl.c:708 [inline]
  __se_sys_ioctl fs/ioctl.c:706 [inline]
  __x64_sys_ioctl+0x73/0xb0 fs/ioctl.c:706
  do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290
  entry_SYSCALL_64_after_hwframe+0x49/0xbe

Freed by task 0:
(stack is not available)

The buggy address belongs to the object at ffff8801ad925bc0
  which belongs to the cache kcm_psock_cache of size 544
The buggy address is located 40 bytes to the right of
  544-byte region [ffff8801ad925bc0, ffff8801ad925de0)
The buggy address belongs to the page:
page:ffffea0006b64900 count:1 mapcount:0 mapping:ffff8801cde561c0 index:0x0  
compound_mapcount: 0
flags: 0x2fffc0000008100(slab|head)
raw: 02fffc0000008100 ffff8801cdf31448 ffff8801cdf31448 ffff8801cde561c0
raw: 0000000000000000 ffff8801ad924040 000000010000000b 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
  ffff8801ad925d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  ffff8801ad925d80: 00 00 00 00 00 00 00 00 00 00 00 00 fc fc fc fc
> ffff8801ad925e00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
                       ^
  ffff8801ad925e80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
  ffff8801ad925f00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================


---
This bug is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

syzbot will keep track of this bug report. See:
https://goo.gl/tpsmEJ#bug-status-tracking for how to communicate with  
syzbot.
syzbot can test patches for this bug, for details see:
https://goo.gl/tpsmEJ#testing-patches

^ permalink raw reply

* Re: [PATCH net-next v5 3/4] net/tc: introduce TC_ACT_REINSERT.
From: Jiri Pirko @ 2018-07-30 12:40 UTC (permalink / raw)
  To: Paolo Abeni
  Cc: netdev, Jamal Hadi Salim, Cong Wang, Daniel Borkmann,
	Marcelo Ricardo Leitner, Eyal Birger, David S. Miller
In-Reply-To: <695eaa79e2c02c64f0daacd38c35c63bbdfee60f.1532934532.git.pabeni@redhat.com>

Mon, Jul 30, 2018 at 02:30:44PM CEST, pabeni@redhat.com wrote:
>This is similar TC_ACT_REDIRECT, but with a slightly different
>semantic:
>- on ingress the mirred skbs are passed to the target device
>network stack without any additional check not scrubbing.
>- the rcu-protected stats provided via the tcf_result struct
>  are updated on error conditions.
>
>This new tcfa_action value is not exposed to the user-space
>and can be used only internally by clsact.
>
>v1 -> v2: do not touch TC_ACT_REDIRECT code path, introduce
> a new action type instead
>v2 -> v3:
> - rename the new action value TC_ACT_REINJECT, update the
>   helper accordingly
> - take care of uncloned reinjected packets in XDP generic
>   hook
>v3 -> v4:
> - renamed again the new action value (JiriP)
>v4 -> v5:
> - fix build error with !NET_CLS_ACT (kbuild bot)

Oh, another nitpick: The changelog should go under "---" line. That way,
the maintainer does not have to deal with it during apply (git apply
will cut it out).

>
>Signed-off-by: Paolo Abeni <pabeni@redhat.com>

Acked-by: Jiri Pirko <jiri@mellanox.com>

^ permalink raw reply

* Re: [PATCH net-next v5 1/4] net/sched: user-space can't set unknown tcfa_action values
From: Jiri Pirko @ 2018-07-30 12:36 UTC (permalink / raw)
  To: Paolo Abeni
  Cc: netdev, Jamal Hadi Salim, Cong Wang, Daniel Borkmann,
	Marcelo Ricardo Leitner, Eyal Birger, David S. Miller
In-Reply-To: <951ad078ad4d5ee108abcd85189460aed7948634.1532934532.git.pabeni@redhat.com>

Mon, Jul 30, 2018 at 02:30:42PM CEST, pabeni@redhat.com wrote:
>Currently, when initializing an action, the user-space can specify
>and use arbitrary values for the tcfa_action field. If the value
>is unknown by the kernel, is implicitly threaded as TC_ACT_UNSPEC.
>
>This change explicitly checks for unknown values at action creation
>time, and explicitly convert them to TC_ACT_UNSPEC. No functional
>changes are introduced, but this will allow introducing tcfa_action
>values not exposed to user-space in a later patch.
>
>Note: we can't use the above to hide TC_ACT_REDIRECT from user-space,
>as the latter is already part of uAPI.
>
>v3 -> v4:
> - use an helper to check for action validity (JiriP)
> - emit an extack for invalid actions (JiriP)
>v4 -> v5:
> - keep messages on a single line, drop net_warn (Marcelo)

Little nitpick: The changelog should be in the reverse order.

>
>Signed-off-by: Paolo Abeni <pabeni@redhat.com>

Acked-by: Jiri Pirko <jiri@mellanox.com>

^ permalink raw reply

* Re: [PATCH net-next] net: phy: mscc: the extended page access register is 16 bits
From: Alexandre Belloni @ 2018-07-30 14:13 UTC (permalink / raw)
  To: Quentin Schulz
  Cc: andrew, f.fainelli, davem, netdev, linux-kernel, thomas.petazzoni
In-Reply-To: <20180730125313.3405-1-quentin.schulz@bootlin.com>

On 30/07/2018 14:53:13+0200, Quentin Schulz wrote:
> The Extended Page Access is a 16-bit register, so change the page
> parameter of vsc85xx_phy_page_set to a u16.
> 
> Signed-off-by: Quentin Schulz <quentin.schulz@bootlin.com>

Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>

> ---
>  drivers/net/phy/mscc.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
> index 650c2667d523..84ca9ff40ae0 100644
> --- a/drivers/net/phy/mscc.c
> +++ b/drivers/net/phy/mscc.c
> @@ -123,7 +123,7 @@ static const struct vsc8531_edge_rate_table edge_table[] = {
>  };
>  #endif /* CONFIG_OF_MDIO */
>  
> -static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page)
> +static int vsc85xx_phy_page_set(struct phy_device *phydev, u16 page)
>  {
>  	int rc;
>  
> -- 
> 2.17.1
> 

-- 
Alexandre Belloni, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox