Skip to content

Commit 6cf3c97

Browse files
jpirkodavem330
authored andcommitted
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 <[email protected]> Reviewed-by: Ido Schimmel <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 18bfb92 commit 6cf3c97

File tree

3 files changed

+153
-1
lines changed

3 files changed

+153
-1
lines changed

drivers/net/ethernet/mellanox/mlxsw/spectrum.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,8 @@ static const struct net_device_ops mlxsw_sp_port_netdev_ops = {
803803
.ndo_get_stats64 = mlxsw_sp_port_get_stats64,
804804
.ndo_vlan_rx_add_vid = mlxsw_sp_port_add_vid,
805805
.ndo_vlan_rx_kill_vid = mlxsw_sp_port_kill_vid,
806+
.ndo_neigh_construct = mlxsw_sp_router_neigh_construct,
807+
.ndo_neigh_destroy = mlxsw_sp_router_neigh_destroy,
806808
.ndo_fdb_add = switchdev_port_fdb_add,
807809
.ndo_fdb_del = switchdev_port_fdb_del,
808810
.ndo_fdb_dump = switchdev_port_fdb_dump,

drivers/net/ethernet/mellanox/mlxsw/spectrum.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
#include <linux/types.h>
4141
#include <linux/netdevice.h>
42+
#include <linux/rhashtable.h>
4243
#include <linux/bitops.h>
4344
#include <linux/if_vlan.h>
4445
#include <linux/list.h>
@@ -212,6 +213,7 @@ struct mlxsw_sp_vr {
212213
struct mlxsw_sp_router {
213214
struct mlxsw_sp_lpm_tree lpm_trees[MLXSW_SP_LPM_TREE_COUNT];
214215
struct mlxsw_sp_vr vrs[MLXSW_SP_VIRTUAL_ROUTER_MAX];
216+
struct rhashtable neigh_ht;
215217
};
216218

217219
struct mlxsw_sp {
@@ -524,5 +526,9 @@ int mlxsw_sp_router_fib4_add(struct mlxsw_sp_port *mlxsw_sp_port,
524526
struct switchdev_trans *trans);
525527
int mlxsw_sp_router_fib4_del(struct mlxsw_sp_port *mlxsw_sp_port,
526528
const struct switchdev_obj_ipv4_fib *fib4);
529+
int mlxsw_sp_router_neigh_construct(struct net_device *dev,
530+
struct neighbour *n);
531+
void mlxsw_sp_router_neigh_destroy(struct net_device *dev,
532+
struct neighbour *n);
527533

528534
#endif

drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
#include <linux/rhashtable.h>
3939
#include <linux/bitops.h>
4040
#include <linux/in6.h>
41+
#include <net/neighbour.h>
42+
#include <net/arp.h>
4143

4244
#include "spectrum.h"
4345
#include "core.h"
@@ -544,6 +546,147 @@ static void mlxsw_sp_vrs_init(struct mlxsw_sp *mlxsw_sp)
544546
}
545547
}
546548

549+
struct mlxsw_sp_neigh_key {
550+
unsigned char addr[sizeof(struct in6_addr)];
551+
struct net_device *dev;
552+
};
553+
554+
struct mlxsw_sp_neigh_entry {
555+
struct rhash_head ht_node;
556+
struct mlxsw_sp_neigh_key key;
557+
u16 rif;
558+
struct neighbour *n;
559+
};
560+
561+
static const struct rhashtable_params mlxsw_sp_neigh_ht_params = {
562+
.key_offset = offsetof(struct mlxsw_sp_neigh_entry, key),
563+
.head_offset = offsetof(struct mlxsw_sp_neigh_entry, ht_node),
564+
.key_len = sizeof(struct mlxsw_sp_neigh_key),
565+
};
566+
567+
static int
568+
mlxsw_sp_neigh_entry_insert(struct mlxsw_sp *mlxsw_sp,
569+
struct mlxsw_sp_neigh_entry *neigh_entry)
570+
{
571+
return rhashtable_insert_fast(&mlxsw_sp->router.neigh_ht,
572+
&neigh_entry->ht_node,
573+
mlxsw_sp_neigh_ht_params);
574+
}
575+
576+
static void
577+
mlxsw_sp_neigh_entry_remove(struct mlxsw_sp *mlxsw_sp,
578+
struct mlxsw_sp_neigh_entry *neigh_entry)
579+
{
580+
rhashtable_remove_fast(&mlxsw_sp->router.neigh_ht,
581+
&neigh_entry->ht_node,
582+
mlxsw_sp_neigh_ht_params);
583+
}
584+
585+
static struct mlxsw_sp_neigh_entry *
586+
mlxsw_sp_neigh_entry_create(const void *addr, size_t addr_len,
587+
struct net_device *dev, u16 rif,
588+
struct neighbour *n)
589+
{
590+
struct mlxsw_sp_neigh_entry *neigh_entry;
591+
592+
neigh_entry = kzalloc(sizeof(*neigh_entry), GFP_ATOMIC);
593+
if (!neigh_entry)
594+
return NULL;
595+
memcpy(neigh_entry->key.addr, addr, addr_len);
596+
neigh_entry->key.dev = dev;
597+
neigh_entry->rif = rif;
598+
neigh_entry->n = n;
599+
return neigh_entry;
600+
}
601+
602+
static void
603+
mlxsw_sp_neigh_entry_destroy(struct mlxsw_sp_neigh_entry *neigh_entry)
604+
{
605+
kfree(neigh_entry);
606+
}
607+
608+
static struct mlxsw_sp_neigh_entry *
609+
mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp *mlxsw_sp, const void *addr,
610+
size_t addr_len, struct net_device *dev)
611+
{
612+
struct mlxsw_sp_neigh_key key = {{ 0 } };
613+
614+
memcpy(key.addr, addr, addr_len);
615+
key.dev = dev;
616+
return rhashtable_lookup_fast(&mlxsw_sp->router.neigh_ht,
617+
&key, mlxsw_sp_neigh_ht_params);
618+
}
619+
620+
int mlxsw_sp_router_neigh_construct(struct net_device *dev,
621+
struct neighbour *n)
622+
{
623+
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
624+
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
625+
struct mlxsw_sp_neigh_entry *neigh_entry;
626+
struct mlxsw_sp_rif *r;
627+
u32 dip;
628+
int err;
629+
630+
if (n->tbl != &arp_tbl)
631+
return 0;
632+
633+
dip = ntohl(*((__be32 *) n->primary_key));
634+
neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, &dip, sizeof(dip),
635+
n->dev);
636+
if (neigh_entry) {
637+
WARN_ON(neigh_entry->n != n);
638+
return 0;
639+
}
640+
641+
r = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
642+
if (WARN_ON(!r))
643+
return -EINVAL;
644+
645+
neigh_entry = mlxsw_sp_neigh_entry_create(&dip, sizeof(dip), n->dev,
646+
r->rif, n);
647+
if (!neigh_entry)
648+
return -ENOMEM;
649+
err = mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry);
650+
if (err)
651+
goto err_neigh_entry_insert;
652+
return 0;
653+
654+
err_neigh_entry_insert:
655+
mlxsw_sp_neigh_entry_destroy(neigh_entry);
656+
return err;
657+
}
658+
659+
void mlxsw_sp_router_neigh_destroy(struct net_device *dev,
660+
struct neighbour *n)
661+
{
662+
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
663+
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
664+
struct mlxsw_sp_neigh_entry *neigh_entry;
665+
u32 dip;
666+
667+
if (n->tbl != &arp_tbl)
668+
return;
669+
670+
dip = ntohl(*((__be32 *) n->primary_key));
671+
neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, &dip, sizeof(dip),
672+
n->dev);
673+
if (!neigh_entry)
674+
return;
675+
mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry);
676+
mlxsw_sp_neigh_entry_destroy(neigh_entry);
677+
}
678+
679+
static int mlxsw_sp_neigh_init(struct mlxsw_sp *mlxsw_sp)
680+
{
681+
return rhashtable_init(&mlxsw_sp->router.neigh_ht,
682+
&mlxsw_sp_neigh_ht_params);
683+
}
684+
685+
static void mlxsw_sp_neigh_fini(struct mlxsw_sp *mlxsw_sp)
686+
{
687+
rhashtable_destroy(&mlxsw_sp->router.neigh_ht);
688+
}
689+
547690
static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
548691
{
549692
char rgcr_pl[MLXSW_REG_RGCR_LEN];
@@ -570,11 +713,12 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
570713
return err;
571714
mlxsw_sp_lpm_init(mlxsw_sp);
572715
mlxsw_sp_vrs_init(mlxsw_sp);
573-
return 0;
716+
return mlxsw_sp_neigh_init(mlxsw_sp);
574717
}
575718

576719
void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
577720
{
721+
mlxsw_sp_neigh_fini(mlxsw_sp);
578722
__mlxsw_sp_router_fini(mlxsw_sp);
579723
}
580724

0 commit comments

Comments
 (0)