Skip to content

Commit

Permalink
mlxsw: spectrum: Add hash table for IPv6 address mapping
Browse files Browse the repository at this point in the history
The device supports forwarding entries such as routes and FDBs that
perform tunnel (e.g., VXLAN, IP-in-IP) encapsulation or decapsulation.
When the underlay is IPv6, these entries do not encode the 128 bit IPv6
address used for encapsulation / decapsulation. Instead, these entries
encode a 24 bit pointer to an array called KVDL where the IPv6 address
is stored.

Currently, only IP-in-IP with IPv6 underlay is supported, but subsequent
patches will add support for VxLAN with IPv6 underlay. To avoid
duplicating the logic required to store and retrieve these IPv6
addresses, introduce a hash table that will store the mapping between
IPv6 addresses and their KVDL index.

Signed-off-by: Amit Cohen <amcohen@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Amit Cohen authored and davem330 committed Dec 15, 2021
1 parent f71f1bc commit e846efe
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 0 deletions.
143 changes: 143 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.c
Original file line number Diff line number Diff line change
Expand Up @@ -2755,6 +2755,140 @@ static void mlxsw_sp_parsing_fini(struct mlxsw_sp *mlxsw_sp)
mutex_destroy(&mlxsw_sp->parsing.lock);
}

struct mlxsw_sp_ipv6_addr_node {
struct in6_addr key;
struct rhash_head ht_node;
u32 kvdl_index;
refcount_t refcount;
};

static const struct rhashtable_params mlxsw_sp_ipv6_addr_ht_params = {
.key_offset = offsetof(struct mlxsw_sp_ipv6_addr_node, key),
.head_offset = offsetof(struct mlxsw_sp_ipv6_addr_node, ht_node),
.key_len = sizeof(struct in6_addr),
.automatic_shrinking = true,
};

static int
mlxsw_sp_ipv6_addr_init(struct mlxsw_sp *mlxsw_sp, const struct in6_addr *addr6,
u32 *p_kvdl_index)
{
struct mlxsw_sp_ipv6_addr_node *node;
char rips_pl[MLXSW_REG_RIPS_LEN];
int err;

err = mlxsw_sp_kvdl_alloc(mlxsw_sp,
MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,
p_kvdl_index);
if (err)
return err;

mlxsw_reg_rips_pack(rips_pl, *p_kvdl_index, addr6);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rips), rips_pl);
if (err)
goto err_rips_write;

node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!node) {
err = -ENOMEM;
goto err_node_alloc;
}

node->key = *addr6;
node->kvdl_index = *p_kvdl_index;
refcount_set(&node->refcount, 1);

err = rhashtable_insert_fast(&mlxsw_sp->ipv6_addr_ht,
&node->ht_node,
mlxsw_sp_ipv6_addr_ht_params);
if (err)
goto err_rhashtable_insert;

return 0;

err_rhashtable_insert:
kfree(node);
err_node_alloc:
err_rips_write:
mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,
*p_kvdl_index);
return err;
}

static void mlxsw_sp_ipv6_addr_fini(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipv6_addr_node *node)
{
u32 kvdl_index = node->kvdl_index;

rhashtable_remove_fast(&mlxsw_sp->ipv6_addr_ht, &node->ht_node,
mlxsw_sp_ipv6_addr_ht_params);
kfree(node);
mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,
kvdl_index);
}

int mlxsw_sp_ipv6_addr_kvdl_index_get(struct mlxsw_sp *mlxsw_sp,
const struct in6_addr *addr6,
u32 *p_kvdl_index)
{
struct mlxsw_sp_ipv6_addr_node *node;
int err = 0;

mutex_lock(&mlxsw_sp->ipv6_addr_ht_lock);
node = rhashtable_lookup_fast(&mlxsw_sp->ipv6_addr_ht, addr6,
mlxsw_sp_ipv6_addr_ht_params);
if (node) {
refcount_inc(&node->refcount);
*p_kvdl_index = node->kvdl_index;
goto out_unlock;
}

err = mlxsw_sp_ipv6_addr_init(mlxsw_sp, addr6, p_kvdl_index);

out_unlock:
mutex_unlock(&mlxsw_sp->ipv6_addr_ht_lock);
return err;
}

