Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/net/ethernet/google/gve/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 9 kB image not shown  

Quelle  gve_flow_rule.c   Sprache: C

 
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Google virtual Ethernet (gve) driver
 *
 * Copyright (C) 2015-2024 Google LLC
 */


#include "gve.h"
#include "gve_adminq.h"

static
int gve_fill_ethtool_flow_spec(struct ethtool_rx_flow_spec *fsp,
          struct gve_adminq_queried_flow_rule *rule)
{
 struct gve_adminq_flow_rule *flow_rule = &rule->flow_rule;
 static const u16 flow_type_lut[] = {
  [GVE_FLOW_TYPE_TCPV4] = TCP_V4_FLOW,
  [GVE_FLOW_TYPE_UDPV4] = UDP_V4_FLOW,
  [GVE_FLOW_TYPE_SCTPV4] = SCTP_V4_FLOW,
  [GVE_FLOW_TYPE_AHV4] = AH_V4_FLOW,
  [GVE_FLOW_TYPE_ESPV4] = ESP_V4_FLOW,
  [GVE_FLOW_TYPE_TCPV6] = TCP_V6_FLOW,
  [GVE_FLOW_TYPE_UDPV6] = UDP_V6_FLOW,
  [GVE_FLOW_TYPE_SCTPV6] = SCTP_V6_FLOW,
  [GVE_FLOW_TYPE_AHV6] = AH_V6_FLOW,
  [GVE_FLOW_TYPE_ESPV6] = ESP_V6_FLOW,
 };

 if (be16_to_cpu(flow_rule->flow_type) >= ARRAY_SIZE(flow_type_lut))
  return -EINVAL;

 fsp->flow_type = flow_type_lut[be16_to_cpu(flow_rule->flow_type)];

 memset(&fsp->h_u, 0, sizeof(fsp->h_u));
 memset(&fsp->h_ext, 0, sizeof(fsp->h_ext));
 memset(&fsp->m_u, 0, sizeof(fsp->m_u));
 memset(&fsp->m_ext, 0, sizeof(fsp->m_ext));

 switch (fsp->flow_type) {
 case TCP_V4_FLOW:
 case UDP_V4_FLOW:
 case SCTP_V4_FLOW:
  fsp->h_u.tcp_ip4_spec.ip4src = flow_rule->key.src_ip[0];
  fsp->h_u.tcp_ip4_spec.ip4dst = flow_rule->key.dst_ip[0];
  fsp->h_u.tcp_ip4_spec.psrc = flow_rule->key.src_port;
  fsp->h_u.tcp_ip4_spec.pdst = flow_rule->key.dst_port;
  fsp->h_u.tcp_ip4_spec.tos = flow_rule->key.tos;
  fsp->m_u.tcp_ip4_spec.ip4src = flow_rule->mask.src_ip[0];
  fsp->m_u.tcp_ip4_spec.ip4dst = flow_rule->mask.dst_ip[0];
  fsp->m_u.tcp_ip4_spec.psrc = flow_rule->mask.src_port;
  fsp->m_u.tcp_ip4_spec.pdst = flow_rule->mask.dst_port;
  fsp->m_u.tcp_ip4_spec.tos = flow_rule->mask.tos;
  break;
 case AH_V4_FLOW:
 case ESP_V4_FLOW:
  fsp->h_u.ah_ip4_spec.ip4src = flow_rule->key.src_ip[0];
  fsp->h_u.ah_ip4_spec.ip4dst = flow_rule->key.dst_ip[0];
  fsp->h_u.ah_ip4_spec.spi = flow_rule->key.spi;
  fsp->h_u.ah_ip4_spec.tos = flow_rule->key.tos;
  fsp->m_u.ah_ip4_spec.ip4src = flow_rule->mask.src_ip[0];
  fsp->m_u.ah_ip4_spec.ip4dst = flow_rule->mask.dst_ip[0];
  fsp->m_u.ah_ip4_spec.spi = flow_rule->mask.spi;
  fsp->m_u.ah_ip4_spec.tos = flow_rule->mask.tos;
  break;
 case TCP_V6_FLOW:
 case UDP_V6_FLOW:
 case SCTP_V6_FLOW:
  memcpy(fsp->h_u.tcp_ip6_spec.ip6src, &flow_rule->key.src_ip,
         sizeof(struct in6_addr));
  memcpy(fsp->h_u.tcp_ip6_spec.ip6dst, &flow_rule->key.dst_ip,
         sizeof(struct in6_addr));
  fsp->h_u.tcp_ip6_spec.psrc = flow_rule->key.src_port;
  fsp->h_u.tcp_ip6_spec.pdst = flow_rule->key.dst_port;
  fsp->h_u.tcp_ip6_spec.tclass = flow_rule->key.tclass;
  memcpy(fsp->m_u.tcp_ip6_spec.ip6src, &flow_rule->mask.src_ip,
         sizeof(struct in6_addr));
  memcpy(fsp->m_u.tcp_ip6_spec.ip6dst, &flow_rule->mask.dst_ip,
         sizeof(struct in6_addr));
  fsp->m_u.tcp_ip6_spec.psrc = flow_rule->mask.src_port;
  fsp->m_u.tcp_ip6_spec.pdst = flow_rule->mask.dst_port;
  fsp->m_u.tcp_ip6_spec.tclass = flow_rule->mask.tclass;
  break;
 case AH_V6_FLOW:
 case ESP_V6_FLOW:
  memcpy(fsp->h_u.ah_ip6_spec.ip6src, &flow_rule->key.src_ip,
         sizeof(struct in6_addr));
  memcpy(fsp->h_u.ah_ip6_spec.ip6dst, &flow_rule->key.dst_ip,
         sizeof(struct in6_addr));
  fsp->h_u.ah_ip6_spec.spi = flow_rule->key.spi;
  fsp->h_u.ah_ip6_spec.tclass = flow_rule->key.tclass;
  memcpy(fsp->m_u.ah_ip6_spec.ip6src, &flow_rule->mask.src_ip,
         sizeof(struct in6_addr));
  memcpy(fsp->m_u.ah_ip6_spec.ip6dst, &flow_rule->mask.dst_ip,
         sizeof(struct in6_addr));
  fsp->m_u.ah_ip6_spec.spi = flow_rule->mask.spi;
  fsp->m_u.ah_ip6_spec.tclass = flow_rule->mask.tclass;
  break;
 default:
  return -EINVAL;
 }

