When using more than one RSS table, specifying a starting queue for flow 
distibution
makes it easier to specify the set of queues attached to the table.  An example:

  ethtool -X eth0 context 0 equal 14                    # queues  0 .. 13
  ethtool -X eth0 context 1 start 14 equal 42           # queues 14 .. 56
  ethtool -N eth0 flow-type udp6 dst-port 4242 context 1

Here, context 0 might be handling normal kernel traffic, while context 1 handles
AF_XDP traffic.

Signed-off-by: Jonathan Lemon <jonathan.le...@gmail.com>
---
 ethtool.8.in   |  6 ++++++
 ethtool.c      | 46 +++++++++++++++++++++++++++++++++-------------
 test-cmdline.c |  4 ++++
 3 files changed, 43 insertions(+), 13 deletions(-)

diff --git a/ethtool.8.in b/ethtool.8.in
index b878521..e9f2421 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -297,6 +297,8 @@ ethtool \- query or control network driver and hardware 
settings
 .B ethtool \-X|\-\-set\-rxfh\-indir|\-\-rxfh
 .I devname
 .RB [ hkey \ \*(MA:\...]
+.RB [ start
+.IR N ]
 .RB [\  equal
 .IR N \ |
 .BI weight\  W0
@@ -953,6 +955,10 @@ even if a nibble is zero.
 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 start\  N
+For the \fBequal\fR and \fBweight\fR options, sets the starting receive queue
+for spreading flows to \fIN\fR.
+.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 59131e8..282e103 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -3902,13 +3902,14 @@ out:
 }
 
 static int fill_indir_table(u32 *indir_size, u32 *indir, int rxfhindir_default,
-                           int rxfhindir_equal, char **rxfhindir_weight,
-                           u32 num_weights)
+                           int rxfhindir_start, int rxfhindir_equal,
+                           char **rxfhindir_weight, u32 num_weights)
 {
        u32 i;
+
        if (rxfhindir_equal) {
                for (i = 0; i < *indir_size; i++)
-                       indir[i] = i % rxfhindir_equal;
+                       indir[i] = rxfhindir_start + (i % rxfhindir_equal);
        } else if (rxfhindir_weight) {
                u32 j, weight, sum = 0, partial = 0;
 
@@ -3937,7 +3938,7 @@ static int fill_indir_table(u32 *indir_size, u32 *indir, 
int rxfhindir_default,
                                weight = get_u32(rxfhindir_weight[j], 0);
                                partial += weight;
                        }
-                       indir[i] = j;
+                       indir[i] = rxfhindir_start + j;
                }
        } else if (rxfhindir_default) {
                /* "*indir_size == 0" ==> reset indir to default */
@@ -3950,8 +3951,8 @@ static int fill_indir_table(u32 *indir_size, u32 *indir, 
int rxfhindir_default,
 }
 
 static int do_srxfhindir(struct cmd_context *ctx, int rxfhindir_default,
-                        int rxfhindir_equal, char **rxfhindir_weight,
-                        u32 num_weights)
+                        int rxfhindir_start, int rxfhindir_equal,
+                        char **rxfhindir_weight, u32 num_weights)
 {
        struct ethtool_rxfh_indir indir_head;
        struct ethtool_rxfh_indir *indir;
@@ -3977,8 +3978,8 @@ static int do_srxfhindir(struct cmd_context *ctx, int 
rxfhindir_default,
        indir->size = indir_head.size;
 
        if (fill_indir_table(&indir->size, indir->ring_index,
-                            rxfhindir_default, rxfhindir_equal,
-                            rxfhindir_weight, num_weights)) {
+                            rxfhindir_default, rxfhindir_start,
+                            rxfhindir_equal, rxfhindir_weight, num_weights)) {
                free(indir);
                return 1;
        }
@@ -3999,7 +4000,7 @@ static int do_srxfh(struct cmd_context *ctx)
        struct ethtool_rxfh rss_head = {0};
        struct ethtool_rxfh *rss = NULL;
        struct ethtool_rxnfc ring_count;
-       int rxfhindir_equal = 0, rxfhindir_default = 0;
+       int rxfhindir_equal = 0, rxfhindir_default = 0, rxfhindir_start = 0;
        struct ethtool_gstrings *hfuncs = NULL;
        char **rxfhindir_weight = NULL;
        char *rxfhindir_key = NULL;
@@ -4024,6 +4025,11 @@ static int do_srxfh(struct cmd_context *ctx)
                        rxfhindir_equal = get_int_range(ctx->argp[arg_num],
                                                        0, 1, INT_MAX);
                        ++arg_num;
+               } else if (!strcmp(ctx->argp[arg_num], "start")) {
+                       ++arg_num;
+                       rxfhindir_start = get_int_range(ctx->argp[arg_num],
+                                                       0, 0, INT_MAX);
+                       ++arg_num;
                } else if (!strcmp(ctx->argp[arg_num], "weight")) {
                        ++arg_num;
                        rxfhindir_weight = ctx->argp + arg_num;
@@ -4084,6 +4090,18 @@ static int do_srxfh(struct cmd_context *ctx)
                return 1;
        }
 
