From: Eyal Perry <eya...@mellanox.com> This ethtool patch adds support to set and get the current RSS hash function for the device through through the new hfunc field in the ethtool_rxfh struct. Kernel supported hash function names are queried with ETHTOOL_GSTRINGS (value 0 is reserved and skipped).
Although currently no device supports a combination of hash functions/attributes, this ethtool implementation will support it. Both in the set and in the get. The device driver declares the functions and/or attributes that it supports, and ethtool will show it correctly and enable the user to set those combinations. If a combination is not supported - the device driver will fail the operation and ethtool will print an error message. Signed-off-by: Eyal Perry <eya...@mellanox.com> Signed-off-by: Amir Vadai <am...@mellanox.com> --- Changes from V1: - Fixed some English mistakes - Fixed the complicated way to write '= req_hfunc;'... - Better support in combination of hash functions/attributes ethtool.8.in | 7 ++++++ ethtool.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/ethtool.8.in b/ethtool.8.in index ae56293..0f43b9b 100644 --- a/ethtool.8.in +++ b/ethtool.8.in @@ -297,6 +297,8 @@ ethtool \- query or control network driver and hardware settings .BI weight\ W0 .IR W1 .RB ...\ ] +.RB [ hfunc +.IR FUNC[,FUNC...] ] .HP .B ethtool \-f|\-\-flash .I devname file @@ -796,6 +798,11 @@ 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 +List of RSS hash functions/attributes of the specified network device. A list +of RSS hash functions and attributes which the device 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 01b13a6..bdf61f7 100644 --- a/ethtool.c +++ b/ethtool.c @@ -3167,6 +3167,7 @@ static int do_grxfh(struct cmd_context *ctx) { struct ethtool_rxfh rss_head = {0}; struct ethtool_rxnfc ring_count; + struct ethtool_gstrings *hfuncs; struct ethtool_rxfh *rss; u32 i, indir_bytes; char *hkey; @@ -3222,6 +3223,23 @@ static int do_grxfh(struct cmd_context *ctx) printf("%02x:", (u8) hkey[i]); } + printf("Supported RSS hash functions: "); + if (!rss->hfunc) { + printf(" Operation not supported\n"); + goto out; + } + + hfuncs = get_stringset(ctx, ETH_SS_RSS_HASH_FUNCS, 0, 1); + for (i = 0; i < hfuncs->len; i++) + printf("%s ", (char *)hfuncs->data + i * ETH_GSTRING_LEN); + printf("\n"); + + printf("Selected RSS hash function: "); + for (i = 0; i < hfuncs->len; i++) + if (rss->hfunc & (1 << i)) + printf("%s ", (char *)hfuncs->data + i * ETH_GSTRING_LEN); + printf("\n"); +out: free(rss); return 0; } @@ -3316,6 +3334,40 @@ static int do_srxfhindir(struct cmd_context *ctx, int rxfhindir_equal, return 0; } + +static int get_hfunc(struct cmd_context *ctx, char *req_hfunc_names) +{ + struct ethtool_gstrings *hfuncs; + char *req_hfunc_name; + char *saveptr; + int i; + int ret = 0; + + hfuncs = get_stringset(ctx, ETH_SS_RSS_HASH_FUNCS, 0, 1); + + for (; ; req_hfunc_names = NULL) { + req_hfunc_name = strtok_r(req_hfunc_names, ",", &saveptr); + if (req_hfunc_name == NULL) + break; + + for (i = 0; i < hfuncs->len; i++) { + char *hfunc_name = (char *)(hfuncs->data + i * + ETH_GSTRING_LEN); + if (!strncmp(hfunc_name, req_hfunc_name, ETH_GSTRING_LEN)) { + ret |= 1 << i; + break; + } + } + + if (i == hfuncs->len) + fprintf(stderr, "Unknown hash function: %s\n", + req_hfunc_name); + } + + + return ret; +} + static int do_srxfh(struct cmd_context *ctx) { struct ethtool_rxfh rss_head = {0}; @@ -3324,9 +3376,11 @@ static int do_srxfh(struct cmd_context *ctx) int rxfhindir_equal = 0; char **rxfhindir_weight = NULL; char *rxfhindir_key = NULL; + char *req_hfunc_name = NULL; char *hkey = NULL; int err = 0; u32 arg_num = 0, indir_bytes = 0; + int req_hfunc = 0; u32 entry_size = sizeof(rss_head.rss_config[0]); u32 num_weights = 0; @@ -3355,6 +3409,12 @@ static int do_srxfh(struct cmd_context *ctx) if (!rxfhindir_key) exit_bad_args(); ++arg_num; + } 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(); } @@ -3375,7 +3435,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_equal, rxfhindir_weight, num_weights); } else if (err < 0) { @@ -3393,6 +3454,12 @@ 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) { + req_hfunc = get_hfunc(ctx, req_hfunc_name); + if (!req_hfunc) + return 1; + } + rss = calloc(1, sizeof(*rss) + indir_bytes + rss_head.key_size); if (!rss) { perror("Cannot allocate memory for RX flow hash config"); @@ -3401,6 +3468,7 @@ static int do_srxfh(struct cmd_context *ctx) 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_equal, rxfhindir_weight, num_weights)) { @@ -4110,7 +4178,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" }, -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html