Commit ab8c83cf authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mlxsw-ipv6-underlay'



Ido Schimmel says:

====================
mlxsw: Add support for VxLAN with IPv6 underlay

So far, mlxsw only supported VxLAN with IPv4 underlay. This patchset
extends mlxsw to also support VxLAN with IPv6 underlay. The main
difference is related to the way IPv6 addresses are handled by the
device. See patch #1 for a detailed explanation.

Patch #1 creates a common hash table to store the mapping from IPv6
addresses to KVDL indexes. This table is useful for both IP-in-IP and
VxLAN tunnels with an IPv6 underlay.

Patch #2 converts the IP-in-IP code to use the new hash table.

Patches #3-#6 are preparations.

Patch #7 finally adds support for VxLAN with IPv6 underlay.

Patch #8 removes a test case that checked that VxLAN configurations with
IPv6 underlay are vetoed by the driver.

A follow-up patchset will add forwarding selftests.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f71f1bcb fb488be8
Loading
Loading
Loading
Loading
+27 −3
Original line number Diff line number Diff line
@@ -504,19 +504,43 @@ static inline void
mlxsw_reg_sfd_uc_tunnel_pack(char *payload, int rec_index,
			     enum mlxsw_reg_sfd_rec_policy policy,
			     const char *mac, u16 fid,
			     enum mlxsw_reg_sfd_rec_action action, u32 uip,
			     enum mlxsw_reg_sfd_rec_action action,
			     enum mlxsw_reg_sfd_uc_tunnel_protocol proto)
{
	mlxsw_reg_sfd_rec_pack(payload, rec_index,
			       MLXSW_REG_SFD_REC_TYPE_UNICAST_TUNNEL, mac,
			       action);
	mlxsw_reg_sfd_rec_policy_set(payload, rec_index, policy);
	mlxsw_reg_sfd_uc_tunnel_uip_msb_set(payload, rec_index, uip >> 24);
	mlxsw_reg_sfd_uc_tunnel_uip_lsb_set(payload, rec_index, uip);
	mlxsw_reg_sfd_uc_tunnel_fid_set(payload, rec_index, fid);
	mlxsw_reg_sfd_uc_tunnel_protocol_set(payload, rec_index, proto);
}

static inline void
mlxsw_reg_sfd_uc_tunnel_pack4(char *payload, int rec_index,
			      enum mlxsw_reg_sfd_rec_policy policy,
			      const char *mac, u16 fid,
			      enum mlxsw_reg_sfd_rec_action action, u32 uip)
{
	mlxsw_reg_sfd_uc_tunnel_uip_msb_set(payload, rec_index, uip >> 24);
	mlxsw_reg_sfd_uc_tunnel_uip_lsb_set(payload, rec_index, uip);
	mlxsw_reg_sfd_uc_tunnel_pack(payload, rec_index, policy, mac, fid,
				     action,
				     MLXSW_REG_SFD_UC_TUNNEL_PROTOCOL_IPV4);
}

static inline void
mlxsw_reg_sfd_uc_tunnel_pack6(char *payload, int rec_index, const char *mac,
			      u16 fid, enum mlxsw_reg_sfd_rec_action action,
			      u32 uip_ptr)
{
	mlxsw_reg_sfd_uc_tunnel_uip_lsb_set(payload, rec_index, uip_ptr);
	/* Only static policy is supported for IPv6 unicast tunnel entry. */
	mlxsw_reg_sfd_uc_tunnel_pack(payload, rec_index,
				     MLXSW_REG_SFD_REC_POLICY_STATIC_ENTRY,
				     mac, fid, action,
				     MLXSW_REG_SFD_UC_TUNNEL_PROTOCOL_IPV6);
}

