// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
#include <linux/err.h>
#include <linux/gfp.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/slab.h>
#include <net/inet_ecn.h>
#include <net/ipv6.h>
#include "reg.h"
#include "spectrum.h"
#include "spectrum_nve.h"
const struct mlxsw_sp_nve_ops *mlxsw_sp1_nve_ops_arr[] = {
[MLXSW_SP_NVE_TYPE_VXLAN] = &mlxsw_sp1_nve_vxlan_ops,
};
const struct mlxsw_sp_nve_ops *mlxsw_sp2_nve_ops_arr[] = {
[MLXSW_SP_NVE_TYPE_VXLAN] = &mlxsw_sp2_nve_vxlan_ops,
};
struct mlxsw_sp_nve_mc_entry;
struct mlxsw_sp_nve_mc_record;
struct mlxsw_sp_nve_mc_list;
struct mlxsw_sp_nve_mc_record_ops {
enum mlxsw_reg_tnumt_record_type type;
int (*entry_add)(struct mlxsw_sp_nve_mc_record *mc_record,
struct mlxsw_sp_nve_mc_entry *mc_entry,
const union mlxsw_sp_l3addr *addr);
void (*entry_del)(const struct mlxsw_sp_nve_mc_record *mc_record,
const struct mlxsw_sp_nve_mc_entry *mc_entry);
void (*entry_set)(const struct mlxsw_sp_nve_mc_record *mc_record,
const struct mlxsw_sp_nve_mc_entry *mc_entry,
char *tnumt_pl, unsigned int entry_index);
bool (*entry_compare)(const struct mlxsw_sp_nve_mc_record *mc_record,
const struct mlxsw_sp_nve_mc_entry *mc_entry,
const union mlxsw_sp_l3addr *addr);
};
struct mlxsw_sp_nve_mc_list_key {
u16 fid_index;
};
struct mlxsw_sp_nve_mc_ipv6_entry {
struct in6_addr addr6;
u32 addr6_kvdl_index;
};
struct mlxsw_sp_nve_mc_entry {
union {
__be32 addr4;
struct mlxsw_sp_nve_mc_ipv6_entry ipv6_entry;
};
u8 valid:1;
};
struct mlxsw_sp_nve_mc_record {
struct list_head list;
enum mlxsw_sp_l3proto proto;
unsigned int num_entries;
struct mlxsw_sp *mlxsw_sp;
struct mlxsw_sp_nve_mc_list *mc_list;
const struct mlxsw_sp_nve_mc_record_ops *ops;
u32 kvdl_index;
struct mlxsw_sp_nve_mc_entry entries[0];
};
struct mlxsw_sp_nve_mc_list {
struct list_head records_list;
struct rhash_head ht_node;
struct mlxsw_sp_nve_mc_list_key key;
};
static const struct rhashtable_params mlxsw_sp_nve_mc_list_ht_params = {
.key_len = sizeof(struct mlxsw_sp_nve_mc_list_key),
.key_offset = offsetof(struct mlxsw_sp_nve_mc_list, key),
.head_offset = offsetof(struct mlxsw_sp_nve_mc_list, ht_node),
};
static int
mlxsw_sp_nve_mc_record_ipv4_entry_add(struct mlxsw_sp_nve_mc_record *mc_record,
struct mlxsw_sp_nve_mc_entry *mc_entry,
const union mlxsw_sp_l3addr *addr)
{
mc_entry->addr4 = addr->addr4;
return 0;
}
static void
mlxsw_sp_nve_mc_record_ipv4_entry_del(const struct mlxsw_sp_nve_mc_record *mc_record,
const struct mlxsw_sp_nve_mc_entry *mc_entry)
{
}
static void
mlxsw_sp_nve_mc_record_ipv4_entry_set(const struct mlxsw_sp_nve_mc_record *mc_record,
const struct mlxsw_sp_nve_mc_entry *mc_entry,
char *tnumt_pl, unsigned int entry_index)
{
u32 udip = be32_to_cpu(mc_entry->addr4);
mlxsw_reg_tnumt_udip_set(tnumt_pl, entry_index, udip);
}
static bool
mlxsw_sp_nve_mc_record_ipv4_entry_compare(const struct mlxsw_sp_nve_mc_record *mc_record,
const struct mlxsw_sp_nve_mc_entry *mc_entry,
const union mlxsw_sp_l3addr *addr)
{
return mc_entry->addr4 == addr->addr4;
}
static const struct mlxsw_sp_nve_mc_record_ops
mlxsw_sp_nve_mc_record_ipv4_ops = {
.type = MLXSW_REG_TNUMT_RECORD_TYPE_IPV4,
.entry_add = &mlxsw_sp_nve_mc_record_ipv4_entry_add,
.entry_del = &mlxsw_sp_nve_mc_record_ipv4_entry_del,
.entry_set = &mlxsw_sp_nve_mc_record_ipv4_entry_set,
.entry_compare = &mlxsw_sp_nve_mc_record_ipv4_entry_compare,
};
static int
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);
return -EINVAL;