16
16
#include "prestera.h"
17
17
#include "prestera_router_hw.h"
18
18
19
+ #define PRESTERA_IMPLICITY_RESOLVE_DEAD_NEIGH
20
+ #define PRESTERA_NH_PROBE_INTERVAL 5000 /* ms */
21
+
19
22
struct prestera_kern_neigh_cache_key {
20
23
struct prestera_ip_addr addr ;
21
24
struct net_device * dev ;
@@ -32,6 +35,7 @@ struct prestera_kern_neigh_cache {
32
35
/* Lock cache if neigh is present in kernel */
33
36
bool in_kernel ;
34
37
};
38
+
35
39
struct prestera_kern_fib_cache_key {
36
40
struct prestera_ip_addr addr ;
37
41
u32 prefix_len ;
@@ -1021,6 +1025,78 @@ __prestera_k_arb_util_fib_overlapped(struct prestera_switch *sw,
1021
1025
return rfc ;
1022
1026
}
1023
1027
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
+
1024
1100
/* Propagate kernel event to hw */
1025
1101
static void prestera_k_arb_n_evt (struct prestera_switch * sw ,
1026
1102
struct neighbour * n )
@@ -1441,6 +1517,34 @@ static int prestera_router_netevent_event(struct notifier_block *nb,
1441
1517
return NOTIFY_DONE ;
1442
1518
}
1443
1519
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
+
1444
1548
int prestera_router_init (struct prestera_switch * sw )
1445
1549
{
1446
1550
struct prestera_router * router ;
@@ -1474,6 +1578,10 @@ int prestera_router_init(struct prestera_switch *sw)
1474
1578
goto err_nh_state_cache_alloc ;
1475
1579
}
1476
1580
1581
+ err = prestera_neigh_work_init (sw );
1582
+ if (err )
1583
+ goto err_neigh_work_init ;
1584
+
1477
1585
router -> inetaddr_valid_nb .notifier_call = __prestera_inetaddr_valid_cb ;
1478
1586
err = register_inetaddr_validator_notifier (& router -> inetaddr_valid_nb );
1479
1587
if (err )
@@ -1504,6 +1612,8 @@ int prestera_router_init(struct prestera_switch *sw)
1504
1612
err_register_inetaddr_notifier :
1505
1613
unregister_inetaddr_validator_notifier (& router -> inetaddr_valid_nb );
1506
1614
err_register_inetaddr_validator_notifier :
1615
+ prestera_neigh_work_fini (sw );
1616
+ err_neigh_work_init :
1507
1617
kfree (router -> nhgrp_hw_state_cache );
1508
1618
err_nh_state_cache_alloc :
1509
1619
rhashtable_destroy (& router -> kern_neigh_cache_ht );
@@ -1522,6 +1632,7 @@ void prestera_router_fini(struct prestera_switch *sw)
1522
1632
unregister_netevent_notifier (& sw -> router -> netevent_nb );
1523
1633
unregister_inetaddr_notifier (& sw -> router -> inetaddr_nb );
1524
1634
unregister_inetaddr_validator_notifier (& sw -> router -> inetaddr_valid_nb );
1635
+ prestera_neigh_work_fini (sw );
1525
1636
prestera_queue_drain ();
1526
1637
1527
1638
prestera_k_arb_abort (sw );
0 commit comments