enum mlxsw_reg_tunnel_port {
	MLXSW_REG_TUNNEL_PORT_NVE,
	MLXSW_REG_TUNNEL_PORT_VPLS,
+143 −0
Original line number Diff line number Diff line
@@ -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)
@@ -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");
@@ -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);
@@ -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);
+18 −0
Original line number Diff line number Diff line
@@ -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 {
@@ -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;
@@ -1310,6 +1317,17 @@ void mlxsw_sp_nve_flood_ip_del(struct mlxsw_sp *mlxsw_sp,
			       struct mlxsw_sp_fid *fid,
			       enum mlxsw_sp_l3proto proto,
			       union mlxsw_sp_l3addr *addr);
int mlxsw_sp_nve_ipv6_addr_kvdl_set(struct mlxsw_sp *mlxsw_sp,
				    const struct in6_addr *addr6,
				    u32 *p_kvdl_index);
void mlxsw_sp_nve_ipv6_addr_kvdl_unset(struct mlxsw_sp *mlxsw_sp,
				       const struct in6_addr *addr6);
int
mlxsw_sp_nve_ipv6_addr_map_replace(struct mlxsw_sp *mlxsw_sp, const char *mac,
				   u16 fid_index,
				   const struct in6_addr *new_addr6);
void mlxsw_sp_nve_ipv6_addr_map_del(struct mlxsw_sp *mlxsw_sp, const char *mac,
				    u16 fid_index);
int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid,
			    struct mlxsw_sp_nve_params *params,
			    struct netlink_ext_ack *extack);
+6 −22
Original line number Diff line number Diff line
@@ -568,37 +568,21 @@ static int
mlxsw_sp2_ipip_rem_addr_set_gre6(struct mlxsw_sp *mlxsw_sp,
				 struct mlxsw_sp_ipip_entry *ipip_entry)
{
	char rips_pl[MLXSW_REG_RIPS_LEN];
	struct __ip6_tnl_parm parms6;
	int err;

	err = mlxsw_sp_kvdl_alloc(mlxsw_sp,
				  MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,
				  &ipip_entry->dip_kvdl_index);
	if (err)
		return err;

	parms6 = mlxsw_sp_ipip_netdev_parms6(ipip_entry->ol_dev);
	mlxsw_reg_rips_pack(rips_pl, ipip_entry->dip_kvdl_index,
			    &parms6.raddr);
	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rips), rips_pl);
	if (err)
		goto err_rips_write;

	return 0;

err_rips_write:
	mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,
			   ipip_entry->dip_kvdl_index);
	return err;
	return mlxsw_sp_ipv6_addr_kvdl_index_get(mlxsw_sp, &parms6.raddr,
						 &ipip_entry->dip_kvdl_index);
}

static void
mlxsw_sp2_ipip_rem_addr_unset_gre6(struct mlxsw_sp *mlxsw_sp,
				   const struct mlxsw_sp_ipip_entry *ipip_entry)
{
	mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,
			   ipip_entry->dip_kvdl_index);
	struct __ip6_tnl_parm parms6;

	parms6 = mlxsw_sp_ipip_netdev_parms6(ipip_entry->ol_dev);
	mlxsw_sp_ipv6_addr_put(mlxsw_sp, &parms6.raddr);
}

