3397d6
From e89f3c656ff17741aa3ea33c57bc177afedc999b Mon Sep 17 00:00:00 2001
3397d6
From: Gal Pressman <galp@mellanox.com>
3397d6
Date: Wed, 8 Mar 2017 16:03:51 +0200
3397d6
Subject: [PATCH 5/7] ethtool: Support for configurable RSS hash function
3397d6
3397d6
This ethtool patch adds support to set and get the current RSS hash
3397d6
function for the device through the new hfunc mask field in the
3397d6
ethtool_rxfh struct. Kernel supported hash function names are queried
3397d6
with ETHTOOL_GSTRINGS - each string is corresponding with a bit in hfunc
3397d6
mask according to its index in the string-set.
3397d6
3397d6
(This corrects the mistaken revert from commit 126464e4da182064. -- JWL)
3397d6
3397d6
Signed-off-by: Eyal Perry <eyalpe@mellanox.com>
3397d6
Signed-off-by: Gal Pressman <galp@mellanox.com>
3397d6
Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
3397d6
Signed-off-by: John W. Linville <linville@tuxdriver.com>
3397d6
(cherry picked from commit b888f358763a20625a381e071ea50524a520c7c1)
3397d6
---
3397d6
 ethtool.8.in |  6 ++++++
3397d6
 ethtool.c    | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
3397d6
 2 files changed, 69 insertions(+), 3 deletions(-)
3397d6
3397d6
diff --git a/ethtool.8.in b/ethtool.8.in
3397d6
index 9631847..b69c5c6 100644
3397d6
--- a/ethtool.8.in
3397d6
+++ b/ethtool.8.in
3397d6
@@ -301,6 +301,8 @@ ethtool \- query or control network driver and hardware settings
3397d6
 .BI weight\  W0
3397d6
 .IR W1
3397d6
 .RB ...\ | \ default \ ]
3397d6
+.RB [ hfunc
3397d6
+.IR FUNC ]
3397d6
 .HP
3397d6
 .B ethtool \-f|\-\-flash
3397d6
 .I devname file
3397d6
@@ -853,6 +855,10 @@ Sets RSS hash key of the specified network device. RSS hash key should be of dev
3397d6
 Hash key format must be in xx:yy:zz:aa:bb:cc format meaning both the nibbles of a byte should be mentioned
3397d6
 even if a nibble is zero.
3397d6
 .TP
3397d6
+.BI hfunc
3397d6
+Sets RSS hash function of the specified network device.
3397d6
+List of RSS hash functions which kernel supports is shown as a part of the --show-rxfh command output.
3397d6
+.TP
3397d6
 .BI equal\  N
3397d6
 Sets the receive flow hash indirection table to spread flows evenly
3397d6
 between the first \fIN\fR receive queues.
3397d6
diff --git a/ethtool.c b/ethtool.c
3397d6
index ce48639..8eba6e6 100644
3397d6
--- a/ethtool.c
3397d6
+++ b/ethtool.c
3397d6
@@ -3640,6 +3640,7 @@ static int do_grxfhindir(struct cmd_context *ctx,
3397d6
 
3397d6
 static int do_grxfh(struct cmd_context *ctx)
3397d6
 {
3397d6
+	struct ethtool_gstrings *hfuncs = NULL;
3397d6
 	struct ethtool_rxfh rss_head = {0};
3397d6
 	struct ethtool_rxnfc ring_count;
3397d6
 	struct ethtool_rxfh *rss;
3397d6
@@ -3697,6 +3698,26 @@ static int do_grxfh(struct cmd_context *ctx)
3397d6
 			printf("%02x:", (u8) hkey[i]);
3397d6
 	}
3397d6
 
3397d6
+	printf("RSS hash function:\n");
3397d6
+	if (!rss->hfunc) {
3397d6
+		printf("    Operation not supported\n");
3397d6
+		goto out;
3397d6
+	}
3397d6
+
3397d6
+	hfuncs = get_stringset(ctx, ETH_SS_RSS_HASH_FUNCS, 0, 1);
3397d6
+	if (!hfuncs) {
3397d6
+		perror("Cannot get hash functions names");
3397d6
+		free(rss);
3397d6
+		return 1;
3397d6
+	}
3397d6
+
3397d6
+	for (i = 0; i < hfuncs->len; i++)
3397d6
+		printf("    %s: %s\n",
3397d6
+		       (const char *)hfuncs->data + i * ETH_GSTRING_LEN,
3397d6
+		       (rss->hfunc & (1 << i)) ? "on" : "off");
3397d6
+
3397d6
+out:
3397d6
+	free(hfuncs);
3397d6
 	free(rss);
3397d6
 	return 0;
3397d6
 }
3397d6
@@ -3800,11 +3821,16 @@ static int do_srxfh(struct cmd_context *ctx)
3397d6
 	struct ethtool_rxfh *rss;
3397d6
 	struct ethtool_rxnfc ring_count;
3397d6
 	int rxfhindir_equal = 0, rxfhindir_default = 0;
3397d6
+	struct ethtool_gstrings *hfuncs = NULL;
3397d6
 	char **rxfhindir_weight = NULL;
3397d6
 	char *rxfhindir_key = NULL;
