|
@@ -56,6 +56,31 @@
|
|
|
#include "spectrum_dpipe.h"
|
|
|
#include "spectrum_router.h"
|
|
|
|
|
|
+struct mlxsw_sp_vr;
|
|
|
+struct mlxsw_sp_lpm_tree;
|
|
|
+
|
|
|
+struct mlxsw_sp_router {
|
|
|
+ struct mlxsw_sp *mlxsw_sp;
|
|
|
+ struct mlxsw_sp_rif **rifs;
|
|
|
+ struct mlxsw_sp_vr *vrs;
|
|
|
+ struct rhashtable neigh_ht;
|
|
|
+ struct rhashtable nexthop_group_ht;
|
|
|
+ struct rhashtable nexthop_ht;
|
|
|
+ struct {
|
|
|
+ struct mlxsw_sp_lpm_tree *trees;
|
|
|
+ unsigned int tree_count;
|
|
|
+ } lpm;
|
|
|
+ struct {
|
|
|
+ struct delayed_work dw;
|
|
|
+ unsigned long interval; /* ms */
|
|
|
+ } neighs_update;
|
|
|
+ struct delayed_work nexthop_probe_dw;
|
|
|
+#define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */
|
|
|
+ struct list_head nexthop_neighs_list;
|
|
|
+ bool aborted;
|
|
|
+ struct notifier_block fib_nb;
|
|
|
+};
|
|
|
+
|
|
|
struct mlxsw_sp_rif {
|
|
|
struct list_head nexthop_list;
|
|
|
struct list_head neigh_list;
|
|
@@ -220,6 +245,12 @@ static struct mlxsw_sp_rif *
|
|
|
mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
|
|
|
const struct net_device *dev);
|
|
|
|
|
|
+#define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE)
|
|
|
+
|
|
|
+struct mlxsw_sp_prefix_usage {
|
|
|
+ DECLARE_BITMAP(b, MLXSW_SP_PREFIX_COUNT);
|
|
|
+};
|
|
|
+
|
|
|
#define mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) \
|
|
|
for_each_set_bit(prefix, (prefix_usage)->b, MLXSW_SP_PREFIX_COUNT)
|
|
|
|
|
@@ -284,6 +315,7 @@ enum mlxsw_sp_fib_entry_type {
|
|
|
};
|
|
|
|
|
|
struct mlxsw_sp_nexthop_group;
|
|
|
+struct mlxsw_sp_fib;
|
|
|
|
|
|
struct mlxsw_sp_fib_node {
|
|
|
struct list_head entry_list;
|
|
@@ -310,6 +342,18 @@ struct mlxsw_sp_fib_entry {
|
|
|
bool offloaded;
|
|
|
};
|
|
|
|
|
|
+enum mlxsw_sp_l3proto {
|
|
|
+ MLXSW_SP_L3_PROTO_IPV4,
|
|
|
+ MLXSW_SP_L3_PROTO_IPV6,
|
|
|
+};
|
|
|
+
|
|
|
+struct mlxsw_sp_lpm_tree {
|
|
|
+ u8 id; /* tree ID */
|
|
|
+ unsigned int ref_count;
|
|
|
+ enum mlxsw_sp_l3proto proto;
|
|
|
+ struct mlxsw_sp_prefix_usage prefix_usage;
|
|
|
+};
|
|
|
+
|
|
|
struct mlxsw_sp_fib {
|
|
|
struct rhashtable ht;
|
|
|
struct list_head node_list;
|
|
@@ -320,6 +364,13 @@ struct mlxsw_sp_fib {
|
|
|
enum mlxsw_sp_l3proto proto;
|
|
|
};
|
|
|
|
|
|
+struct mlxsw_sp_vr {
|
|
|
+ u16 id; /* virtual router ID */
|
|
|
+ u32 tb_id; /* kernel fib table id */
|
|
|
+ unsigned int rif_count;
|
|
|
+ struct mlxsw_sp_fib *fib4;
|
|
|
+};
|
|
|
+
|
|
|
static const struct rhashtable_params mlxsw_sp_fib_ht_params;
|
|
|
|
|
|
static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp_vr *vr,
|
|
@@ -358,8 +409,8 @@ mlxsw_sp_lpm_tree_find_unused(struct mlxsw_sp *mlxsw_sp)
|
|
|
static struct mlxsw_sp_lpm_tree *lpm_tree;
|
|
|
int i;
|
|
|
|
|
|
- for (i = 0; i < mlxsw_sp->router.lpm.tree_count; i++) {
|
|
|
- lpm_tree = &mlxsw_sp->router.lpm.trees[i];
|
|
|
+ for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
|
|
|
+ lpm_tree = &mlxsw_sp->router->lpm.trees[i];
|
|
|
if (lpm_tree->ref_count == 0)
|
|
|
return lpm_tree;
|
|
|
}
|
|
@@ -455,8 +506,8 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp,
|
|
|
struct mlxsw_sp_lpm_tree *lpm_tree;
|
|
|
int i;
|
|
|
|
|
|
- for (i = 0; i < mlxsw_sp->router.lpm.tree_count; i++) {
|
|
|
- lpm_tree = &mlxsw_sp->router.lpm.trees[i];
|
|
|
+ for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
|
|
|
+ lpm_tree = &mlxsw_sp->router->lpm.trees[i];
|
|
|
if (lpm_tree->ref_count != 0 &&
|
|
|
lpm_tree->proto == proto &&
|
|
|
mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage,
|
|
@@ -493,15 +544,15 @@ static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp)
|
|
|
return -EIO;
|
|
|
|
|
|
max_trees = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_LPM_TREES);
|
|
|
- mlxsw_sp->router.lpm.tree_count = max_trees - MLXSW_SP_LPM_TREE_MIN;
|
|
|
- mlxsw_sp->router.lpm.trees = kcalloc(mlxsw_sp->router.lpm.tree_count,
|
|
|
+ mlxsw_sp->router->lpm.tree_count = max_trees - MLXSW_SP_LPM_TREE_MIN;
|
|
|
+ mlxsw_sp->router->lpm.trees = kcalloc(mlxsw_sp->router->lpm.tree_count,
|
|
|
sizeof(struct mlxsw_sp_lpm_tree),
|
|
|
GFP_KERNEL);
|
|
|
- if (!mlxsw_sp->router.lpm.trees)
|
|
|
+ if (!mlxsw_sp->router->lpm.trees)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- for (i = 0; i < mlxsw_sp->router.lpm.tree_count; i++) {
|
|
|
- lpm_tree = &mlxsw_sp->router.lpm.trees[i];
|
|
|
+ for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
|
|
|
+ lpm_tree = &mlxsw_sp->router->lpm.trees[i];
|
|
|
lpm_tree->id = i + MLXSW_SP_LPM_TREE_MIN;
|
|
|
}
|
|
|
|
|
@@ -510,7 +561,7 @@ static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp)
|
|
|
|
|
|
static void mlxsw_sp_lpm_fini(struct mlxsw_sp *mlxsw_sp)
|
|
|
{
|
|
|
- kfree(mlxsw_sp->router.lpm.trees);
|
|
|
+ kfree(mlxsw_sp->router->lpm.trees);
|
|
|
}
|
|
|
|
|
|
static bool mlxsw_sp_vr_is_used(const struct mlxsw_sp_vr *vr)
|
|
@@ -524,7 +575,7 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_find_unused(struct mlxsw_sp *mlxsw_sp)
|
|
|
int i;
|
|
|
|
|
|
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
|
|
|
- vr = &mlxsw_sp->router.vrs[i];
|
|
|
+ vr = &mlxsw_sp->router->vrs[i];
|
|
|
if (!mlxsw_sp_vr_is_used(vr))
|
|
|
return vr;
|
|
|
}
|
|
@@ -570,7 +621,7 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_find(struct mlxsw_sp *mlxsw_sp,
|
|
|
tb_id = mlxsw_sp_fix_tb_id(tb_id);
|
|
|
|
|
|
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
|
|
|
- vr = &mlxsw_sp->router.vrs[i];
|
|
|
+ vr = &mlxsw_sp->router->vrs[i];
|
|
|
if (mlxsw_sp_vr_is_used(vr) && vr->tb_id == tb_id)
|
|
|
return vr;
|
|
|
}
|
|
@@ -677,13 +728,13 @@ static int mlxsw_sp_vrs_init(struct mlxsw_sp *mlxsw_sp)
|
|
|
return -EIO;
|
|
|
|
|
|
max_vrs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS);
|
|
|
- mlxsw_sp->router.vrs = kcalloc(max_vrs, sizeof(struct mlxsw_sp_vr),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!mlxsw_sp->router.vrs)
|
|
|
+ mlxsw_sp->router->vrs = kcalloc(max_vrs, sizeof(struct mlxsw_sp_vr),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!mlxsw_sp->router->vrs)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
for (i = 0; i < max_vrs; i++) {
|
|
|
- vr = &mlxsw_sp->router.vrs[i];
|
|
|
+ vr = &mlxsw_sp->router->vrs[i];
|
|
|
vr->id = i;
|
|
|
}
|
|
|
|
|
@@ -703,7 +754,7 @@ static void mlxsw_sp_vrs_fini(struct mlxsw_sp *mlxsw_sp)
|
|
|
*/
|
|
|
mlxsw_core_flush_owq();
|
|
|
mlxsw_sp_router_fib_flush(mlxsw_sp);
|
|
|
- kfree(mlxsw_sp->router.vrs);
|
|
|
+ kfree(mlxsw_sp->router->vrs);
|
|
|
}
|
|
|
|
|
|
struct mlxsw_sp_neigh_key {
|
|
@@ -755,7 +806,7 @@ 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,
|
|
|
+ return rhashtable_insert_fast(&mlxsw_sp->router->neigh_ht,
|
|
|
&neigh_entry->ht_node,
|
|
|
mlxsw_sp_neigh_ht_params);
|
|
|
}
|
|
@@ -764,7 +815,7 @@ 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,
|
|
|
+ rhashtable_remove_fast(&mlxsw_sp->router->neigh_ht,
|
|
|
&neigh_entry->ht_node,
|
|
|
mlxsw_sp_neigh_ht_params);
|
|
|
}
|
|
@@ -812,7 +863,7 @@ mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp *mlxsw_sp, struct neighbour *n)
|
|
|
struct mlxsw_sp_neigh_key key;
|
|
|
|
|
|
key.n = n;
|
|
|
- return rhashtable_lookup_fast(&mlxsw_sp->router.neigh_ht,
|
|
|
+ return rhashtable_lookup_fast(&mlxsw_sp->router->neigh_ht,
|
|
|
&key, mlxsw_sp_neigh_ht_params);
|
|
|
}
|
|
|
|
|
@@ -821,7 +872,7 @@ mlxsw_sp_router_neighs_update_interval_init(struct mlxsw_sp *mlxsw_sp)
|
|
|
{
|
|
|
unsigned long interval = NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME);
|
|
|
|
|
|
- mlxsw_sp->router.neighs_update.interval = jiffies_to_msecs(interval);
|
|
|
+ mlxsw_sp->router->neighs_update.interval = jiffies_to_msecs(interval);
|
|
|
}
|
|
|
|
|
|
static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp,
|
|
@@ -836,13 +887,13 @@ static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp,
|
|
|
|
|
|
mlxsw_reg_rauhtd_ent_ipv4_unpack(rauhtd_pl, ent_index, &rif, &dip);
|
|
|
|
|
|
- if (!mlxsw_sp->rifs[rif]) {
|
|
|
+ if (!mlxsw_sp->router->rifs[rif]) {
|
|
|
dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect RIF in neighbour entry\n");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
dipn = htonl(dip);
|
|
|
- dev = mlxsw_sp->rifs[rif]->dev;
|
|
|
+ dev = mlxsw_sp->router->rifs[rif]->dev;
|
|
|
n = neigh_lookup(&arp_tbl, &dipn, dev);
|
|
|
if (!n) {
|
|
|
netdev_err(dev, "Failed to find matching neighbour for IP=%pI4h\n",
|
|
@@ -951,7 +1002,7 @@ static void mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp *mlxsw_sp)
|
|
|
|
|
|
/* Take RTNL mutex here to prevent lists from changes */
|
|
|
rtnl_lock();
|
|
|
- list_for_each_entry(neigh_entry, &mlxsw_sp->router.nexthop_neighs_list,
|
|
|
+ list_for_each_entry(neigh_entry, &mlxsw_sp->router->nexthop_neighs_list,
|
|
|
nexthop_neighs_list_node)
|
|
|
/* If this neigh have nexthops, make the kernel think this neigh
|
|
|
* is active regardless of the traffic.
|
|
@@ -963,33 +1014,35 @@ static void mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp *mlxsw_sp)
|
|
|
static void
|
|
|
mlxsw_sp_router_neighs_update_work_schedule(struct mlxsw_sp *mlxsw_sp)
|
|
|
{
|
|
|
- unsigned long interval = mlxsw_sp->router.neighs_update.interval;
|
|
|
+ unsigned long interval = mlxsw_sp->router->neighs_update.interval;
|
|
|
|
|
|
- mlxsw_core_schedule_dw(&mlxsw_sp->router.neighs_update.dw,
|
|
|
+ mlxsw_core_schedule_dw(&mlxsw_sp->router->neighs_update.dw,
|
|
|
msecs_to_jiffies(interval));
|
|
|
}
|
|
|
|
|
|
static void mlxsw_sp_router_neighs_update_work(struct work_struct *work)
|
|
|
{
|
|
|
- struct mlxsw_sp *mlxsw_sp = container_of(work, struct mlxsw_sp,
|
|
|
- router.neighs_update.dw.work);
|
|
|
+ struct mlxsw_sp_router *router;
|
|
|
int err;
|
|
|
|
|
|
- err = mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp);
|
|
|
+ router = container_of(work, struct mlxsw_sp_router,
|
|
|
+ neighs_update.dw.work);
|
|
|
+ err = mlxsw_sp_router_neighs_update_rauhtd(router->mlxsw_sp);
|
|
|
if (err)
|
|
|
- dev_err(mlxsw_sp->bus_info->dev, "Could not update kernel for neigh activity");
|
|
|
+ dev_err(router->mlxsw_sp->bus_info->dev, "Could not update kernel for neigh activity");
|
|
|
|
|
|
- mlxsw_sp_router_neighs_update_nh(mlxsw_sp);
|
|
|
+ mlxsw_sp_router_neighs_update_nh(router->mlxsw_sp);
|
|
|
|
|
|
- mlxsw_sp_router_neighs_update_work_schedule(mlxsw_sp);
|
|
|
+ mlxsw_sp_router_neighs_update_work_schedule(router->mlxsw_sp);
|
|
|
}
|
|
|
|
|
|
static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work)
|
|
|
{
|
|
|
struct mlxsw_sp_neigh_entry *neigh_entry;
|
|
|
- struct mlxsw_sp *mlxsw_sp = container_of(work, struct mlxsw_sp,
|
|
|
- router.nexthop_probe_dw.work);
|
|
|
+ struct mlxsw_sp_router *router;
|
|
|
|
|
|
+ router = container_of(work, struct mlxsw_sp_router,
|
|
|
+ nexthop_probe_dw.work);
|
|
|
/* Iterate over nexthop neighbours, find those who are unresolved and
|
|
|
* send arp on them. This solves the chicken-egg problem when
|
|
|
* the nexthop wouldn't get offloaded until the neighbor is resolved
|
|
@@ -999,13 +1052,13 @@ static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work)
|
|
|
* Take RTNL mutex here to prevent lists from changes.
|
|
|
*/
|
|
|
rtnl_lock();
|
|
|
- list_for_each_entry(neigh_entry, &mlxsw_sp->router.nexthop_neighs_list,
|
|
|
+ list_for_each_entry(neigh_entry, &router->nexthop_neighs_list,
|
|
|
nexthop_neighs_list_node)
|
|
|
if (!neigh_entry->connected)
|
|
|
neigh_event_send(neigh_entry->key.n, NULL);
|
|
|
rtnl_unlock();
|
|
|
|
|
|
- mlxsw_core_schedule_dw(&mlxsw_sp->router.nexthop_probe_dw,
|
|
|
+ mlxsw_core_schedule_dw(&router->nexthop_probe_dw,
|
|
|
MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL);
|
|
|
}
|
|
|
|
|
@@ -1127,7 +1180,7 @@ int mlxsw_sp_router_netevent_event(struct notifier_block *unused,
|
|
|
|
|
|
mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
|
|
interval = jiffies_to_msecs(NEIGH_VAR(p, DELAY_PROBE_TIME));
|
|
|
- mlxsw_sp->router.neighs_update.interval = interval;
|
|
|
+ mlxsw_sp->router->neighs_update.interval = interval;
|
|
|
|
|
|
mlxsw_sp_port_dev_put(mlxsw_sp_port);
|
|
|
break;
|
|
@@ -1168,7 +1221,7 @@ static int mlxsw_sp_neigh_init(struct mlxsw_sp *mlxsw_sp)
|
|
|
{
|
|
|
int err;
|
|
|
|
|
|
- err = rhashtable_init(&mlxsw_sp->router.neigh_ht,
|
|
|
+ err = rhashtable_init(&mlxsw_sp->router->neigh_ht,
|
|
|
&mlxsw_sp_neigh_ht_params);
|
|
|
if (err)
|
|
|
return err;
|
|
@@ -1179,20 +1232,20 @@ static int mlxsw_sp_neigh_init(struct mlxsw_sp *mlxsw_sp)
|
|
|
mlxsw_sp_router_neighs_update_interval_init(mlxsw_sp);
|
|
|
|
|
|
/* Create the delayed works for the activity_update */
|
|
|
- INIT_DELAYED_WORK(&mlxsw_sp->router.neighs_update.dw,
|
|
|
+ INIT_DELAYED_WORK(&mlxsw_sp->router->neighs_update.dw,
|
|
|
mlxsw_sp_router_neighs_update_work);
|
|
|
- INIT_DELAYED_WORK(&mlxsw_sp->router.nexthop_probe_dw,
|
|
|
+ INIT_DELAYED_WORK(&mlxsw_sp->router->nexthop_probe_dw,
|
|
|
mlxsw_sp_router_probe_unresolved_nexthops);
|
|
|
- mlxsw_core_schedule_dw(&mlxsw_sp->router.neighs_update.dw, 0);
|
|
|
- mlxsw_core_schedule_dw(&mlxsw_sp->router.nexthop_probe_dw, 0);
|
|
|
+ mlxsw_core_schedule_dw(&mlxsw_sp->router->neighs_update.dw, 0);
|
|
|
+ mlxsw_core_schedule_dw(&mlxsw_sp->router->nexthop_probe_dw, 0);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static void mlxsw_sp_neigh_fini(struct mlxsw_sp *mlxsw_sp)
|
|
|
{
|
|
|
- cancel_delayed_work_sync(&mlxsw_sp->router.neighs_update.dw);
|
|
|
- cancel_delayed_work_sync(&mlxsw_sp->router.nexthop_probe_dw);
|
|
|
- rhashtable_destroy(&mlxsw_sp->router.neigh_ht);
|
|
|
+ cancel_delayed_work_sync(&mlxsw_sp->router->neighs_update.dw);
|
|
|
+ cancel_delayed_work_sync(&mlxsw_sp->router->nexthop_probe_dw);
|
|
|
+ rhashtable_destroy(&mlxsw_sp->router->neigh_ht);
|
|
|
}
|
|
|
|
|
|
static int mlxsw_sp_neigh_rif_flush(struct mlxsw_sp *mlxsw_sp,
|
|
@@ -1267,7 +1320,7 @@ static const struct rhashtable_params mlxsw_sp_nexthop_group_ht_params = {
|
|
|
static int mlxsw_sp_nexthop_group_insert(struct mlxsw_sp *mlxsw_sp,
|
|
|
struct mlxsw_sp_nexthop_group *nh_grp)
|
|
|
{
|
|
|
- return rhashtable_insert_fast(&mlxsw_sp->router.nexthop_group_ht,
|
|
|
+ return rhashtable_insert_fast(&mlxsw_sp->router->nexthop_group_ht,
|
|
|
&nh_grp->ht_node,
|
|
|
mlxsw_sp_nexthop_group_ht_params);
|
|
|
}
|
|
@@ -1275,7 +1328,7 @@ static int mlxsw_sp_nexthop_group_insert(struct mlxsw_sp *mlxsw_sp,
|
|
|
static void mlxsw_sp_nexthop_group_remove(struct mlxsw_sp *mlxsw_sp,
|
|
|
struct mlxsw_sp_nexthop_group *nh_grp)
|
|
|
{
|
|
|
- rhashtable_remove_fast(&mlxsw_sp->router.nexthop_group_ht,
|
|
|
+ rhashtable_remove_fast(&mlxsw_sp->router->nexthop_group_ht,
|
|
|
&nh_grp->ht_node,
|
|
|
mlxsw_sp_nexthop_group_ht_params);
|
|
|
}
|
|
@@ -1284,7 +1337,7 @@ static struct mlxsw_sp_nexthop_group *
|
|
|
mlxsw_sp_nexthop_group_lookup(struct mlxsw_sp *mlxsw_sp,
|
|
|
struct mlxsw_sp_nexthop_group_key key)
|
|
|
{
|
|
|
- return rhashtable_lookup_fast(&mlxsw_sp->router.nexthop_group_ht, &key,
|
|
|
+ return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_group_ht, &key,
|
|
|
mlxsw_sp_nexthop_group_ht_params);
|
|
|
}
|
|
|
|
|
@@ -1297,14 +1350,14 @@ static const struct rhashtable_params mlxsw_sp_nexthop_ht_params = {
|
|
|
static int mlxsw_sp_nexthop_insert(struct mlxsw_sp *mlxsw_sp,
|
|
|
struct mlxsw_sp_nexthop *nh)
|
|
|
{
|
|
|
- return rhashtable_insert_fast(&mlxsw_sp->router.nexthop_ht,
|
|
|
+ return rhashtable_insert_fast(&mlxsw_sp->router->nexthop_ht,
|
|
|
&nh->ht_node, mlxsw_sp_nexthop_ht_params);
|
|
|
}
|
|
|
|
|
|
static void mlxsw_sp_nexthop_remove(struct mlxsw_sp *mlxsw_sp,
|
|
|
struct mlxsw_sp_nexthop *nh)
|
|
|
{
|
|
|
- rhashtable_remove_fast(&mlxsw_sp->router.nexthop_ht, &nh->ht_node,
|
|
|
+ rhashtable_remove_fast(&mlxsw_sp->router->nexthop_ht, &nh->ht_node,
|
|
|
mlxsw_sp_nexthop_ht_params);
|
|
|
}
|
|
|
|
|
@@ -1312,7 +1365,7 @@ static struct mlxsw_sp_nexthop *
|
|
|
mlxsw_sp_nexthop_lookup(struct mlxsw_sp *mlxsw_sp,
|
|
|
struct mlxsw_sp_nexthop_key key)
|
|
|
{
|
|
|
- return rhashtable_lookup_fast(&mlxsw_sp->router.nexthop_ht, &key,
|
|
|
+ return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_ht, &key,
|
|
|
mlxsw_sp_nexthop_ht_params);
|
|
|
}
|
|
|
|
|
@@ -1599,7 +1652,7 @@ static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp,
|
|
|
*/
|
|
|
if (list_empty(&neigh_entry->nexthop_list))
|
|
|
list_add_tail(&neigh_entry->nexthop_neighs_list_node,
|
|
|
- &mlxsw_sp->router.nexthop_neighs_list);
|
|
|
+ &mlxsw_sp->router->nexthop_neighs_list);
|
|
|
|
|
|
nh->neigh_entry = neigh_entry;
|
|
|
list_add_tail(&nh->neigh_list_node, &neigh_entry->nexthop_list);
|
|
@@ -1697,7 +1750,7 @@ static void mlxsw_sp_nexthop_event(struct mlxsw_sp *mlxsw_sp,
|
|
|
struct mlxsw_sp_nexthop *nh;
|
|
|
struct mlxsw_sp_rif *rif;
|
|
|
|
|
|
- if (mlxsw_sp->router.aborted)
|
|
|
+ if (mlxsw_sp->router->aborted)
|
|
|
return;
|
|
|
|
|
|
key.fib_nh = fib_nh;
|
|
@@ -2510,7 +2563,7 @@ mlxsw_sp_router_fib4_add(struct mlxsw_sp *mlxsw_sp,
|
|
|
struct mlxsw_sp_fib_node *fib_node;
|
|
|
int err;
|
|
|
|
|
|
- if (mlxsw_sp->router.aborted)
|
|
|
+ if (mlxsw_sp->router->aborted)
|
|
|
return 0;
|
|
|
|
|
|
fib_node = mlxsw_sp_fib4_node_get(mlxsw_sp, fen_info);
|
|
@@ -2550,7 +2603,7 @@ static void mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp,
|
|
|
struct mlxsw_sp_fib_entry *fib_entry;
|
|
|
struct mlxsw_sp_fib_node *fib_node;
|
|
|
|
|
|
- if (mlxsw_sp->router.aborted)
|
|
|
+ if (mlxsw_sp->router->aborted)
|
|
|
return;
|
|
|
|
|
|
fib_entry = mlxsw_sp_fib4_entry_lookup(mlxsw_sp, fen_info);
|
|
@@ -2581,7 +2634,7 @@ static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp)
|
|
|
return err;
|
|
|
|
|
|
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
|
|
|
- struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[i];
|
|
|
+ struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i];
|
|
|
char raltb_pl[MLXSW_REG_RALTB_LEN];
|
|
|
char ralue_pl[MLXSW_REG_RALUE_LEN];
|
|
|
|
|
@@ -2663,7 +2716,7 @@ static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp)
|
|
|
int i;
|
|
|
|
|
|
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
|
|
|
- struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[i];
|
|
|
+ struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i];
|
|
|
|
|
|
if (!mlxsw_sp_vr_is_used(vr))
|
|
|
continue;
|
|
@@ -2675,11 +2728,11 @@ static void mlxsw_sp_router_fib4_abort(struct mlxsw_sp *mlxsw_sp)
|
|
|
{
|
|
|
int err;
|
|
|
|
|
|
- if (mlxsw_sp->router.aborted)
|
|
|
+ if (mlxsw_sp->router->aborted)
|
|
|
return;
|
|
|
dev_warn(mlxsw_sp->bus_info->dev, "FIB abort triggered. Note that FIB entries are no longer being offloaded to this device.\n");
|
|
|
mlxsw_sp_router_fib_flush(mlxsw_sp);
|
|
|
- mlxsw_sp->router.aborted = true;
|
|
|
+ mlxsw_sp->router->aborted = true;
|
|
|
err = mlxsw_sp_router_set_abort_trap(mlxsw_sp);
|
|
|
if (err)
|
|
|
dev_warn(mlxsw_sp->bus_info->dev, "Failed to set abort trap.\n");
|
|
@@ -2745,9 +2798,9 @@ static void mlxsw_sp_router_fib_event_work(struct work_struct *work)
|
|
|
static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
|
|
|
unsigned long event, void *ptr)
|
|
|
{
|
|
|
- struct mlxsw_sp *mlxsw_sp = container_of(nb, struct mlxsw_sp, fib_nb);
|
|
|
struct mlxsw_sp_fib_event_work *fib_work;
|
|
|
struct fib_notifier_info *info = ptr;
|
|
|
+ struct mlxsw_sp_router *router;
|
|
|
|
|
|
if (!net_eq(info->net, &init_net))
|
|
|
return NOTIFY_DONE;
|
|
@@ -2757,7 +2810,8 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
|
|
|
return NOTIFY_BAD;
|
|
|
|
|
|
INIT_WORK(&fib_work->work, mlxsw_sp_router_fib_event_work);
|
|
|
- fib_work->mlxsw_sp = mlxsw_sp;
|
|
|
+ router = container_of(nb, struct mlxsw_sp_router, fib_nb);
|
|
|
+ fib_work->mlxsw_sp = router->mlxsw_sp;
|
|
|
fib_work->event = event;
|
|
|
|
|
|
switch (event) {
|
|
@@ -2795,8 +2849,9 @@ mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
|
|
|
int i;
|
|
|
|
|
|
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++)
|
|
|
- if (mlxsw_sp->rifs[i] && mlxsw_sp->rifs[i]->dev == dev)
|
|
|
- return mlxsw_sp->rifs[i];
|
|
|
+ if (mlxsw_sp->router->rifs[i] &&
|
|
|
+ mlxsw_sp->router->rifs[i]->dev == dev)
|
|
|
+ return mlxsw_sp->router->rifs[i];
|
|
|
|
|
|
return NULL;
|
|
|
}
|
|
@@ -2852,7 +2907,7 @@ static int mlxsw_sp_avail_rif_get(struct mlxsw_sp *mlxsw_sp)
|
|
|
int i;
|
|
|
|
|
|
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++)
|
|
|
- if (!mlxsw_sp->rifs[i])
|
|
|
+ if (!mlxsw_sp->router->rifs[i])
|
|
|
return i;
|
|
|
|
|
|
return MLXSW_SP_INVALID_INDEX_RIF;
|
|
@@ -2932,6 +2987,12 @@ mlxsw_sp_rif_alloc(u16 rif_index, u16 vr_id, struct net_device *l3_dev,
|
|
|
return rif;
|
|
|
}
|
|
|
|
|
|
+struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp,
|
|
|
+ u16 rif_index)
|
|
|
+{
|
|
|
+ return mlxsw_sp->router->rifs[rif_index];
|
|
|
+}
|
|
|
+
|
|
|
u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif)
|
|
|
{
|
|
|
return rif->rif_index;
|
|
@@ -2994,7 +3055,7 @@ mlxsw_sp_vport_rif_sp_create(struct mlxsw_sp_port *mlxsw_sp_vport,
|
|
|
}
|
|
|
|
|
|
f->rif = rif;
|
|
|
- mlxsw_sp->rifs[rif_index] = rif;
|
|
|
+ mlxsw_sp->router->rifs[rif_index] = rif;
|
|
|
vr->rif_count++;
|
|
|
|
|
|
return rif;
|
|
@@ -3015,7 +3076,7 @@ static void mlxsw_sp_vport_rif_sp_destroy(struct mlxsw_sp_port *mlxsw_sp_vport,
|
|
|
struct mlxsw_sp_rif *rif)
|
|
|
{
|
|
|
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp;
|
|
|
- struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[rif->vr_id];
|
|
|
+ struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id];
|
|
|
struct net_device *l3_dev = rif->dev;
|
|
|
struct mlxsw_sp_fid *f = rif->f;
|
|
|
u16 rif_index = rif->rif_index;
|
|
@@ -3027,7 +3088,7 @@ static void mlxsw_sp_vport_rif_sp_destroy(struct mlxsw_sp_port *mlxsw_sp_vport,
|
|
|
mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_INGRESS);
|
|
|
|
|
|
vr->rif_count--;
|
|
|
- mlxsw_sp->rifs[rif_index] = NULL;
|
|
|
+ mlxsw_sp->router->rifs[rif_index] = NULL;
|
|
|
f->rif = NULL;
|
|
|
|
|
|
kfree(rif);
|
|
@@ -3142,7 +3203,7 @@ static struct mlxsw_sp_fid *mlxsw_sp_bridge_fid_get(struct mlxsw_sp *mlxsw_sp,
|
|
|
|
|
|
if (is_vlan_dev(l3_dev))
|
|
|
fid = vlan_dev_vlan_id(l3_dev);
|
|
|
- else if (mlxsw_sp->master_bridge.dev == l3_dev)
|
|
|
+ else if (mlxsw_sp_master_bridge(mlxsw_sp)->dev == l3_dev)
|
|
|
fid = 1;
|
|
|
else
|
|
|
return mlxsw_sp_vfid_find(mlxsw_sp, l3_dev);
|
|
@@ -3251,7 +3312,7 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
|
|
|
}
|
|
|
|
|
|
f->rif = rif;
|
|
|
- mlxsw_sp->rifs[rif_index] = rif;
|
|
|
+ mlxsw_sp->router->rifs[rif_index] = rif;
|
|
|
vr->rif_count++;
|
|
|
|
|
|
netdev_dbg(l3_dev, "RIF=%d created\n", rif_index);
|
|
@@ -3273,7 +3334,7 @@ err_port_flood_set:
|
|
|
void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
|
|
|
struct mlxsw_sp_rif *rif)
|
|
|
{
|
|
|
- struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[rif->vr_id];
|
|
|
+ struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id];
|
|
|
struct net_device *l3_dev = rif->dev;
|
|
|
struct mlxsw_sp_fid *f = rif->f;
|
|
|
u16 rif_index = rif->rif_index;
|
|
@@ -3281,7 +3342,7 @@ void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
|
|
|
mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif);
|
|
|
|
|
|
vr->rif_count--;
|
|
|
- mlxsw_sp->rifs[rif_index] = NULL;
|
|
|
+ mlxsw_sp->router->rifs[rif_index] = NULL;
|
|
|
f->rif = NULL;
|
|
|
|
|
|
kfree(rif);
|
|
@@ -3338,7 +3399,7 @@ static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev,
|
|
|
return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event,
|
|
|
vid);
|
|
|
else if (netif_is_bridge_master(real_dev) &&
|
|
|
- mlxsw_sp->master_bridge.dev == real_dev)
|
|
|
+ mlxsw_sp_master_bridge(mlxsw_sp)->dev == real_dev)
|
|
|
return mlxsw_sp_inetaddr_bridge_event(vlan_dev, real_dev,
|
|
|
event);
|
|
|
|
|
@@ -3489,16 +3550,39 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp)
|
|
|
+{
|
|
|
+ u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
|
|
|
+
|
|
|
+ mlxsw_sp->router->rifs = kcalloc(max_rifs,
|
|
|
+ sizeof(struct mlxsw_sp_rif *),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!mlxsw_sp->router->rifs)
|
|
|
+ return -ENOMEM;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void mlxsw_sp_rifs_fini(struct mlxsw_sp *mlxsw_sp)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++)
|
|
|
+ WARN_ON_ONCE(mlxsw_sp->router->rifs[i]);
|
|
|
+
|
|
|
+ kfree(mlxsw_sp->router->rifs);
|
|
|
+}
|
|
|
+
|
|
|
static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb)
|
|
|
{
|
|
|
- struct mlxsw_sp *mlxsw_sp = container_of(nb, struct mlxsw_sp, fib_nb);
|
|
|
+ struct mlxsw_sp_router *router;
|
|
|
|
|
|
/* Flush pending FIB notifications and then flush the device's
|
|
|
* table before requesting another dump. The FIB notification
|
|
|
* block is unregistered, so no need to take RTNL.
|
|
|
*/
|
|
|
mlxsw_core_flush_owq();
|
|
|
- mlxsw_sp_router_fib_flush(mlxsw_sp);
|
|
|
+ router = container_of(nb, struct mlxsw_sp_router, fib_nb);
|
|
|
+ mlxsw_sp_router_fib_flush(router->mlxsw_sp);
|
|
|
}
|
|
|
|
|
|
static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
|
|
@@ -3509,55 +3593,50 @@ static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
|
|
|
|
|
|
if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_RIFS))
|
|
|
return -EIO;
|
|
|
-
|
|
|
max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
|
|
|
- mlxsw_sp->rifs = kcalloc(max_rifs, sizeof(struct mlxsw_sp_rif *),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!mlxsw_sp->rifs)
|
|
|
- return -ENOMEM;
|
|
|
|
|
|
mlxsw_reg_rgcr_pack(rgcr_pl, true);
|
|
|
mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl, max_rifs);
|
|
|
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
|
|
|
if (err)
|
|
|
- goto err_rgcr_fail;
|
|
|
-
|
|
|
+ return err;
|
|
|
return 0;
|
|
|
-
|
|
|
-err_rgcr_fail:
|
|
|
- kfree(mlxsw_sp->rifs);
|
|
|
- return err;
|
|
|
}
|
|
|
|
|
|
static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
|
|
|
{
|
|
|
char rgcr_pl[MLXSW_REG_RGCR_LEN];
|
|
|
- int i;
|
|
|
|
|
|
mlxsw_reg_rgcr_pack(rgcr_pl, false);
|
|
|
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
|
|
|
-
|
|
|
- for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++)
|
|
|
- WARN_ON_ONCE(mlxsw_sp->rifs[i]);
|
|
|
-
|
|
|
- kfree(mlxsw_sp->rifs);
|
|
|
}
|
|
|
|
|
|
int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
|
|
|
{
|
|
|
+ struct mlxsw_sp_router *router;
|
|
|
int err;
|
|
|
|
|
|
- INIT_LIST_HEAD(&mlxsw_sp->router.nexthop_neighs_list);
|
|
|
+ router = kzalloc(sizeof(*mlxsw_sp->router), GFP_KERNEL);
|
|
|
+ if (!router)
|
|
|
+ return -ENOMEM;
|
|
|
+ mlxsw_sp->router = router;
|
|
|
+ router->mlxsw_sp = mlxsw_sp;
|
|
|
+
|
|
|
+ INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_neighs_list);
|
|
|
err = __mlxsw_sp_router_init(mlxsw_sp);
|
|
|
if (err)
|
|
|
- return err;
|
|
|
+ goto err_router_init;
|
|
|
+
|
|
|
+ err = mlxsw_sp_rifs_init(mlxsw_sp);
|
|
|
+ if (err)
|
|
|
+ goto err_rifs_init;
|
|
|
|
|
|
- err = rhashtable_init(&mlxsw_sp->router.nexthop_ht,
|
|
|
+ err = rhashtable_init(&mlxsw_sp->router->nexthop_ht,
|
|
|
&mlxsw_sp_nexthop_ht_params);
|
|
|
if (err)
|
|
|
goto err_nexthop_ht_init;
|
|
|
|
|
|
- err = rhashtable_init(&mlxsw_sp->router.nexthop_group_ht,
|
|
|
+ err = rhashtable_init(&mlxsw_sp->router->nexthop_group_ht,
|
|
|
&mlxsw_sp_nexthop_group_ht_params);
|
|
|
if (err)
|
|
|
goto err_nexthop_group_ht_init;
|
|
@@ -3574,8 +3653,8 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
|
|
|
if (err)
|
|
|
goto err_neigh_init;
|
|
|
|
|
|
- mlxsw_sp->fib_nb.notifier_call = mlxsw_sp_router_fib_event;
|
|
|
- err = register_fib_notifier(&mlxsw_sp->fib_nb,
|
|
|
+ mlxsw_sp->router->fib_nb.notifier_call = mlxsw_sp_router_fib_event;
|
|
|
+ err = register_fib_notifier(&mlxsw_sp->router->fib_nb,
|
|
|
mlxsw_sp_router_fib_dump_flush);
|
|
|
if (err)
|
|
|
goto err_register_fib_notifier;
|
|
@@ -3589,21 +3668,27 @@ err_neigh_init:
|
|
|
err_vrs_init:
|
|
|
mlxsw_sp_lpm_fini(mlxsw_sp);
|
|
|
err_lpm_init:
|
|
|
- rhashtable_destroy(&mlxsw_sp->router.nexthop_group_ht);
|
|
|
+ rhashtable_destroy(&mlxsw_sp->router->nexthop_group_ht);
|
|
|
err_nexthop_group_ht_init:
|
|
|
- rhashtable_destroy(&mlxsw_sp->router.nexthop_ht);
|
|
|
+ rhashtable_destroy(&mlxsw_sp->router->nexthop_ht);
|
|
|
err_nexthop_ht_init:
|
|
|
+ mlxsw_sp_rifs_fini(mlxsw_sp);
|
|
|
+err_rifs_init:
|
|
|
__mlxsw_sp_router_fini(mlxsw_sp);
|
|
|
+err_router_init:
|
|
|
+ kfree(mlxsw_sp->router);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
|
|
|
{
|
|
|
- unregister_fib_notifier(&mlxsw_sp->fib_nb);
|
|
|
+ unregister_fib_notifier(&mlxsw_sp->router->fib_nb);
|
|
|
mlxsw_sp_neigh_fini(mlxsw_sp);
|
|
|
mlxsw_sp_vrs_fini(mlxsw_sp);
|
|
|
mlxsw_sp_lpm_fini(mlxsw_sp);
|
|
|
- rhashtable_destroy(&mlxsw_sp->router.nexthop_group_ht);
|
|
|
- rhashtable_destroy(&mlxsw_sp->router.nexthop_ht);
|
|
|
+ rhashtable_destroy(&mlxsw_sp->router->nexthop_group_ht);
|
|
|
+ rhashtable_destroy(&mlxsw_sp->router->nexthop_ht);
|
|
|
+ mlxsw_sp_rifs_fini(mlxsw_sp);
|
|
|
__mlxsw_sp_router_fini(mlxsw_sp);
|
|
|
+ kfree(mlxsw_sp->router);
|
|
|
}
|