 fsp->ring_cookie = be16_to_cpu(flow_rule->action);

 return 0;
}

static int gve_generate_flow_rule(struct gve_priv *priv, struct ethtool_rx_flow_spec *fsp,
      struct gve_adminq_flow_rule *rule)
{
 static const u16 flow_type_lut[] = {
  [TCP_V4_FLOW] = GVE_FLOW_TYPE_TCPV4,
  [UDP_V4_FLOW] = GVE_FLOW_TYPE_UDPV4,
  [SCTP_V4_FLOW] = GVE_FLOW_TYPE_SCTPV4,
  [AH_V4_FLOW] = GVE_FLOW_TYPE_AHV4,
  [ESP_V4_FLOW] = GVE_FLOW_TYPE_ESPV4,
  [TCP_V6_FLOW] = GVE_FLOW_TYPE_TCPV6,
  [UDP_V6_FLOW] = GVE_FLOW_TYPE_UDPV6,
  [SCTP_V6_FLOW] = GVE_FLOW_TYPE_SCTPV6,
  [AH_V6_FLOW] = GVE_FLOW_TYPE_AHV6,
  [ESP_V6_FLOW] = GVE_FLOW_TYPE_ESPV6,
 };
 u32 flow_type;

 if (fsp->ring_cookie == RX_CLS_FLOW_DISC)
  return -EOPNOTSUPP;

 if (fsp->ring_cookie >= priv->rx_cfg.num_queues)
  return -EINVAL;

 rule->action = cpu_to_be16(fsp->ring_cookie);

 flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
 if (!flow_type || flow_type >= ARRAY_SIZE(flow_type_lut))
  return -EINVAL;

 rule->flow_type = cpu_to_be16(flow_type_lut[flow_type]);

 switch (flow_type) {
 case TCP_V4_FLOW:
 case UDP_V4_FLOW:
 case SCTP_V4_FLOW:
  rule->key.src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
  rule->key.dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
  rule->key.src_port = fsp->h_u.tcp_ip4_spec.psrc;
  rule->key.dst_port = fsp->h_u.tcp_ip4_spec.pdst;
  rule->mask.src_ip[0] = fsp->m_u.tcp_ip4_spec.ip4src;
  rule->mask.dst_ip[0] = fsp->m_u.tcp_ip4_spec.ip4dst;
  rule->mask.src_port = fsp->m_u.tcp_ip4_spec.psrc;
  rule->mask.dst_port = fsp->m_u.tcp_ip4_spec.pdst;
  break;
 case AH_V4_FLOW:
 case ESP_V4_FLOW:
  rule->key.src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
  rule->key.dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
  rule->key.spi = fsp->h_u.ah_ip4_spec.spi;
  rule->mask.src_ip[0] = fsp->m_u.tcp_ip4_spec.ip4src;
  rule->mask.dst_ip[0] = fsp->m_u.tcp_ip4_spec.ip4dst;
  rule->mask.spi = fsp->m_u.ah_ip4_spec.spi;
  break;
 case TCP_V6_FLOW:
 case UDP_V6_FLOW:
 case SCTP_V6_FLOW:
  memcpy(&rule->key.src_ip, fsp->h_u.tcp_ip6_spec.ip6src,
         sizeof(struct in6_addr));
  memcpy(&rule->key.dst_ip, fsp->h_u.tcp_ip6_spec.ip6dst,
         sizeof(struct in6_addr));
  rule->key.src_port = fsp->h_u.tcp_ip6_spec.psrc;
  rule->key.dst_port = fsp->h_u.tcp_ip6_spec.pdst;
  memcpy(&rule->mask.src_ip, fsp->m_u.tcp_ip6_spec.ip6src,
         sizeof(struct in6_addr));
  memcpy(&rule->mask.dst_ip, fsp->m_u.tcp_ip6_spec.ip6dst,
         sizeof(struct in6_addr));
  rule->mask.src_port = fsp->m_u.tcp_ip6_spec.psrc;
  rule->mask.dst_port = fsp->m_u.tcp_ip6_spec.pdst;
  break;
 case AH_V6_FLOW:
 case ESP_V6_FLOW:
  memcpy(&rule->key.src_ip, fsp->h_u.usr_ip6_spec.ip6src,
         sizeof(struct in6_addr));
  memcpy(&rule->key.dst_ip, fsp->h_u.usr_ip6_spec.ip6dst,
         sizeof(struct in6_addr));
  rule->key.spi = fsp->h_u.ah_ip6_spec.spi;
  memcpy(&rule->mask.src_ip, fsp->m_u.usr_ip6_spec.ip6src,
         sizeof(struct in6_addr));
  memcpy(&rule->mask.dst_ip, fsp->m_u.usr_ip6_spec.ip6dst,
         sizeof(struct in6_addr));
  rule->key.spi = fsp->h_u.ah_ip6_spec.spi;
  break;
 default:
  /* not doing un-parsed flow types */
  return -EINVAL;
 }

