brintos

brintos / linux-shallow public Read only

0
0
Text · 9.2 KiB · 0bb8cd1 Raw
299 lines · c
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)2/* Google virtual Ethernet (gve) driver3 *4 * Copyright (C) 2015-2024 Google LLC5 */6 7#include "gve.h"8#include "gve_adminq.h"9 10static11int 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}299