Skip to content

Commit ae15ed6

Browse files
OrlovEIkuba-moo
authored andcommitted
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>
1 parent 396b80c commit ae15ed6

File tree

2 files changed

+114
-0
lines changed

2 files changed

+114
-0
lines changed

drivers/net/ethernet/marvell/prestera/prestera.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,9 @@ struct prestera_router {
324324
struct notifier_block netevent_nb;
325325
u8 *nhgrp_hw_state_cache; /* Bitmap cached hw state of nhs */
326326
unsigned long nhgrp_hw_cache_kick; /* jiffies */
327+
struct {
328+
struct delayed_work dw;
329+
} neighs_update;
327330
};
328331

329332
struct prestera_rxtx_params {

drivers/net/ethernet/marvell/prestera/prestera_router.c

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
#include "prestera.h"
1717
#include "prestera_router_hw.h"
1818

19+
#define PRESTERA_IMPLICITY_RESOLVE_DEAD_NEIGH
20+
#define PRESTERA_NH_PROBE_INTERVAL 5000 /* ms */
21+
1922
struct prestera_kern_neigh_cache_key {
2023
struct prestera_ip_addr addr;
2124
struct net_device *dev;
@@ -32,6 +35,7 @@ struct prestera_kern_neigh_cache {
3235
/* Lock cache if neigh is present in kernel */
3336
bool in_kernel;
3437
};
38+
3539
struct prestera_kern_fib_cache_key {
3640
struct prestera_ip_addr addr;
3741
u32 prefix_len;
@@ -1021,6 +1025,78 @@ __prestera_k_arb_util_fib_overlapped(struct prestera_switch *sw,
10211025
return rfc;
10221026
}
10231027

1028+
static void __prestera_k_arb_hw_state_upd(struct prestera_switch *sw,
1029+
struct prestera_kern_neigh_cache *nc)
1030+
{
1031+
struct prestera_nh_neigh_key nh_key;
1032+
struct prestera_nh_neigh *nh_neigh;
1033+
struct neighbour *n;
1034+
bool hw_active;
1035+
1036+
prestera_util_nc_key2nh_key(&nc->key, &nh_key);
1037+
nh_neigh = prestera_nh_neigh_find(sw, &nh_key);
1038+
if (!nh_neigh) {
1039+
pr_err("Cannot find nh_neigh for cached %pI4n",
1040+
&nc->key.addr.u.ipv4);
1041+
return;
1042+
}
1043+
1044+
hw_active = prestera_nh_neigh_util_hw_state(sw, nh_neigh);
1045+
1046+
#ifdef PRESTERA_IMPLICITY_RESOLVE_DEAD_NEIGH
1047+
if (!hw_active && nc->in_kernel)
1048+
goto out;
1049+
#else /* PRESTERA_IMPLICITY_RESOLVE_DEAD_NEIGH */
1050+
if (!hw_active)
1051+
goto out;
1052+
#endif /* PRESTERA_IMPLICITY_RESOLVE_DEAD_NEIGH */
1053+
1054+
if (nc->key.addr.v == PRESTERA_IPV4) {
1055+
n = neigh_lookup(&arp_tbl, &nc->key.addr.u.ipv4,
1056+
nc->key.dev);
1057+
if (!n)
1058+
n = neigh_create(&arp_tbl, &nc->key.addr.u.ipv4,
1059+
nc->key.dev);
1060+
} else {
1061+
n = NULL;
1062+
}
1063+
1064+
if (!IS_ERR(n) && n) {
1065+
neigh_event_send(n, NULL);
1066+
neigh_release(n);
1067+
} else {
1068+
pr_err("Cannot create neighbour %pI4n", &nc->key.addr.u.ipv4);
1069+
}
1070+
1071+
out:
1072+
return;
1073+
}
1074+
1075+
/* Propagate hw state to kernel */
1076+
static void prestera_k_arb_hw_evt(struct prestera_switch *sw)
1077+
{
1078+
struct prestera_kern_neigh_cache *n_cache;
1079+
struct rhashtable_iter iter;
1080+
1081+
rhashtable_walk_enter(&sw->router->kern_neigh_cache_ht, &iter);
1082+
rhashtable_walk_start(&iter);
1083+
while (1) {
1084+
n_cache = rhashtable_walk_next(&iter);
1085+
1086+
if (!n_cache)
1087+
break;
1088+
1089+
if (IS_ERR(n_cache))
1090+
continue;
1091+
1092+
rhashtable_walk_stop(&iter);
1093+
__prestera_k_arb_hw_state_upd(sw, n_cache);
1094+
rhashtable_walk_start(&iter);
1095+
}
1096+
rhashtable_walk_stop(&iter);
1097+
rhashtable_walk_exit(&iter);
1098+
}
1099+
10241100
/* Propagate kernel event to hw */
10251101
static void prestera_k_arb_n_evt(struct prestera_switch *sw,
10261102
struct neighbour *n)
@@ -1441,6 +1517,34 @@ static int prestera_router_netevent_event(struct notifier_block *nb,
14411517
return NOTIFY_DONE;
14421518
}
14431519

1520+
static void prestera_router_update_neighs_work(struct work_struct *work)
1521+
{
1522+
struct prestera_router *router;
1523+
1524+
router = container_of(work, struct prestera_router,
1525+
neighs_update.dw.work);
1526+
rtnl_lock();
1527+
1528+
prestera_k_arb_hw_evt(router->sw);
1529+
1530+
rtnl_unlock();
1531+
prestera_queue_delayed_work(&router->neighs_update.dw,
1532+
msecs_to_jiffies(PRESTERA_NH_PROBE_INTERVAL));
1533+
}
1534+
1535+
static int prestera_neigh_work_init(struct prestera_switch *sw)
1536+
{
1537+
INIT_DELAYED_WORK(&sw->router->neighs_update.dw,
1538+
prestera_router_update_neighs_work);
1539+
prestera_queue_delayed_work(&sw->router->neighs_update.dw, 0);
1540+
return 0;
1541+
}
1542+
1543+
static void prestera_neigh_work_fini(struct prestera_switch *sw)
1544+
{
1545+
cancel_delayed_work_sync(&sw->router->neighs_update.dw);
1546+
}
1547+
14441548
int prestera_router_init(struct prestera_switch *sw)
14451549
{
14461550
struct prestera_router *router;
@@ -1474,6 +1578,10 @@ int prestera_router_init(struct prestera_switch *sw)
14741578
goto err_nh_state_cache_alloc;
14751579
}
14761580

1581+
err = prestera_neigh_work_init(sw);
1582+
if (err)
1583+
goto err_neigh_work_init;
1584+
14771585
router->inetaddr_valid_nb.notifier_call = __prestera_inetaddr_valid_cb;
14781586
err = register_inetaddr_validator_notifier(&router->inetaddr_valid_nb);
14791587
if (err)
@@ -1504,6 +1612,8 @@ int prestera_router_init(struct prestera_switch *sw)
15041612
err_register_inetaddr_notifier:
15051613
unregister_inetaddr_validator_notifier(&router->inetaddr_valid_nb);
15061614
err_register_inetaddr_validator_notifier:
1615+
prestera_neigh_work_fini(sw);
1616+
err_neigh_work_init:
15071617
kfree(router->nhgrp_hw_state_cache);
15081618
err_nh_state_cache_alloc:
15091619
rhashtable_destroy(&router->kern_neigh_cache_ht);
@@ -1522,6 +1632,7 @@ void prestera_router_fini(struct prestera_switch *sw)
15221632
unregister_netevent_notifier(&sw->router->netevent_nb);
15231633
unregister_inetaddr_notifier(&sw->router->inetaddr_nb);
15241634
unregister_inetaddr_validator_notifier(&sw->router->inetaddr_valid_nb);
1635+
prestera_neigh_work_fini(sw);
15251636
prestera_queue_drain();
15261637

15271638
prestera_k_arb_abort(sw);

0 commit comments

Comments
 (0)