void
mlxsw_sp_ipv6_addr_put(struct mlxsw_sp *mlxsw_sp, const struct in6_addr *addr6)
{
struct mlxsw_sp_ipv6_addr_node *node;

mutex_lock(&mlxsw_sp->ipv6_addr_ht_lock);
node = rhashtable_lookup_fast(&mlxsw_sp->ipv6_addr_ht, addr6,
mlxsw_sp_ipv6_addr_ht_params);
if (WARN_ON(!node))
goto out_unlock;

if (!refcount_dec_and_test(&node->refcount))
goto out_unlock;

mlxsw_sp_ipv6_addr_fini(mlxsw_sp, node);

out_unlock:
mutex_unlock(&mlxsw_sp->ipv6_addr_ht_lock);
}

static int mlxsw_sp_ipv6_addr_ht_init(struct mlxsw_sp *mlxsw_sp)
{
int err;

err = rhashtable_init(&mlxsw_sp->ipv6_addr_ht,
&mlxsw_sp_ipv6_addr_ht_params);
if (err)
return err;

mutex_init(&mlxsw_sp->ipv6_addr_ht_lock);
return 0;
}

static void mlxsw_sp_ipv6_addr_ht_fini(struct mlxsw_sp *mlxsw_sp)
{
mutex_destroy(&mlxsw_sp->ipv6_addr_ht_lock);
rhashtable_destroy(&mlxsw_sp->ipv6_addr_ht);
}

static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
const struct mlxsw_bus_info *mlxsw_bus_info,
struct netlink_ext_ack *extack)
Expand Down Expand Up @@ -2843,6 +2977,12 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
goto err_afa_init;
}

err = mlxsw_sp_ipv6_addr_ht_init(mlxsw_sp);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize hash table for IPv6 addresses\n");
goto err_ipv6_addr_ht_init;
}

err = mlxsw_sp_nve_init(mlxsw_sp);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize NVE\n");
Expand Down Expand Up @@ -2944,6 +3084,8 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
err_acl_init:
mlxsw_sp_nve_fini(mlxsw_sp);
err_nve_init:
mlxsw_sp_ipv6_addr_ht_fini(mlxsw_sp);
err_ipv6_addr_ht_init:
mlxsw_sp_afa_fini(mlxsw_sp);
err_afa_init:
mlxsw_sp_counter_pool_fini(mlxsw_sp);
Expand Down Expand Up @@ -3075,6 +3217,7 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)
mlxsw_sp_router_fini(mlxsw_sp);
mlxsw_sp_acl_fini(mlxsw_sp);
mlxsw_sp_nve_fini(mlxsw_sp);
mlxsw_sp_ipv6_addr_ht_fini(mlxsw_sp);
mlxsw_sp_afa_fini(mlxsw_sp);
mlxsw_sp_counter_pool_fini(mlxsw_sp);
mlxsw_sp_switchdev_fini(mlxsw_sp);
Expand Down
7 changes: 7 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ struct mlxsw_sp {
const struct mlxsw_listener *listeners;
size_t listeners_count;
u32 lowest_shaper_bs;
struct rhashtable ipv6_addr_ht;
struct mutex ipv6_addr_ht_lock; /* Protects ipv6_addr_ht */
};

struct mlxsw_sp_ptp_ops {
Expand Down Expand Up @@ -587,6 +589,11 @@ mlxsw_sp_sample_trigger_params_set(struct mlxsw_sp *mlxsw_sp,
void
mlxsw_sp_sample_trigger_params_unset(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_sample_trigger *trigger);
int mlxsw_sp_ipv6_addr_kvdl_index_get(struct mlxsw_sp *mlxsw_sp,
const struct in6_addr *addr6,
u32 *p_kvdl_index);
void
mlxsw_sp_ipv6_addr_put(struct mlxsw_sp *mlxsw_sp, const struct in6_addr *addr6);

extern const struct mlxsw_sp_sb_vals mlxsw_sp1_sb_vals;
extern const struct mlxsw_sp_sb_vals mlxsw_sp2_sb_vals;
Expand Down

0 comments on commit e846efe

Please sign in to comment.