+       if (rxfhindir_start && rxfhindir_default) {
+               fprintf(stderr,
+                       "Start and default options are mutually exclusive\n");
+               return 1;
+       }
+
+       if (rxfhindir_start && !(rxfhindir_equal || rxfhindir_weight)) {
+               fprintf(stderr,
+                       "Start must be used with equal or weight options\n");
+               return 1;
+       }
+
        if (rxfhindir_default && rss_context) {
                fprintf(stderr,
                        "Default and context options are mutually exclusive\n");
@@ -4130,8 +4148,9 @@ static int do_srxfh(struct cmd_context *ctx)
        err = send_ioctl(ctx, &rss_head);
        if (err < 0 && errno == EOPNOTSUPP && !rxfhindir_key &&
            !req_hfunc_name && !rss_context) {
-               return do_srxfhindir(ctx, rxfhindir_default, rxfhindir_equal,
-                                    rxfhindir_weight, num_weights);
+               return do_srxfhindir(ctx, rxfhindir_default, rxfhindir_start,
+                                    rxfhindir_equal, rxfhindir_weight,
+                                    num_weights);
        } else if (err < 0) {
                perror("Cannot get RX flow hash indir size and key size");
                return 1;
@@ -4186,8 +4205,9 @@ static int do_srxfh(struct cmd_context *ctx)
                rss->indir_size = rss_head.indir_size;
                rss->key_size = rss_head.key_size;
                if (fill_indir_table(&rss->indir_size, rss->rss_config,
-                                    rxfhindir_default, rxfhindir_equal,
-                                    rxfhindir_weight, num_weights)) {
+                                    rxfhindir_default, rxfhindir_start,
+                                    rxfhindir_equal, rxfhindir_weight,
+                                    num_weights)) {
                        err = 1;
                        goto free;
                }
diff --git a/test-cmdline.c b/test-cmdline.c
index 84630a5..b76e2c3 100644
--- a/test-cmdline.c
+++ b/test-cmdline.c
@@ -194,7 +194,11 @@ static struct test_case {
        { 1, "-X devname equal 0" },
        { 1, "--set-rxfh-indir devname equal foo" },
        { 1, "-X devname equal" },
+       { 1, "-X devname start" },
+       { 1, "-X devname start 3" },
+       { 0, "-X devname start 4 equal 2" },
        { 0, "--set-rxfh-indir devname weight 1 2 3 4" },
+       { 0, "--set-rxfh-indir devname start 4 weight 1 2 3 4" },
        { 0, "--rxfh devname hkey 
48:15:6e:bb:d8:bd:6f:b1:a4:c6:7a:c4:76:1c:29:98:da:e1:ae:6c:2e:12:2f:c0:b9:be:61:3d:00:54:35:9e:09:05:c7:d7:93:72:4a:ee"
 },
        { 0, "-X devname hkey 
48:15:6e:bb:d8:bd:6f:b1:a4:c6:7a:c4:76:1c:29:98:da:e1:ae:6c:2e:12:2f:c0:b9:be:61:3d:00:54:35:9e:09:05:c7:d7:93:72:4a:ee"
 },
 #if 0
-- 
2.21.0.196.g041f5ea1cf

Reply via email to