3397d6
+	char *req_hfunc_name = NULL;
3397d6
+	char *hfunc_name = NULL;
3397d6
 	char *hkey = NULL;
3397d6
 	int err = 0;
3397d6
+	int i;
3397d6
 	u32 arg_num = 0, indir_bytes = 0;
3397d6
+	u32 req_hfunc = 0;
3397d6
 	u32 entry_size = sizeof(rss_head.rss_config[0]);
3397d6
 	u32 num_weights = 0;
3397d6
 
3397d6
@@ -3836,6 +3862,12 @@ static int do_srxfh(struct cmd_context *ctx)
3397d6
 		} else if (!strcmp(ctx->argp[arg_num], "default")) {
3397d6
 			++arg_num;
3397d6
 			rxfhindir_default = 1;
3397d6
+		} else if (!strcmp(ctx->argp[arg_num], "hfunc")) {
3397d6
+			++arg_num;
3397d6
+			req_hfunc_name = ctx->argp[arg_num];
3397d6
+			if (!req_hfunc_name)
3397d6
+				exit_bad_args();
3397d6
+			++arg_num;
3397d6
 		} else {
3397d6
 			exit_bad_args();
3397d6
 		}
3397d6
@@ -3868,7 +3900,8 @@ static int do_srxfh(struct cmd_context *ctx)
3397d6
 
3397d6
 	rss_head.cmd = ETHTOOL_GRSSH;
3397d6
 	err = send_ioctl(ctx, &rss_head);
3397d6
-	if (err < 0 && errno == EOPNOTSUPP && !rxfhindir_key) {
3397d6
+	if (err < 0 && errno == EOPNOTSUPP && !rxfhindir_key &&
3397d6
+	    !req_hfunc_name) {
3397d6
 		return do_srxfhindir(ctx, rxfhindir_default, rxfhindir_equal,
3397d6
 				     rxfhindir_weight, num_weights);
3397d6
 	} else if (err < 0) {
3397d6
@@ -3886,14 +3919,39 @@ static int do_srxfh(struct cmd_context *ctx)
3397d6
 	if (rxfhindir_equal || rxfhindir_weight)
3397d6
 		indir_bytes = rss_head.indir_size * entry_size;
3397d6
 
3397d6
+	if (rss_head.hfunc && req_hfunc_name) {
3397d6
+		hfuncs = get_stringset(ctx, ETH_SS_RSS_HASH_FUNCS, 0, 1);
3397d6
+		if (!hfuncs) {
3397d6
+			perror("Cannot get hash functions names");
3397d6
+			return 1;
3397d6
+		}
3397d6
+
3397d6
+		for (i = 0; i < hfuncs->len && !req_hfunc ; i++) {
3397d6
+			hfunc_name = (char *)(hfuncs->data +
3397d6
+					      i * ETH_GSTRING_LEN);
3397d6
+			if (!strncmp(hfunc_name, req_hfunc_name,
3397d6
+				     ETH_GSTRING_LEN))
3397d6
+				req_hfunc = (u32)1 << i;
3397d6
+		}
3397d6
+
3397d6
+		if (!req_hfunc) {
3397d6
+			fprintf(stderr,
3397d6
+				"Unknown hash function: %s\n", req_hfunc_name);
3397d6
+			free(hfuncs);
3397d6
+			return 1;
3397d6
+		}
3397d6
+	}
3397d6
+
3397d6
 	rss = calloc(1, sizeof(*rss) + indir_bytes + rss_head.key_size);
3397d6
 	if (!rss) {
3397d6
 		perror("Cannot allocate memory for RX flow hash config");
3397d6
-		return 1;
3397d6
+		err = 1;
3397d6
+		goto free;
3397d6
 	}
3397d6
 	rss->cmd = ETHTOOL_SRSSH;
3397d6
 	rss->indir_size = rss_head.indir_size;
3397d6
 	rss->key_size = rss_head.key_size;
3397d6
+	rss->hfunc = req_hfunc;
3397d6
 
3397d6
 	if (fill_indir_table(&rss->indir_size, rss->rss_config, rxfhindir_default,
3397d6
 			     rxfhindir_equal, rxfhindir_weight, num_weights)) {
3397d6
@@ -3918,6 +3976,7 @@ free:
3397d6
 		free(hkey);
3397d6
 
3397d6
 	free(rss);
3397d6
+	free(hfuncs);
3397d6
 	return err;
3397d6
 }
3397d6
 
3397d6
@@ -4650,7 +4709,8 @@ static const struct option {
3397d6
 	{ "-X|--set-rxfh-indir|--rxfh", 1, do_srxfh,
3397d6
 	  "Set Rx flow hash indirection table and/or RSS hash key",
3397d6
 	  "		[ equal N | weight W0 W1 ... | default ]\n"
3397d6
-	  "		[ hkey %x:%x:%x:%x:%x:.... ]\n" },
3397d6
+	  "		[ hkey %x:%x:%x:%x:%x:.... ]\n"
3397d6
+	  "		[ hfunc FUNC ]\n" },
3397d6
 	{ "-f|--flash", 1, do_flash,
3397d6
 	  "Flash firmware image from the specified file to a region on the device",
3397d6
 	  "               FILENAME [ REGION-NUMBER-TO-FLASH ]\n" },
3397d6
-- 
3397d6
1.8.3.1
3397d6