forked from Minki/linux
mlxsw: spectrum_router: Add private neigh table
We need to hold some private data for every neigh entry. It would be possible to do it using neigh_priv_len/ndo_neigh_construct/ ndo_neigh_destroy however only for the port device itself. That would not work for stacked devices like bridge/team/bond. So introduce a private neigh table. Hook onto ndos neigh_construct/destroy and add/remove table entry according to that. Signed-off-by: Jiri Pirko <jiri@mellanox.com> Reviewed-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
18bfb924f0
commit
6cf3c971dc
@ -803,6 +803,8 @@ static const struct net_device_ops mlxsw_sp_port_netdev_ops = {
|
||||
.ndo_get_stats64 = mlxsw_sp_port_get_stats64,
|
||||
.ndo_vlan_rx_add_vid = mlxsw_sp_port_add_vid,
|
||||
.ndo_vlan_rx_kill_vid = mlxsw_sp_port_kill_vid,
|
||||
.ndo_neigh_construct = mlxsw_sp_router_neigh_construct,
|
||||
.ndo_neigh_destroy = mlxsw_sp_router_neigh_destroy,
|
||||
.ndo_fdb_add = switchdev_port_fdb_add,
|
||||
.ndo_fdb_del = switchdev_port_fdb_del,
|
||||
.ndo_fdb_dump = switchdev_port_fdb_dump,
|
||||
|
@ -39,6 +39,7 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/rhashtable.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/list.h>
|
||||
@ -212,6 +213,7 @@ struct mlxsw_sp_vr {
|
||||
struct mlxsw_sp_router {
|
||||
struct mlxsw_sp_lpm_tree lpm_trees[MLXSW_SP_LPM_TREE_COUNT];
|
||||
struct mlxsw_sp_vr vrs[MLXSW_SP_VIRTUAL_ROUTER_MAX];
|
||||
struct rhashtable neigh_ht;
|
||||
};
|
||||
|
||||
struct mlxsw_sp {
|
||||
@ -524,5 +526,9 @@ int mlxsw_sp_router_fib4_add(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
struct switchdev_trans *trans);
|
||||
int mlxsw_sp_router_fib4_del(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
const struct switchdev_obj_ipv4_fib *fib4);
|
||||
int mlxsw_sp_router_neigh_construct(struct net_device *dev,
|
||||
struct neighbour *n);
|
||||
void mlxsw_sp_router_neigh_destroy(struct net_device *dev,
|
||||
struct neighbour *n);
|
||||
|
||||
#endif
|
||||
|
@ -38,6 +38,8 @@
|
||||
#include <linux/rhashtable.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/in6.h>
|
||||
#include <net/neighbour.h>
|
||||
#include <net/arp.h>
|
||||
|
||||
#include "spectrum.h"
|
||||
#include "core.h"
|
||||
@ -544,6 +546,147 @@ static void mlxsw_sp_vrs_init(struct mlxsw_sp *mlxsw_sp)
|
||||
}
|
||||
}
|
||||
|
||||
struct mlxsw_sp_neigh_key {
|
||||
unsigned char addr[sizeof(struct in6_addr)];
|
||||
struct net_device *dev;
|
||||
};
|
||||
|
||||
struct mlxsw_sp_neigh_entry {
|
||||
struct rhash_head ht_node;
|
||||
struct mlxsw_sp_neigh_key key;
|
||||
u16 rif;
|
||||
struct neighbour *n;
|
||||
};
|
||||
|
||||
static const struct rhashtable_params mlxsw_sp_neigh_ht_params = {
|
||||
.key_offset = offsetof(struct mlxsw_sp_neigh_entry, key),
|
||||
.head_offset = offsetof(struct mlxsw_sp_neigh_entry, ht_node),
|
||||
.key_len = sizeof(struct mlxsw_sp_neigh_key),
|
||||
};
|
||||
|
||||
static int
|
||||
mlxsw_sp_neigh_entry_insert(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_neigh_entry *neigh_entry)
|
||||
{
|
||||
return rhashtable_insert_fast(&mlxsw_sp->router.neigh_ht,
|
||||
&neigh_entry->ht_node,
|
||||
mlxsw_sp_neigh_ht_params);
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_sp_neigh_entry_remove(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_neigh_entry *neigh_entry)
|
||||
{
|
||||
rhashtable_remove_fast(&mlxsw_sp->router.neigh_ht,
|
||||
&neigh_entry->ht_node,
|
||||
mlxsw_sp_neigh_ht_params);
|
||||
}
|
||||
|
||||
static struct mlxsw_sp_neigh_entry *
|
||||
mlxsw_sp_neigh_entry_create(const void *addr, size_t addr_len,
|
||||
struct net_device *dev, u16 rif,
|
||||
struct neighbour *n)
|
||||
{
|
||||
struct mlxsw_sp_neigh_entry *neigh_entry;
|
||||
|
||||
neigh_entry = kzalloc(sizeof(*neigh_entry), GFP_ATOMIC);
|
||||
if (!neigh_entry)
|
||||
return NULL;
|
||||
memcpy(neigh_entry->key.addr, addr, addr_len);
|
||||
neigh_entry->key.dev = dev;
|
||||
neigh_entry->rif = rif;
|
||||
neigh_entry->n = n;
|
||||
return neigh_entry;
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_sp_neigh_entry_destroy(struct mlxsw_sp_neigh_entry *neigh_entry)
|
||||
{
|
||||
kfree(neigh_entry);
|
||||
}
|
||||
|
||||
static struct mlxsw_sp_neigh_entry *
|
||||
mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp *mlxsw_sp, const void *addr,
|
||||
size_t addr_len, struct net_device *dev)
|
||||
{
|
||||
struct mlxsw_sp_neigh_key key = {{ 0 } };
|
||||
|
||||
memcpy(key.addr, addr, addr_len);
|
||||
key.dev = dev;
|
||||
return rhashtable_lookup_fast(&mlxsw_sp->router.neigh_ht,
|
||||
&key, mlxsw_sp_neigh_ht_params);
|
||||
}
|
||||
|
||||
int mlxsw_sp_router_neigh_construct(struct net_device *dev,
|
||||
struct neighbour *n)
|
||||
{
|
||||
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||
struct mlxsw_sp_neigh_entry *neigh_entry;
|
||||
struct mlxsw_sp_rif *r;
|
||||
u32 dip;
|
||||
int err;
|
||||
|
||||
if (n->tbl != &arp_tbl)
|
||||
return 0;
|
||||
|
||||
dip = ntohl(*((__be32 *) n->primary_key));
|
||||
neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, &dip, sizeof(dip),
|
||||
n->dev);
|
||||
if (neigh_entry) {
|
||||
WARN_ON(neigh_entry->n != n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
|
||||
if (WARN_ON(!r))
|
||||
return -EINVAL;
|
||||
|
||||
neigh_entry = mlxsw_sp_neigh_entry_create(&dip, sizeof(dip), n->dev,
|
||||
r->rif, n);
|
||||
if (!neigh_entry)
|
||||
return -ENOMEM;
|
||||
err = mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry);
|
||||
if (err)
|
||||
goto err_neigh_entry_insert;
|
||||
return 0;
|
||||
|
||||
err_neigh_entry_insert:
|
||||
mlxsw_sp_neigh_entry_destroy(neigh_entry);
|
||||
return err;
|
||||
}
|
||||
|
||||
void mlxsw_sp_router_neigh_destroy(struct net_device *dev,
|
||||
struct neighbour *n)
|
||||
{
|
||||
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||
struct mlxsw_sp_neigh_entry *neigh_entry;
|
||||
u32 dip;
|
||||
|
||||
if (n->tbl != &arp_tbl)
|
||||
return;
|
||||
|
||||
dip = ntohl(*((__be32 *) n->primary_key));
|
||||
neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, &dip, sizeof(dip),
|
||||
n->dev);
|
||||
if (!neigh_entry)
|
||||
return;
|
||||
mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry);
|
||||
mlxsw_sp_neigh_entry_destroy(neigh_entry);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_neigh_init(struct mlxsw_sp *mlxsw_sp)
|
||||
{
|
||||
return rhashtable_init(&mlxsw_sp->router.neigh_ht,
|
||||
&mlxsw_sp_neigh_ht_params);
|
||||
}
|
||||
|
||||
static void mlxsw_sp_neigh_fini(struct mlxsw_sp *mlxsw_sp)
|
||||
{
|
||||
rhashtable_destroy(&mlxsw_sp->router.neigh_ht);
|
||||
}
|
||||
|
||||
static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
|
||||
{
|
||||
char rgcr_pl[MLXSW_REG_RGCR_LEN];
|
||||
@ -570,11 +713,12 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
|
||||
return err;
|
||||
mlxsw_sp_lpm_init(mlxsw_sp);
|
||||
mlxsw_sp_vrs_init(mlxsw_sp);
|
||||
return 0;
|
||||
return mlxsw_sp_neigh_init(mlxsw_sp);
|
||||
}
|
||||
|
||||
void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
|
||||
{
|
||||
mlxsw_sp_neigh_fini(mlxsw_sp);
|
||||
__mlxsw_sp_router_fini(mlxsw_sp);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user