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