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+
1922struct 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+
3539struct 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 */
10251101static 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+
14441548int 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)
15041612err_register_inetaddr_notifier :
15051613 unregister_inetaddr_validator_notifier (& router -> inetaddr_valid_nb );
15061614err_register_inetaddr_validator_notifier :
1615+ prestera_neigh_work_fini (sw );
1616+ err_neigh_work_init :
15071617 kfree (router -> nhgrp_hw_state_cache );
15081618err_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