File Index
Files and directories
Sign in
FILE

gve_flow_rule.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/google/gve/gve_flow_rule.c C
  1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
  2/* Google virtual Ethernet (gve) driver
  3 *
  4 * Copyright (C) 2015-2024 Google LLC
  5 */
  6
  7#include "gve.h"
  8#include "gve_adminq.h"
  9
 10static
 11int gve_fill_ethtool_flow_spec(struct ethtool_rx_flow_spec *fsp,
 12			       struct gve_adminq_queried_flow_rule *rule)
 13{
 14	struct gve_adminq_flow_rule *flow_rule = &rule->flow_rule;
 15	static const u16 flow_type_lut[] = {
 16		[GVE_FLOW_TYPE_TCPV4]	= TCP_V4_FLOW,
 17		[GVE_FLOW_TYPE_UDPV4]	= UDP_V4_FLOW,
 18		[GVE_FLOW_TYPE_SCTPV4]	= SCTP_V4_FLOW,
 19		[GVE_FLOW_TYPE_AHV4]	= AH_V4_FLOW,
 20		[GVE_FLOW_TYPE_ESPV4]	= ESP_V4_FLOW,
 21		[GVE_FLOW_TYPE_TCPV6]	= TCP_V6_FLOW,
 22		[GVE_FLOW_TYPE_UDPV6]	= UDP_V6_FLOW,
 23		[GVE_FLOW_TYPE_SCTPV6]	= SCTP_V6_FLOW,
 24		[GVE_FLOW_TYPE_AHV6]	= AH_V6_FLOW,
 25		[GVE_FLOW_TYPE_ESPV6]	= ESP_V6_FLOW,
 26	};
 27
 28	if (be16_to_cpu(flow_rule->flow_type) >= ARRAY_SIZE(flow_type_lut))
 29		return -EINVAL;
 30
 31	fsp->flow_type = flow_type_lut[be16_to_cpu(flow_rule->flow_type)];
 32
 33	memset(&fsp->h_u, 0, sizeof(fsp->h_u));
 34	memset(&fsp->h_ext, 0, sizeof(fsp->h_ext));
 35	memset(&fsp->m_u, 0, sizeof(fsp->m_u));
 36	memset(&fsp->m_ext, 0, sizeof(fsp->m_ext));
 37
 38	switch (fsp->flow_type) {
 39	case TCP_V4_FLOW:
 40	case UDP_V4_FLOW:
 41	case SCTP_V4_FLOW:
 42		fsp->h_u.tcp_ip4_spec.ip4src = flow_rule->key.src_ip[0];
 43		fsp->h_u.tcp_ip4_spec.ip4dst = flow_rule->key.dst_ip[0];
 44		fsp->h_u.tcp_ip4_spec.psrc = flow_rule->key.src_port;
 45		fsp->h_u.tcp_ip4_spec.pdst = flow_rule->key.dst_port;
 46		fsp->h_u.tcp_ip4_spec.tos = flow_rule->key.tos;
 47		fsp->m_u.tcp_ip4_spec.ip4src = flow_rule->mask.src_ip[0];
 48		fsp->m_u.tcp_ip4_spec.ip4dst = flow_rule->mask.dst_ip[0];
 49		fsp->m_u.tcp_ip4_spec.psrc = flow_rule->mask.src_port;
 50		fsp->m_u.tcp_ip4_spec.pdst = flow_rule->mask.dst_port;
 51		fsp->m_u.tcp_ip4_spec.tos = flow_rule->mask.tos;
 52		break;
 53	case AH_V4_FLOW:
 54	case ESP_V4_FLOW:
 55		fsp->h_u.ah_ip4_spec.ip4src = flow_rule->key.src_ip[0];
 56		fsp->h_u.ah_ip4_spec.ip4dst = flow_rule->key.dst_ip[0];
 57		fsp->h_u.ah_ip4_spec.spi = flow_rule->key.spi;
 58		fsp->h_u.ah_ip4_spec.tos = flow_rule->key.tos;
 59		fsp->m_u.ah_ip4_spec.ip4src = flow_rule->mask.src_ip[0];
 60		fsp->m_u.ah_ip4_spec.ip4dst = flow_rule->mask.dst_ip[0];
 61		fsp->m_u.ah_ip4_spec.spi = flow_rule->mask.spi;
 62		fsp->m_u.ah_ip4_spec.tos = flow_rule->mask.tos;
 63		break;
 64	case TCP_V6_FLOW:
 65	case UDP_V6_FLOW:
 66	case SCTP_V6_FLOW:
 67		memcpy(fsp->h_u.tcp_ip6_spec.ip6src, &flow_rule->key.src_ip,
 68		       sizeof(struct in6_addr));
 69		memcpy(fsp->h_u.tcp_ip6_spec.ip6dst, &flow_rule->key.dst_ip,
 70		       sizeof(struct in6_addr));
 71		fsp->h_u.tcp_ip6_spec.psrc = flow_rule->key.src_port;
 72		fsp->h_u.tcp_ip6_spec.pdst = flow_rule->key.dst_port;
 73		fsp->h_u.tcp_ip6_spec.tclass = flow_rule->key.tclass;
 74		memcpy(fsp->m_u.tcp_ip6_spec.ip6src, &flow_rule->mask.src_ip,
 75		       sizeof(struct in6_addr));
 76		memcpy(fsp->m_u.tcp_ip6_spec.ip6dst, &flow_rule->mask.dst_ip,
 77		       sizeof(struct in6_addr));
 78		fsp->m_u.tcp_ip6_spec.psrc = flow_rule->mask.src_port;
 79		fsp->m_u.tcp_ip6_spec.pdst = flow_rule->mask.dst_port;
 80		fsp->m_u.tcp_ip6_spec.tclass = flow_rule->mask.tclass;
 81		break;
 82	case AH_V6_FLOW:
 83	case ESP_V6_FLOW:
 84		memcpy(fsp->h_u.ah_ip6_spec.ip6src, &flow_rule->key.src_ip,
 85		       sizeof(struct in6_addr));
 86		memcpy(fsp->h_u.ah_ip6_spec.ip6dst, &flow_rule->key.dst_ip,
 87		       sizeof(struct in6_addr));
 88		fsp->h_u.ah_ip6_spec.spi = flow_rule->key.spi;
 89		fsp->h_u.ah_ip6_spec.tclass = flow_rule->key.tclass;
 90		memcpy(fsp->m_u.ah_ip6_spec.ip6src, &flow_rule->mask.src_ip,
 91		       sizeof(struct in6_addr));
 92		memcpy(fsp->m_u.ah_ip6_spec.ip6dst, &flow_rule->mask.dst_ip,
 93		       sizeof(struct in6_addr));
 94		fsp->m_u.ah_ip6_spec.spi = flow_rule->mask.spi;
 95		fsp->m_u.ah_ip6_spec.tclass = flow_rule->mask.tclass;
 96		break;
 97	default:
 98		return -EINVAL;
 99	}
100
101	fsp->ring_cookie = be16_to_cpu(flow_rule->action);
102
103	return 0;
104}
105
106static int gve_generate_flow_rule(struct gve_priv *priv, struct ethtool_rx_flow_spec *fsp,
107				  struct gve_adminq_flow_rule *rule)
108{
109	static const u16 flow_type_lut[] = {
110		[TCP_V4_FLOW]	= GVE_FLOW_TYPE_TCPV4,
111		[UDP_V4_FLOW]	= GVE_FLOW_TYPE_UDPV4,
112		[SCTP_V4_FLOW]	= GVE_FLOW_TYPE_SCTPV4,
113		[AH_V4_FLOW]	= GVE_FLOW_TYPE_AHV4,
114		[ESP_V4_FLOW]	= GVE_FLOW_TYPE_ESPV4,
115		[TCP_V6_FLOW]	= GVE_FLOW_TYPE_TCPV6,
116		[UDP_V6_FLOW]	= GVE_FLOW_TYPE_UDPV6,
117		[SCTP_V6_FLOW]	= GVE_FLOW_TYPE_SCTPV6,
118		[AH_V6_FLOW]	= GVE_FLOW_TYPE_AHV6,
119		[ESP_V6_FLOW]	= GVE_FLOW_TYPE_ESPV6,
120	};
121	u32 flow_type;
122
123	if (fsp->ring_cookie == RX_CLS_FLOW_DISC)
124		return -EOPNOTSUPP;
125
126	if (fsp->ring_cookie >= priv->rx_cfg.num_queues)
127		return -EINVAL;
128
129	rule->action = cpu_to_be16(fsp->ring_cookie);
130
131	flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
132	if (!flow_type || flow_type >= ARRAY_SIZE(flow_type_lut))
133		return -EINVAL;
134
135	rule->flow_type = cpu_to_be16(flow_type_lut[flow_type]);
136
137	switch (flow_type) {
138	case TCP_V4_FLOW:
139	case UDP_V4_FLOW:
140	case SCTP_V4_FLOW:
141		rule->key.src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
142		rule->key.dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
143		rule->key.src_port = fsp->h_u.tcp_ip4_spec.psrc;
144		rule->key.dst_port = fsp->h_u.tcp_ip4_spec.pdst;
145		rule->mask.src_ip[0] = fsp->m_u.tcp_ip4_spec.ip4src;
146		rule->mask.dst_ip[0] = fsp->m_u.tcp_ip4_spec.ip4dst;
147		rule->mask.src_port = fsp->m_u.tcp_ip4_spec.psrc;
148		rule->mask.dst_port = fsp->m_u.tcp_ip4_spec.pdst;
149		break;
150	case AH_V4_FLOW:
151	case ESP_V4_FLOW:
152		rule->key.src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
153		rule->key.dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
154		rule->key.spi = fsp->h_u.ah_ip4_spec.spi;
155		rule->mask.src_ip[0] = fsp->m_u.tcp_ip4_spec.ip4src;
156		rule->mask.dst_ip[0] = fsp->m_u.tcp_ip4_spec.ip4dst;
157		rule->mask.spi = fsp->m_u.ah_ip4_spec.spi;
158		break;
159	case TCP_V6_FLOW:
160	case UDP_V6_FLOW:
161	case SCTP_V6_FLOW:
162		memcpy(&rule->key.src_ip, fsp->h_u.tcp_ip6_spec.ip6src,
163		       sizeof(struct in6_addr));
164		memcpy(&rule->key.dst_ip, fsp->h_u.tcp_ip6_spec.ip6dst,
165		       sizeof(struct in6_addr));
166		rule->key.src_port = fsp->h_u.tcp_ip6_spec.psrc;
167		rule->key.dst_port = fsp->h_u.tcp_ip6_spec.pdst;
168		memcpy(&rule->mask.src_ip, fsp->m_u.tcp_ip6_spec.ip6src,
169		       sizeof(struct in6_addr));
170		memcpy(&rule->mask.dst_ip, fsp->m_u.tcp_ip6_spec.ip6dst,
171		       sizeof(struct in6_addr));
172		rule->mask.src_port = fsp->m_u.tcp_ip6_spec.psrc;
173		rule->mask.dst_port = fsp->m_u.tcp_ip6_spec.pdst;
174		break;
175	case AH_V6_FLOW:
176	case ESP_V6_FLOW:
177		memcpy(&rule->key.src_ip, fsp->h_u.usr_ip6_spec.ip6src,
178		       sizeof(struct in6_addr));
179		memcpy(&rule->key.dst_ip, fsp->h_u.usr_ip6_spec.ip6dst,
180		       sizeof(struct in6_addr));
181		rule->key.spi = fsp->h_u.ah_ip6_spec.spi;
182		memcpy(&rule->mask.src_ip, fsp->m_u.usr_ip6_spec.ip6src,
183		       sizeof(struct in6_addr));
184		memcpy(&rule->mask.dst_ip, fsp->m_u.usr_ip6_spec.ip6dst,
185		       sizeof(struct in6_addr));
186		rule->key.spi = fsp->h_u.ah_ip6_spec.spi;
187		break;
188	default:
189		/* not doing un-parsed flow types */
190		return -EINVAL;
191	}
192
193	return 0;
194}
195
196int gve_get_flow_rule_entry(struct gve_priv *priv, struct ethtool_rxnfc *cmd)
197{
198	struct gve_adminq_queried_flow_rule *rules_cache = priv->flow_rules_cache.rules_cache;
199	struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
200	u32 *cache_num = &priv->flow_rules_cache.rules_cache_num;
201	struct gve_adminq_queried_flow_rule *rule = NULL;
202	int err = 0;
203	u32 i;
204
205	if (!priv->max_flow_rules)
206		return -EOPNOTSUPP;
207
208	if (!priv->flow_rules_cache.rules_cache_synced ||
209	    fsp->location < be32_to_cpu(rules_cache[0].location) ||
210	    fsp->location > be32_to_cpu(rules_cache[*cache_num - 1].location)) {
211		err = gve_adminq_query_flow_rules(priv, GVE_FLOW_RULE_QUERY_RULES, fsp->location);
212		if (err)
213			return err;
214
215		priv->flow_rules_cache.rules_cache_synced = true;
216	}
217
218	for (i = 0; i < *cache_num; i++) {
219		if (fsp->location == be32_to_cpu(rules_cache[i].location)) {
220			rule = &rules_cache[i];
221			break;
222		}
223	}
224
225	if (!rule)
226		return -EINVAL;
227
228	err = gve_fill_ethtool_flow_spec(fsp, rule);
229
230	return err;
231}
232
233int gve_get_flow_rule_ids(struct gve_priv *priv, struct ethtool_rxnfc *cmd, u32 *rule_locs)
234{
235	__be32 *rule_ids_cache = priv->flow_rules_cache.rule_ids_cache;
236	u32 *cache_num = &priv->flow_rules_cache.rule_ids_cache_num;
237	u32 starting_rule_id = 0;
238	u32 i = 0, j = 0;
239	int err = 0;
240
241	if (!priv->max_flow_rules)
242		return -EOPNOTSUPP;
243
244	do {
245		err = gve_adminq_query_flow_rules(priv, GVE_FLOW_RULE_QUERY_IDS,
246						  starting_rule_id);
247		if (err)
248			return err;
249
250		for (i = 0; i < *cache_num; i++) {
251			if (j >= cmd->rule_cnt)
252				return -EMSGSIZE;
253
254			rule_locs[j++] = be32_to_cpu(rule_ids_cache[i]);
255			starting_rule_id = be32_to_cpu(rule_ids_cache[i]) + 1;
256		}
257	} while (*cache_num != 0);
258	cmd->data = priv->max_flow_rules;
259
260	return err;
261}
262
263int gve_add_flow_rule(struct gve_priv *priv, struct ethtool_rxnfc *cmd)
264{
265	struct ethtool_rx_flow_spec *fsp = &cmd->fs;
266	struct gve_adminq_flow_rule *rule = NULL;
267	int err;
268
269	if (!priv->max_flow_rules)
270		return -EOPNOTSUPP;
271
272	rule = kvzalloc(sizeof(*rule), GFP_KERNEL);
273	if (!rule)
274		return -ENOMEM;
275
276	err = gve_generate_flow_rule(priv, fsp, rule);
277	if (err)
278		goto out;
279
280	err = gve_adminq_add_flow_rule(priv, rule, fsp->location);
281
282out:
283	kvfree(rule);
284	if (err)
285		dev_err(&priv->pdev->dev, "Failed to add the flow rule: %u", fsp->location);
286
287	return err;
288}
289
290int gve_del_flow_rule(struct gve_priv *priv, struct ethtool_rxnfc *cmd)
291{
292	struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
293
294	if (!priv->max_flow_rules)
295		return -EOPNOTSUPP;
296
297	return gve_adminq_del_flow_rule(priv, fsp->location);
298}
~/ Read-only file preview.