 return 0;
}

int gve_get_flow_rule_entry(struct gve_priv *priv, struct ethtool_rxnfc *cmd)
{
 struct gve_adminq_queried_flow_rule *rules_cache = priv->flow_rules_cache.rules_cache;
 struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
 u32 *cache_num = &priv->flow_rules_cache.rules_cache_num;
 struct gve_adminq_queried_flow_rule *rule = NULL;
 int err = 0;
 u32 i;

 if (!priv->max_flow_rules)
  return -EOPNOTSUPP;

 if (!priv->flow_rules_cache.rules_cache_synced ||
     fsp->location < be32_to_cpu(rules_cache[0].location) ||
     fsp->location > be32_to_cpu(rules_cache[*cache_num - 1].location)) {
  err = gve_adminq_query_flow_rules(priv, GVE_FLOW_RULE_QUERY_RULES, fsp->location);
  if (err)
   return err;

  priv->flow_rules_cache.rules_cache_synced = true;
 }

 for (i = 0; i < *cache_num; i++) {
  if (fsp->location == be32_to_cpu(rules_cache[i].location)) {
   rule = &rules_cache[i];
   break;
  }
 }

 if (!rule)
  return -EINVAL;

 err = gve_fill_ethtool_flow_spec(fsp, rule);

 return err;
}

int gve_get_flow_rule_ids(struct gve_priv *priv, struct ethtool_rxnfc *cmd, u32 *rule_locs)
{
 __be32 *rule_ids_cache = priv->flow_rules_cache.rule_ids_cache;
 u32 *cache_num = &priv->flow_rules_cache.rule_ids_cache_num;
 u32 starting_rule_id = 0;
 u32 i = 0, j = 0;
 int err = 0;

 if (!priv->max_flow_rules)
  return -EOPNOTSUPP;

 do {
  err = gve_adminq_query_flow_rules(priv, GVE_FLOW_RULE_QUERY_IDS,
        starting_rule_id);
  if (err)
   return err;

  for (i = 0; i < *cache_num; i++) {
   if (j >= cmd->rule_cnt)
    return -EMSGSIZE;

   rule_locs[j++] = be32_to_cpu(rule_ids_cache[i]);
   starting_rule_id = be32_to_cpu(rule_ids_cache[i]) + 1;
  }
 } while (*cache_num != 0);
 cmd->data = priv->max_flow_rules;

 return err;
}

int gve_add_flow_rule(struct gve_priv *priv, struct ethtool_rxnfc *cmd)
{
 struct ethtool_rx_flow_spec *fsp = &cmd->fs;
 struct gve_adminq_flow_rule *rule = NULL;
 int err;

 if (!priv->max_flow_rules)
  return -EOPNOTSUPP;

 rule = kvzalloc(sizeof(*rule), GFP_KERNEL);
 if (!rule)
  return -ENOMEM;

 err = gve_generate_flow_rule(priv, fsp, rule);
 if (err)
  goto out;

 err = gve_adminq_add_flow_rule(priv, rule, fsp->location);

out:
 kvfree(rule);
 if (err)
  dev_err(&priv->pdev->dev, "Failed to add the flow rule: %u", fsp->location);

 return err;
}

int gve_del_flow_rule(struct gve_priv *priv, struct ethtool_rxnfc *cmd)
{
 struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;

 if (!priv->max_flow_rules)
  return -EOPNOTSUPP;

 return gve_adminq_del_flow_rule(priv, fsp->location);
}

Messung V0.5
C=90 H=93 G=91

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.