All of lore.kernel.org
 help / color / mirror / Atom feed
From: Edward Cree <ecree@solarflare.com>
To: "John W. Linville" <linville@tuxdriver.com>
Cc: <netdev@vger.kernel.org>
Subject: [PATCH ethtool 2/3] ethtool: add support for extra RSS contexts and RSS steering filters
Date: Fri, 9 Mar 2018 15:04:12 +0000	[thread overview]
Message-ID: <219f1d93-46b9-ba70-266e-21ea34887034@solarflare.com> (raw)
In-Reply-To: <c061eab4-6069-017c-554f-210feb170520@solarflare.com>

RSS contexts can be created on a device with -X ... context new, modified
 with -X ... context N, and deleted with -X ... context N delete.
N-tuple filters can be directed at those contexts with -N ... context N.

Signed-off-by: Edward Cree <ecree@solarflare.com>
---
 ethtool.c  | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------
 internal.h |   4 +-
 rxclass.c  |  58 +++++++++++++++++++++----
 3 files changed, 173 insertions(+), 30 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index c870a2b..5ea9f05 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -1506,7 +1506,7 @@ static void dump_features(const struct feature_defs *defs,
 
 static int dump_rxfhash(int fhash, u64 val)
 {
-	switch (fhash) {
+	switch (fhash & ~FLOW_RSS) {
 	case TCP_V4_FLOW:
 		fprintf(stdout, "TCP over IPV4 flows");
 		break;
@@ -3517,11 +3517,20 @@ static int do_srxclass(struct cmd_context *ctx)
 	if (ctx->argc < 2)
 		exit_bad_args();
 
-	if (ctx->argc == 3 && !strcmp(ctx->argp[0], "rx-flow-hash")) {
+	if (!strcmp(ctx->argp[0], "rx-flow-hash")) {
 		int rx_fhash_set;
 		u32 rx_fhash_val;
 		struct ethtool_rxnfc nfccmd;
+		bool flow_rss = false;
 
+		if (ctx->argc == 5) {
+			if (strcmp(ctx->argp[3], "context"))
+				exit_bad_args();
+			flow_rss = true;
+			nfccmd.rss_context = get_u32(ctx->argp[4], 0);
+		} else if (ctx->argc != 3) {
+			exit_bad_args();
+		}
 		rx_fhash_set = rxflow_str_to_type(ctx->argp[1]);
 		if (!rx_fhash_set)
 			exit_bad_args();
@@ -3531,16 +3540,19 @@ static int do_srxclass(struct cmd_context *ctx)
 		nfccmd.cmd = ETHTOOL_SRXFH;
 		nfccmd.flow_type = rx_fhash_set;
 		nfccmd.data = rx_fhash_val;
+		if (flow_rss)
+			nfccmd.flow_type |= FLOW_RSS;
 
 		err = send_ioctl(ctx, &nfccmd);
 		if (err < 0)
 			perror("Cannot change RX network flow hashing options");
 	} else if (!strcmp(ctx->argp[0], "flow-type")) {
 		struct ethtool_rx_flow_spec rx_rule_fs;
+		__u32 rss_context = 0;
 
 		ctx->argc--;
 		ctx->argp++;
-		if (rxclass_parse_ruleopts(ctx, &rx_rule_fs) < 0)
+		if (rxclass_parse_ruleopts(ctx, &rx_rule_fs, &rss_context) < 0)
 			exit_bad_args();
 
 		/* attempt to add rule via N-tuple specifier */
@@ -3549,7 +3561,7 @@ static int do_srxclass(struct cmd_context *ctx)
 			return 0;
 
 		/* attempt to add rule via network flow classifier */
-		err = rxclass_rule_ins(ctx, &rx_rule_fs);
+		err = rxclass_rule_ins(ctx, &rx_rule_fs, rss_context);
 		if (err < 0) {
 			fprintf(stderr, "Cannot insert"
 				" classification rule\n");
@@ -3578,8 +3590,18 @@ static int do_grxclass(struct cmd_context *ctx)
 	struct ethtool_rxnfc nfccmd;
 	int err;
 
-	if (ctx->argc == 2 && !strcmp(ctx->argp[0], "rx-flow-hash")) {
+	if (ctx->argc > 0 && !strcmp(ctx->argp[0], "rx-flow-hash")) {
 		int rx_fhash_get;
+		bool flow_rss = false;
+
+		if (ctx->argc == 4) {
+			if (strcmp(ctx->argp[2], "context"))
+				exit_bad_args();
+			flow_rss = true;
+			nfccmd.rss_context = get_u32(ctx->argp[3], 0);
+		} else if (ctx->argc != 2) {
+			exit_bad_args();
+		}
 
 		rx_fhash_get = rxflow_str_to_type(ctx->argp[1]);
 		if (!rx_fhash_get)
@@ -3587,11 +3609,17 @@ static int do_grxclass(struct cmd_context *ctx)
 
 		nfccmd.cmd = ETHTOOL_GRXFH;
 		nfccmd.flow_type = rx_fhash_get;
+		if (flow_rss)
+			nfccmd.flow_type |= FLOW_RSS;
 		err = send_ioctl(ctx, &nfccmd);
-		if (err < 0)
+		if (err < 0) {
 			perror("Cannot get RX network flow hashing options");
-		else
+		} else {
+			if (flow_rss)
+				fprintf(stdout, "For RSS context %u:\n",
+					nfccmd.rss_context);
 			dump_rxfhash(rx_fhash_get, nfccmd.data);
+		}
 	} else if (ctx->argc == 2 && !strcmp(ctx->argp[0], "rule")) {
 		int rx_class_rule_get =
 			get_uint_range(ctx->argp[1], 0, INT_MAX);
@@ -3683,10 +3711,23 @@ static int do_grxfh(struct cmd_context *ctx)
 	struct ethtool_rxfh rss_head = {0};
 	struct ethtool_rxnfc ring_count;
 	struct ethtool_rxfh *rss;
+	u32 rss_context = 0;
 	u32 i, indir_bytes;
+	int arg_num = 0;
 	char *hkey;
 	int err;
 
+	while (arg_num < ctx->argc) {
+		if (!strcmp(ctx->argp[arg_num], "context")) {
+			++arg_num;
+			rss_context = get_int_range(ctx->argp[arg_num], 0, 1,
+						    ETH_RXFH_CONTEXT_ALLOC - 1);
+			++arg_num;
+		} else {
+			exit_bad_args();
+		}
+	}
+
 	ring_count.cmd = ETHTOOL_GRXRINGS;
 	err = send_ioctl(ctx, &ring_count);
 	if (err < 0) {
@@ -3695,6 +3736,7 @@ static int do_grxfh(struct cmd_context *ctx)
 	}
 
 	rss_head.cmd = ETHTOOL_GRSSH;
+	rss_head.rss_context = rss_context;
 	err = send_ioctl(ctx, &rss_head);
 	if (err < 0 && errno == EOPNOTSUPP) {
 		return do_grxfhindir(ctx, &ring_count);
@@ -3712,6 +3754,7 @@ static int do_grxfh(struct cmd_context *ctx)
 	}
 
 	rss->cmd = ETHTOOL_GRSSH;
+	rss->rss_context = rss_context;
 	rss->indir_size = rss_head.indir_size;
 	rss->key_size = rss_head.key_size;
 	err = send_ioctl(ctx, rss);
@@ -3872,6 +3915,8 @@ static int do_srxfh(struct cmd_context *ctx)
 	u32 req_hfunc = 0;
 	u32 entry_size = sizeof(rss_head.rss_config[0]);
 	u32 num_weights = 0;
+	u32 rss_context = 0;
+	int delete = 0;
 
 	if (ctx->argc < 1)
 		exit_bad_args();
@@ -3907,6 +3952,18 @@ static int do_srxfh(struct cmd_context *ctx)
 			if (!req_hfunc_name)
 				exit_bad_args();
 			++arg_num;
+		} else if (!strcmp(ctx->argp[arg_num], "context")) {
+			++arg_num;
+			if(!strcmp(ctx->argp[arg_num], "new"))
+				rss_context = ETH_RXFH_CONTEXT_ALLOC;
+			else
+				rss_context = get_int_range(
+						ctx->argp[arg_num], 0, 1,
+						ETH_RXFH_CONTEXT_ALLOC - 1);
+			++arg_num;
+		} else if (!strcmp(ctx->argp[arg_num], "delete")) {
+			++arg_num;
+			delete = 1;
 		} else {
 			exit_bad_args();
 		}
@@ -3930,6 +3987,41 @@ static int do_srxfh(struct cmd_context *ctx)
 		return 1;
 	}
 
+	if (rxfhindir_default && rss_context) {
+		fprintf(stderr,
+			"Default and context options are mutually exclusive\n");
+		return 1;
+	}
+
+	if (delete && !rss_context) {
+		fprintf(stderr, "Delete option requires context option\n");
+		return 1;
+	}
+	
+	if (delete && rxfhindir_weight) {
+		fprintf(stderr,
+			"Delete and weight options are mutually exclusive\n");
+		return 1;
+	}
+	
+	if (delete && rxfhindir_equal) {
+		fprintf(stderr,
+			"Delete and equal options are mutually exclusive\n");
+		return 1;
+	}
+	
+	if (delete && rxfhindir_default) {
+		fprintf(stderr,
+			"Delete and default options are mutually exclusive\n");
+		return 1;
+	}
+	
+	if (delete && rxfhindir_key) {
+		fprintf(stderr,
+			"Delete and hkey options are mutually exclusive\n");
+		return 1;
+	}
+
 	ring_count.cmd = ETHTOOL_GRXRINGS;
 	err = send_ioctl(ctx, &ring_count);
 	if (err < 0) {
@@ -3940,7 +4032,7 @@ 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 &&
-	    !req_hfunc_name) {
+	    !req_hfunc_name && !rss_context) {
 		return do_srxfhindir(ctx, rxfhindir_default, rxfhindir_equal,
 				     rxfhindir_weight, num_weights);
 	} else if (err < 0) {
@@ -3988,14 +4080,19 @@ static int do_srxfh(struct cmd_context *ctx)
 		goto free;
 	}
 	rss->cmd = ETHTOOL_SRSSH;
-	rss->indir_size = rss_head.indir_size;
-	rss->key_size = rss_head.key_size;
+	rss->rss_context = rss_context;
 	rss->hfunc = req_hfunc;
-
-	if (fill_indir_table(&rss->indir_size, rss->rss_config, rxfhindir_default,
-			     rxfhindir_equal, rxfhindir_weight, num_weights)) {
-		err = 1;
-		goto free;
+	if (delete) {
+		rss->indir_size = rss->key_size = 0;
+	} else {
+		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)) {
+			err = 1;
+			goto free;
+		}
 	}
 
 	if (hkey)
@@ -4008,6 +4105,8 @@ static int do_srxfh(struct cmd_context *ctx)
 	if (err < 0) {
 		perror("Cannot set RX flow hash configuration");
 		err = 1;
+	} else if (rss_context == ETH_RXFH_CONTEXT_ALLOC) {
+		printf("New RSS context is %d\n", rss->rss_context);
 	}
 
 free:
@@ -5023,12 +5122,12 @@ static const struct option {
 	{ "-n|-u|--show-nfc|--show-ntuple", 1, do_grxclass,
 	  "Show Rx network flow classification options or rules",
 	  "		[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
-	  "tcp6|udp6|ah6|esp6|sctp6 |\n"
+	  "tcp6|udp6|ah6|esp6|sctp6 [context %d] |\n"
 	  "		  rule %d ]\n" },
 	{ "-N|-U|--config-nfc|--config-ntuple", 1, do_srxclass,
 	  "Configure Rx network flow classification options or rules",
 	  "		rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
-	  "tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... |\n"
+	  "tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... [context %d] |\n"
 	  "		flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4|"
 	  "ip6|tcp6|udp6|ah6|esp6|sctp6\n"
 	  "			[ src %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
@@ -5047,17 +5146,21 @@ static const struct option {
 	  "			[ user-def %x [m %x] ]\n"
 	  "			[ dst-mac %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
 	  "			[ action %d ] | [ vf %d queue %d ]\n"
+	  "			[ context %d ]\n"
 	  "			[ loc %d]] |\n"
 	  "		delete %d\n" },
 	{ "-T|--show-time-stamping", 1, do_tsinfo,
 	  "Show time stamping capabilities" },
 	{ "-x|--show-rxfh-indir|--show-rxfh", 1, do_grxfh,
-	  "Show Rx flow hash indirection table and/or RSS hash key" },
+	  "Show Rx flow hash indirection table and/or RSS hash key",
+	  "		[ context %d ]\n" },
 	{ "-X|--set-rxfh-indir|--rxfh", 1, do_srxfh,
 	  "Set Rx flow hash indirection table and/or RSS hash key",
+	  "		[ context %d|new ]\n"
 	  "		[ equal N | weight W0 W1 ... | default ]\n"
 	  "		[ hkey %x:%x:%x:%x:%x:.... ]\n"
-	  "		[ hfunc FUNC ]\n" },
+	  "		[ hfunc FUNC ]\n"
+	  "		[ delete ]\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" },
diff --git a/internal.h b/internal.h
index 4e658ea..913f4eb 100644
--- a/internal.h
+++ b/internal.h
@@ -332,11 +332,11 @@ int vmxnet3_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
 
 /* Rx flow classification */
 int rxclass_parse_ruleopts(struct cmd_context *ctx,
-			   struct ethtool_rx_flow_spec *fsp);
+			   struct ethtool_rx_flow_spec *fsp, __u32 *rss_context);
 int rxclass_rule_getall(struct cmd_context *ctx);
 int rxclass_rule_get(struct cmd_context *ctx, __u32 loc);
 int rxclass_rule_ins(struct cmd_context *ctx,
-		     struct ethtool_rx_flow_spec *fsp);
+		     struct ethtool_rx_flow_spec *fsp, __u32 rss_context);
 int rxclass_rule_del(struct cmd_context *ctx, __u32 loc);
 
 /* Module EEPROM parsing code */
diff --git a/rxclass.c b/rxclass.c
index e05031b..ce4b382 100644
--- a/rxclass.c
+++ b/rxclass.c
@@ -94,14 +94,15 @@ static void rxclass_print_nfc_spec_ext(struct ethtool_rx_flow_spec *fsp)
 	}
 }
 
-static void rxclass_print_nfc_rule(struct ethtool_rx_flow_spec *fsp)
+static void rxclass_print_nfc_rule(struct ethtool_rx_flow_spec *fsp,
+				   __u32 rss_context)
 {
 	unsigned char	*smac, *smacm, *dmac, *dmacm;
 	__u32		flow_type;
 
 	fprintf(stdout,	"Filter: %d\n", fsp->location);
 
-	flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT);
+	flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
 
 	invert_flow_mask(fsp);
 
@@ -247,6 +248,9 @@ static void rxclass_print_nfc_rule(struct ethtool_rx_flow_spec *fsp)
 
 	rxclass_print_nfc_spec_ext(fsp);
 
+	if (fsp->flow_type & FLOW_RSS)
+		fprintf(stdout, "\tRSS Context ID: %u\n", rss_context);
+
 	if (fsp->ring_cookie != RX_CLS_FLOW_DISC) {
 		u64 vf = ethtool_get_flow_spec_ring_vf(fsp->ring_cookie);
 		u64 queue = ethtool_get_flow_spec_ring(fsp->ring_cookie);
@@ -269,10 +273,11 @@ static void rxclass_print_nfc_rule(struct ethtool_rx_flow_spec *fsp)
 	fprintf(stdout, "\n");
 }
 
-static void rxclass_print_rule(struct ethtool_rx_flow_spec *fsp)
+static void rxclass_print_rule(struct ethtool_rx_flow_spec *fsp,
+			       __u32 rss_context)
 {
 	/* print the rule in this location */
-	switch (fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
+	switch (fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS)) {
 	case TCP_V4_FLOW:
 	case UDP_V4_FLOW:
 	case SCTP_V4_FLOW:
@@ -285,11 +290,11 @@ static void rxclass_print_rule(struct ethtool_rx_flow_spec *fsp)
 	case ESP_V6_FLOW:
 	case IPV6_USER_FLOW:
 	case ETHER_FLOW:
-		rxclass_print_nfc_rule(fsp);
+		rxclass_print_nfc_rule(fsp, rss_context);
 		break;
 	case IPV4_USER_FLOW:
 		if (fsp->h_u.usr_ip4_spec.ip_ver == ETH_RX_NFC_IP4)
-			rxclass_print_nfc_rule(fsp);
+			rxclass_print_nfc_rule(fsp, rss_context);
 		else /* IPv6 uses IPV6_USER_FLOW */
 			fprintf(stderr, "IPV4_USER_FLOW with wrong ip_ver\n");
 		break;
@@ -333,7 +338,7 @@ int rxclass_rule_get(struct cmd_context *ctx, __u32 loc)
 	}
 
 	/* display rule */
-	rxclass_print_rule(&nfccmd.fs);
+	rxclass_print_rule(&nfccmd.fs, (__u32)nfccmd.rss_context);
 	return err;
 }
 
@@ -563,7 +568,7 @@ out:
 }
 
 int rxclass_rule_ins(struct cmd_context *ctx,
-		     struct ethtool_rx_flow_spec *fsp)
+		     struct ethtool_rx_flow_spec *fsp, __u32 rss_context)
 {
 	struct ethtool_rxnfc nfccmd;
 	__u32 loc = fsp->location;
@@ -581,6 +586,7 @@ int rxclass_rule_ins(struct cmd_context *ctx,
 
 	/* notify netdev of new rule */
 	nfccmd.cmd = ETHTOOL_SRXCLSRLINS;
+	nfccmd.rss_context = rss_context;
 	nfccmd.fs = *fsp;
 	err = send_ioctl(ctx, &nfccmd);
 	if (err < 0)
@@ -1254,7 +1260,7 @@ static int rxclass_get_mask(char *str, unsigned char *p,
 }
 
 int rxclass_parse_ruleopts(struct cmd_context *ctx,
-			   struct ethtool_rx_flow_spec *fsp)
+			   struct ethtool_rx_flow_spec *fsp, __u32 *rss_context)
 {
 	const struct rule_opts *options;
 	unsigned char *p = (unsigned char *)fsp;
@@ -1343,6 +1349,40 @@ int rxclass_parse_ruleopts(struct cmd_context *ctx,
 	for (i = 1; i < argc;) {
 		const struct rule_opts *opt;
 		int idx;
+
+		/* special handling for 'context %d' as it doesn't go in
+		 * the struct ethtool_rx_flow_spec
+		 */
+		if (!strcmp(argp[i], "context")) {
+			unsigned long long val;
+
+			i++;
+			if (i >= argc) {
+				fprintf(stderr, "'context' missing value\n");
+				return -1;
+			}
+
+			if (rxclass_get_ulong(argp[i], &val, 32)) {
+				fprintf(stderr, "Invalid context value[%s]\n",
+					argp[i]);
+				return -1;
+			}
+
+			/* Can't use the ALLOC special value as the context ID
+			 * of a filter to insert
+			 */
+			if ((__u32)val == ETH_RXFH_CONTEXT_ALLOC) {
+				fprintf(stderr, "Bad context value %x\n",
+					(__u32)val);
+				return -1;
+			}
+
+			*rss_context = (__u32)val;
+			fsp->flow_type |= FLOW_RSS;
+			i++;
+			continue;
+		}
+
 		for (opt = options, idx = 0; idx < n_opts; idx++, opt++) {
 			char mask_name[16];
 

  parent reply	other threads:[~2018-03-09 15:04 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-09 15:01 [PATCH ethtool 0/3] RSS ntuple filters Edward Cree
2018-03-09 15:03 ` [PATCH ethtool 1/3] ethtool-copy.h: sync with net-next Edward Cree
2018-03-09 15:04 ` Edward Cree [this message]
2018-03-09 15:04 ` [PATCH ethtool 3/3] ethtool.8: Document RSS context control and RSS filters Edward Cree
2018-03-12 18:51 ` [PATCH ethtool 0/3] RSS ntuple filters John W. Linville

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=219f1d93-46b9-ba70-266e-21ea34887034@solarflare.com \
    --to=ecree@solarflare.com \
    --cc=linville@tuxdriver.com \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.