static const struct mlxsw_sp_ipip_ops mlxsw_sp2_ipip_gre6_ops = {
+161 −4
Original line number Diff line number Diff line
@@ -130,15 +130,25 @@ mlxsw_sp_nve_mc_record_ipv6_entry_add(struct mlxsw_sp_nve_mc_record *mc_record,
				      struct mlxsw_sp_nve_mc_entry *mc_entry,
				      const union mlxsw_sp_l3addr *addr)
{
	WARN_ON(1);
	u32 kvdl_index;
	int err;

	return -EINVAL;
	err = mlxsw_sp_ipv6_addr_kvdl_index_get(mc_record->mlxsw_sp,
						&addr->addr6, &kvdl_index);
	if (err)
		return err;

	mc_entry->ipv6_entry.addr6 = addr->addr6;
	mc_entry->ipv6_entry.addr6_kvdl_index = kvdl_index;
	return 0;
}

static void
mlxsw_sp_nve_mc_record_ipv6_entry_del(const struct mlxsw_sp_nve_mc_record *mc_record,
				      const struct mlxsw_sp_nve_mc_entry *mc_entry)
{
	mlxsw_sp_ipv6_addr_put(mc_record->mlxsw_sp,
			       &mc_entry->ipv6_entry.addr6);
}

static void
@@ -787,6 +797,142 @@ static void mlxsw_sp_nve_fdb_clear_offload(struct mlxsw_sp *mlxsw_sp,
	ops->fdb_clear_offload(nve_dev, vni);
}

struct mlxsw_sp_nve_ipv6_ht_key {
	u8 mac[ETH_ALEN];
	u16 fid_index;
};

struct mlxsw_sp_nve_ipv6_ht_node {
	struct rhash_head ht_node;
	struct list_head list;
	struct mlxsw_sp_nve_ipv6_ht_key key;
	struct in6_addr addr6;
};

static const struct rhashtable_params mlxsw_sp_nve_ipv6_ht_params = {
	.key_len = sizeof(struct mlxsw_sp_nve_ipv6_ht_key),
	.key_offset = offsetof(struct mlxsw_sp_nve_ipv6_ht_node, key),
	.head_offset = offsetof(struct mlxsw_sp_nve_ipv6_ht_node, ht_node),
};

int mlxsw_sp_nve_ipv6_addr_kvdl_set(struct mlxsw_sp *mlxsw_sp,
				    const struct in6_addr *addr6,
				    u32 *p_kvdl_index)
{
	return mlxsw_sp_ipv6_addr_kvdl_index_get(mlxsw_sp, addr6, p_kvdl_index);
}

void mlxsw_sp_nve_ipv6_addr_kvdl_unset(struct mlxsw_sp *mlxsw_sp,
				       const struct in6_addr *addr6)
{
	mlxsw_sp_ipv6_addr_put(mlxsw_sp, addr6);
}

static struct mlxsw_sp_nve_ipv6_ht_node *
mlxsw_sp_nve_ipv6_ht_node_lookup(struct mlxsw_sp *mlxsw_sp, const char *mac,
				 u16 fid_index)
{
	struct mlxsw_sp_nve_ipv6_ht_key key = {};

	ether_addr_copy(key.mac, mac);
	key.fid_index = fid_index;
	return rhashtable_lookup_fast(&mlxsw_sp->nve->ipv6_ht, &key,
				      mlxsw_sp_nve_ipv6_ht_params);
}

static int mlxsw_sp_nve_ipv6_ht_insert(struct mlxsw_sp *mlxsw_sp,
				       const char *mac, u16 fid_index,
				       const struct in6_addr *addr6)
{
	struct mlxsw_sp_nve_ipv6_ht_node *ipv6_ht_node;
	struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
	int err;

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

	ether_addr_copy(ipv6_ht_node->key.mac, mac);
	ipv6_ht_node->key.fid_index = fid_index;
	ipv6_ht_node->addr6 = *addr6;

	err = rhashtable_insert_fast(&nve->ipv6_ht, &ipv6_ht_node->ht_node,
				     mlxsw_sp_nve_ipv6_ht_params);
	if (err)
		goto err_rhashtable_insert;

	list_add(&ipv6_ht_node->list, &nve->ipv6_addr_list);

	return 0;

err_rhashtable_insert:
	kfree(ipv6_ht_node);
	return err;
}

static void
mlxsw_sp_nve_ipv6_ht_remove(struct mlxsw_sp *mlxsw_sp,
			    struct mlxsw_sp_nve_ipv6_ht_node *ipv6_ht_node)
{
	struct mlxsw_sp_nve *nve = mlxsw_sp->nve;

	list_del(&ipv6_ht_node->list);
	rhashtable_remove_fast(&nve->ipv6_ht, &ipv6_ht_node->ht_node,
			       mlxsw_sp_nve_ipv6_ht_params);
	kfree(ipv6_ht_node);
}

int
mlxsw_sp_nve_ipv6_addr_map_replace(struct mlxsw_sp *mlxsw_sp, const char *mac,
				   u16 fid_index,
				   const struct in6_addr *new_addr6)
{
	struct mlxsw_sp_nve_ipv6_ht_node *ipv6_ht_node;

	ASSERT_RTNL();

	ipv6_ht_node = mlxsw_sp_nve_ipv6_ht_node_lookup(mlxsw_sp, mac,
							fid_index);
	if (!ipv6_ht_node)
		return mlxsw_sp_nve_ipv6_ht_insert(mlxsw_sp, mac, fid_index,
						   new_addr6);

	mlxsw_sp_ipv6_addr_put(mlxsw_sp, &ipv6_ht_node->addr6);
	ipv6_ht_node->addr6 = *new_addr6;
	return 0;
}

void mlxsw_sp_nve_ipv6_addr_map_del(struct mlxsw_sp *mlxsw_sp, const char *mac,
				    u16 fid_index)
{
	struct mlxsw_sp_nve_ipv6_ht_node *ipv6_ht_node;

	ASSERT_RTNL();

	ipv6_ht_node = mlxsw_sp_nve_ipv6_ht_node_lookup(mlxsw_sp, mac,
							fid_index);
	if (WARN_ON(!ipv6_ht_node))
		return;

	mlxsw_sp_nve_ipv6_ht_remove(mlxsw_sp, ipv6_ht_node);
}

static void mlxsw_sp_nve_ipv6_addr_flush_by_fid(struct mlxsw_sp *mlxsw_sp,
						u16 fid_index)
{
	struct mlxsw_sp_nve_ipv6_ht_node *ipv6_ht_node, *tmp;
	struct mlxsw_sp_nve *nve = mlxsw_sp->nve;

	list_for_each_entry_safe(ipv6_ht_node, tmp, &nve->ipv6_addr_list,
				 list) {
		if (ipv6_ht_node->key.fid_index != fid_index)
			continue;

		mlxsw_sp_ipv6_addr_put(mlxsw_sp, &ipv6_ht_node->addr6);
		mlxsw_sp_nve_ipv6_ht_remove(mlxsw_sp, ipv6_ht_node);
	}
}

int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid,
			    struct mlxsw_sp_nve_params *params,
			    struct netlink_ext_ack *extack)
