forked from Minki/linux
net: marvell: prestera: Propagate nh state from hw to kernel
We poll nexthops in HW and call for each active nexthop appropriate neighbour. Also we provide implicity neighbour resolving. For example, user have added nexthop route: # ip route add 5.5.5.5 via 1.1.1.2 But neighbour 1.1.1.2 doesn't exist. In this case we will try to call neigh_event_send, even if there is no traffic. This is useful, when you have add route, which will be used after some time but with a lot of traffic (burst). So, we has prepared, offloaded route in advance. Co-developed-by: Taras Chornyi <tchornyi@marvell.com> Signed-off-by: Taras Chornyi <tchornyi@marvell.com> Co-developed-by: Oleksandr Mazur <oleksandr.mazur@plvision.eu> Signed-off-by: Oleksandr Mazur <oleksandr.mazur@plvision.eu> Signed-off-by: Yevhen Orlov <yevhen.orlov@plvision.eu> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
396b80cb5c
commit
ae15ed6e40
@ -324,6 +324,9 @@ struct prestera_router {
|
||||
struct notifier_block netevent_nb;
|
||||
u8 *nhgrp_hw_state_cache; /* Bitmap cached hw state of nhs */
|
||||
unsigned long nhgrp_hw_cache_kick; /* jiffies */
|
||||
struct {
|
||||
struct delayed_work dw;
|
||||
} neighs_update;
|
||||
};
|
||||
|
||||
struct prestera_rxtx_params {
|
||||
|
@ -16,6 +16,9 @@
|
||||
#include "prestera.h"
|
||||
#include "prestera_router_hw.h"
|
||||
|
||||
#define PRESTERA_IMPLICITY_RESOLVE_DEAD_NEIGH
|
||||
#define PRESTERA_NH_PROBE_INTERVAL 5000 /* ms */
|
||||
|
||||
struct prestera_kern_neigh_cache_key {
|
||||
struct prestera_ip_addr addr;
|
||||
struct net_device *dev;
|
||||
@ -32,6 +35,7 @@ struct prestera_kern_neigh_cache {
|
||||
/* Lock cache if neigh is present in kernel */
|
||||
bool in_kernel;
|
||||
};
|
||||
|
||||
struct prestera_kern_fib_cache_key {
|
||||
struct prestera_ip_addr addr;
|
||||
u32 prefix_len;
|
||||
@ -1021,6 +1025,78 @@ __prestera_k_arb_util_fib_overlapped(struct prestera_switch *sw,
|
||||
return rfc;
|
||||
}
|
||||
|
||||
static void __prestera_k_arb_hw_state_upd(struct prestera_switch *sw,
|
||||
struct prestera_kern_neigh_cache *nc)
|
||||
{
|
||||
struct prestera_nh_neigh_key nh_key;
|
||||
struct prestera_nh_neigh *nh_neigh;
|
||||
struct neighbour *n;
|
||||
bool hw_active;
|
||||
|
||||
prestera_util_nc_key2nh_key(&nc->key, &nh_key);
|
||||
nh_neigh = prestera_nh_neigh_find(sw, &nh_key);
|
||||
if (!nh_neigh) {
|
||||
pr_err("Cannot find nh_neigh for cached %pI4n",
|
||||
&nc->key.addr.u.ipv4);
|
||||
return;
|
||||
}
|
||||
|
||||
hw_active = prestera_nh_neigh_util_hw_state(sw, nh_neigh);
|
||||
|
||||
#ifdef PRESTERA_IMPLICITY_RESOLVE_DEAD_NEIGH
|
||||
if (!hw_active && nc->in_kernel)
|
||||
goto out;
|
||||
#else /* PRESTERA_IMPLICITY_RESOLVE_DEAD_NEIGH */
|
||||
if (!hw_active)
|
||||
goto out;
|
||||
#endif /* PRESTERA_IMPLICITY_RESOLVE_DEAD_NEIGH */
|
||||
|
||||
if (nc->key.addr.v == PRESTERA_IPV4) {
|
||||
n = neigh_lookup(&arp_tbl, &nc->key.addr.u.ipv4,
|
||||
nc->key.dev);
|
||||
if (!n)
|
||||
n = neigh_create(&arp_tbl, &nc->key.addr.u.ipv4,
|
||||
nc->key.dev);
|
||||
} else {
|
||||
n = NULL;
|
||||
}
|
||||
|
||||
if (!IS_ERR(n) && n) {
|
||||
neigh_event_send(n, NULL);
|
||||
neigh_release(n);
|
||||
} else {
|
||||
pr_err("Cannot create neighbour %pI4n", &nc->key.addr.u.ipv4);
|
||||
}
|
||||
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
/* Propagate hw state to kernel */
|
||||
static void prestera_k_arb_hw_evt(struct prestera_switch *sw)
|
||||
{
|
||||
struct prestera_kern_neigh_cache *n_cache;
|
||||
struct rhashtable_iter iter;
|
||||
|
||||
rhashtable_walk_enter(&sw->router->kern_neigh_cache_ht, &iter);
|
||||
rhashtable_walk_start(&iter);
|
||||
while (1) {
|
||||
n_cache = rhashtable_walk_next(&iter);
|
||||
|
||||
if (!n_cache)
|
||||
break;
|
||||
|
||||
if (IS_ERR(n_cache))
|
||||
continue;
|
||||
|
||||
rhashtable_walk_stop(&iter);
|
||||
__prestera_k_arb_hw_state_upd(sw, n_cache);
|
||||
rhashtable_walk_start(&iter);
|
||||
}
|
||||
rhashtable_walk_stop(&iter);
|
||||
rhashtable_walk_exit(&iter);
|
||||
}
|
||||
|
||||
/* Propagate kernel event to hw */
|
||||
static void prestera_k_arb_n_evt(struct prestera_switch *sw,
|
||||
struct neighbour *n)
|
||||
@ -1441,6 +1517,34 @@ static int prestera_router_netevent_event(struct notifier_block *nb,
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static void prestera_router_update_neighs_work(struct work_struct *work)
|
||||
{
|
||||
struct prestera_router *router;
|
||||
|
||||
router = container_of(work, struct prestera_router,
|
||||
neighs_update.dw.work);
|
||||
rtnl_lock();
|
||||
|
||||
prestera_k_arb_hw_evt(router->sw);
|
||||
|
||||
rtnl_unlock();
|
||||
prestera_queue_delayed_work(&router->neighs_update.dw,
|
||||
msecs_to_jiffies(PRESTERA_NH_PROBE_INTERVAL));
|
||||
}
|
||||
|
||||
static int prestera_neigh_work_init(struct prestera_switch *sw)
|
||||
{
|
||||
INIT_DELAYED_WORK(&sw->router->neighs_update.dw,
|
||||
prestera_router_update_neighs_work);
|
||||
prestera_queue_delayed_work(&sw->router->neighs_update.dw, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void prestera_neigh_work_fini(struct prestera_switch *sw)
|
||||
{
|
||||
cancel_delayed_work_sync(&sw->router->neighs_update.dw);
|
||||
}
|
||||
|
||||
int prestera_router_init(struct prestera_switch *sw)
|
||||
{
|
||||
struct prestera_router *router;
|
||||
@ -1474,6 +1578,10 @@ int prestera_router_init(struct prestera_switch *sw)
|
||||
goto err_nh_state_cache_alloc;
|
||||
}
|
||||
|
||||
err = prestera_neigh_work_init(sw);
|
||||
if (err)
|
||||
goto err_neigh_work_init;
|
||||
|
||||
router->inetaddr_valid_nb.notifier_call = __prestera_inetaddr_valid_cb;
|
||||
err = register_inetaddr_validator_notifier(&router->inetaddr_valid_nb);
|
||||
if (err)
|
||||
@ -1504,6 +1612,8 @@ err_register_netevent_notifier:
|
||||
err_register_inetaddr_notifier:
|
||||
unregister_inetaddr_validator_notifier(&router->inetaddr_valid_nb);
|
||||
err_register_inetaddr_validator_notifier:
|
||||
prestera_neigh_work_fini(sw);
|
||||
err_neigh_work_init:
|
||||
kfree(router->nhgrp_hw_state_cache);
|
||||
err_nh_state_cache_alloc:
|
||||
rhashtable_destroy(&router->kern_neigh_cache_ht);
|
||||
@ -1522,6 +1632,7 @@ void prestera_router_fini(struct prestera_switch *sw)
|
||||
unregister_netevent_notifier(&sw->router->netevent_nb);
|
||||
unregister_inetaddr_notifier(&sw->router->inetaddr_nb);
|
||||
unregister_inetaddr_validator_notifier(&sw->router->inetaddr_valid_nb);
|
||||
prestera_neigh_work_fini(sw);
|
||||
prestera_queue_drain();
|
||||
|
||||
prestera_k_arb_abort(sw);
|
||||
|
Loading…
Reference in New Issue
Block a user