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

Quelle  spectrum_port_range.c   Sprache: C

 
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */

#include <linux/bits.h>
#include <linux/netlink.h>
#include <linux/refcount.h>
#include <linux/xarray.h>
#include <net/devlink.h>

#include "spectrum.h"

struct mlxsw_sp_port_range_reg {
 struct mlxsw_sp_port_range range;
 refcount_t refcount;
 u32 index;
};

struct mlxsw_sp_port_range_core {
 struct xarray prr_xa;
 struct xa_limit prr_ids;
 atomic_t prr_count;
};

static int
mlxsw_sp_port_range_reg_configure(struct mlxsw_sp *mlxsw_sp,
      const struct mlxsw_sp_port_range_reg *prr)
{
 char pprr_pl[MLXSW_REG_PPRR_LEN];

 /* We do not care if packet is IPv4/IPv6 and TCP/UDP, so set all four
 * fields.
 */

 mlxsw_reg_pprr_pack(pprr_pl, prr->index);
 mlxsw_reg_pprr_ipv4_set(pprr_pl, true);
 mlxsw_reg_pprr_ipv6_set(pprr_pl, true);
 mlxsw_reg_pprr_src_set(pprr_pl, prr->range.source);
 mlxsw_reg_pprr_dst_set(pprr_pl, !prr->range.source);
 mlxsw_reg_pprr_tcp_set(pprr_pl, true);
 mlxsw_reg_pprr_udp_set(pprr_pl, true);
 mlxsw_reg_pprr_port_range_min_set(pprr_pl, prr->range.min);
 mlxsw_reg_pprr_port_range_max_set(pprr_pl, prr->range.max);

 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pprr), pprr_pl);
}

static struct mlxsw_sp_port_range_reg *
mlxsw_sp_port_range_reg_create(struct mlxsw_sp *mlxsw_sp,
          const struct mlxsw_sp_port_range *range,
          struct netlink_ext_ack *extack)
{
 struct mlxsw_sp_port_range_core *pr_core = mlxsw_sp->pr_core;
 struct mlxsw_sp_port_range_reg *prr;
 int err;

 prr = kzalloc(sizeof(*prr), GFP_KERNEL);
 if (!prr)
  return ERR_PTR(-ENOMEM);

 prr->range = *range;
 refcount_set(&prr->refcount, 1);

 err = xa_alloc(&pr_core->prr_xa, &prr->index, prr, pr_core->prr_ids,
         GFP_KERNEL);
 if (err) {
  if (err == -EBUSY)
   NL_SET_ERR_MSG_MOD(extack, "Exceeded number of port range registers");
  goto err_xa_alloc;
 }

 err = mlxsw_sp_port_range_reg_configure(mlxsw_sp, prr);
 if (err) {
  NL_SET_ERR_MSG_MOD(extack, "Failed to configure port range register");
  goto err_reg_configure;
 }

 atomic_inc(&pr_core->prr_count);

 return prr;

err_reg_configure:
 xa_erase(&pr_core->prr_xa, prr->index);
err_xa_alloc:
 kfree(prr);
 return ERR_PTR(err);
}

static void mlxsw_sp_port_range_reg_destroy(struct mlxsw_sp *mlxsw_sp,
         struct mlxsw_sp_port_range_reg *prr)
{
 struct mlxsw_sp_port_range_core *pr_core = mlxsw_sp->pr_core;

 atomic_dec(&pr_core->prr_count);
 xa_erase(&pr_core->prr_xa, prr->index);
 kfree(prr);
}

static struct mlxsw_sp_port_range_reg *
mlxsw_sp_port_range_reg_find(struct mlxsw_sp *mlxsw_sp,
        const struct mlxsw_sp_port_range *range)
{
 struct mlxsw_sp_port_range_core *pr_core = mlxsw_sp->pr_core;
 struct mlxsw_sp_port_range_reg *prr;
 unsigned long index;

 xa_for_each(&pr_core->prr_xa, index, prr) {
  if (prr->range.min == range->min &&
      prr->range.max == range->max &&
      prr->range.source == range->source)
   return prr;
 }

 return NULL;
}

int mlxsw_sp_port_range_reg_get(struct mlxsw_sp *mlxsw_sp,
    const struct mlxsw_sp_port_range *range,
    struct netlink_ext_ack *extack,
    u8 *p_prr_index)
{
 struct mlxsw_sp_port_range_reg *prr;

 prr = mlxsw_sp_port_range_reg_find(mlxsw_sp, range);
 if (prr) {
  refcount_inc(&prr->refcount);
  *p_prr_index = prr->index;
  return 0;
 }

 prr = mlxsw_sp_port_range_reg_create(mlxsw_sp, range, extack);
 if (IS_ERR(prr))
  return PTR_ERR(prr);

 *p_prr_index = prr->index;

 return 0;
}

void mlxsw_sp_port_range_reg_put(struct mlxsw_sp *mlxsw_sp, u8 prr_index)
{
 struct mlxsw_sp_port_range_core *pr_core = mlxsw_sp->pr_core;
 struct mlxsw_sp_port_range_reg *prr;

 prr = xa_load(&pr_core->prr_xa, prr_index);
 if (WARN_ON(!prr))
  return;

 if (!refcount_dec_and_test(&prr->refcount))
  return;

 mlxsw_sp_port_range_reg_destroy(mlxsw_sp, prr);
}

static u64 mlxsw_sp_port_range_reg_occ_get(void *priv)
{
 struct mlxsw_sp_port_range_core *pr_core = priv;

 return atomic_read(&pr_core->prr_count);
}

int mlxsw_sp_port_range_init(struct mlxsw_sp *mlxsw_sp)
{
 struct mlxsw_sp_port_range_core *pr_core;
 struct mlxsw_core *core = mlxsw_sp->core;
 u64 max;

 if (!MLXSW_CORE_RES_VALID(core, ACL_MAX_L4_PORT_RANGE))
  return -EIO;
 max = MLXSW_CORE_RES_GET(core, ACL_MAX_L4_PORT_RANGE);

 /* Each port range register is represented using a single bit in the
 * two bytes "l4_port_range" ACL key element.
 */

 WARN_ON(max > BITS_PER_BYTE * sizeof(u16));

 pr_core = kzalloc(sizeof(*mlxsw_sp->pr_core), GFP_KERNEL);
 if (!pr_core)
  return -ENOMEM;
 mlxsw_sp->pr_core = pr_core;

 pr_core->prr_ids.max = max - 1;
 xa_init_flags(&pr_core->prr_xa, XA_FLAGS_ALLOC);

 devl_resource_occ_get_register(priv_to_devlink(core),
           MLXSW_SP_RESOURCE_PORT_RANGE_REGISTERS,
           mlxsw_sp_port_range_reg_occ_get,
           pr_core);

 return 0;
}

void mlxsw_sp_port_range_fini(struct mlxsw_sp *mlxsw_sp)
{
 struct mlxsw_sp_port_range_core *pr_core = mlxsw_sp->pr_core;

 devl_resource_occ_get_unregister(priv_to_devlink(mlxsw_sp->core),
      MLXSW_SP_RESOURCE_PORT_RANGE_REGISTERS);
 WARN_ON(!xa_empty(&pr_core->prr_xa));
 xa_destroy(&pr_core->prr_xa);
 kfree(pr_core);
}

Messung V0.5
C=99 H=96 G=97

¤ Dauer der Verarbeitung: 0.0 Sekunden  (vorverarbeitet)  ¤

*© 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.