@@ -845,6 +991,7 @@ void mlxsw_sp_nve_fid_disable(struct mlxsw_sp *mlxsw_sp,

	mlxsw_sp_nve_flood_ip_flush(mlxsw_sp, fid);
	mlxsw_sp_nve_fdb_flush_by_fid(mlxsw_sp, fid_index);
	mlxsw_sp_nve_ipv6_addr_flush_by_fid(mlxsw_sp, fid_index);

	if (WARN_ON(mlxsw_sp_fid_nve_ifindex(fid, &nve_ifindex) ||
		    mlxsw_sp_fid_vni(fid, &vni)))
@@ -981,7 +1128,13 @@ int mlxsw_sp_nve_init(struct mlxsw_sp *mlxsw_sp)
	err = rhashtable_init(&nve->mc_list_ht,
			      &mlxsw_sp_nve_mc_list_ht_params);
	if (err)
		goto err_rhashtable_init;
		goto err_mc_rhashtable_init;

	err = rhashtable_init(&nve->ipv6_ht, &mlxsw_sp_nve_ipv6_ht_params);
	if (err)
		goto err_ipv6_rhashtable_init;

	INIT_LIST_HEAD(&nve->ipv6_addr_list);

	err = mlxsw_sp_nve_qos_init(mlxsw_sp);
	if (err)
@@ -1000,8 +1153,10 @@ int mlxsw_sp_nve_init(struct mlxsw_sp *mlxsw_sp)
err_nve_resources_query:
err_nve_ecn_init:
err_nve_qos_init:
	rhashtable_destroy(&nve->ipv6_ht);
err_ipv6_rhashtable_init:
	rhashtable_destroy(&nve->mc_list_ht);
err_rhashtable_init:
err_mc_rhashtable_init:
	mlxsw_sp->nve = NULL;
	kfree(nve);
	return err;
@@ -1010,6 +1165,8 @@ int mlxsw_sp_nve_init(struct mlxsw_sp *mlxsw_sp)
void mlxsw_sp_nve_fini(struct mlxsw_sp *mlxsw_sp)
{
	WARN_ON(mlxsw_sp->nve->num_nve_tunnels);
	WARN_ON(!list_empty(&mlxsw_sp->nve->ipv6_addr_list));
	rhashtable_destroy(&mlxsw_sp->nve->ipv6_ht);
	rhashtable_destroy(&mlxsw_sp->nve->mc_list_ht);
	kfree(mlxsw_sp->nve);
	mlxsw_sp->nve = NULL;
Loading