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