2121
2222#include <net/net_namespace.h>
2323#include <net/netns/generic.h>
24+ #include <net/netevent.h>
2425#include <net/tcp.h>
2526#include <net/ipv6.h>
2627#include <net/ip_fib.h>
@@ -5047,10 +5048,87 @@ static int cma_netdev_callback(struct notifier_block *self, unsigned long event,
50475048 return ret ;
50485049}
50495050
5051+ static void cma_netevent_work_handler (struct work_struct * _work )
5052+ {
5053+ struct rdma_id_private * id_priv =
5054+ container_of (_work , struct rdma_id_private , id .net_work );
5055+ struct rdma_cm_event event = {};
5056+
5057+ mutex_lock (& id_priv -> handler_mutex );
5058+
5059+ if (READ_ONCE (id_priv -> state ) == RDMA_CM_DESTROYING ||
5060+ READ_ONCE (id_priv -> state ) == RDMA_CM_DEVICE_REMOVAL )
5061+ goto out_unlock ;
5062+
5063+ event .event = RDMA_CM_EVENT_UNREACHABLE ;
5064+ event .status = - ETIMEDOUT ;
5065+
5066+ if (cma_cm_event_handler (id_priv , & event )) {
5067+ __acquire (& id_priv -> handler_mutex );
5068+ id_priv -> cm_id .ib = NULL ;
5069+ cma_id_put (id_priv );
5070+ destroy_id_handler_unlock (id_priv );
5071+ return ;
5072+ }
5073+
5074+ out_unlock :
5075+ mutex_unlock (& id_priv -> handler_mutex );
5076+ cma_id_put (id_priv );
5077+ }
5078+
5079+ static int cma_netevent_callback (struct notifier_block * self ,
5080+ unsigned long event , void * ctx )
5081+ {
5082+ struct id_table_entry * ips_node = NULL ;
5083+ struct rdma_id_private * current_id ;
5084+ struct neighbour * neigh = ctx ;
5085+ unsigned long flags ;
5086+
5087+ if (event != NETEVENT_NEIGH_UPDATE )
5088+ return NOTIFY_DONE ;
5089+
5090+ spin_lock_irqsave (& id_table_lock , flags );
5091+ if (neigh -> tbl -> family == AF_INET6 ) {
5092+ struct sockaddr_in6 neigh_sock_6 ;
5093+
5094+ neigh_sock_6 .sin6_family = AF_INET6 ;
5095+ neigh_sock_6 .sin6_addr = * (struct in6_addr * )neigh -> primary_key ;
5096+ ips_node = node_from_ndev_ip (& id_table , neigh -> dev -> ifindex ,
5097+ (struct sockaddr * )& neigh_sock_6 );
5098+ } else if (neigh -> tbl -> family == AF_INET ) {
5099+ struct sockaddr_in neigh_sock_4 ;
5100+
5101+ neigh_sock_4 .sin_family = AF_INET ;
5102+ neigh_sock_4 .sin_addr .s_addr = * (__be32 * )(neigh -> primary_key );
5103+ ips_node = node_from_ndev_ip (& id_table , neigh -> dev -> ifindex ,
5104+ (struct sockaddr * )& neigh_sock_4 );
5105+ } else
5106+ goto out ;
5107+
5108+ if (!ips_node )
5109+ goto out ;
5110+
5111+ list_for_each_entry (current_id , & ips_node -> id_list , id_list_entry ) {
5112+ if (!memcmp (current_id -> id .route .addr .dev_addr .dst_dev_addr ,
5113+ neigh -> ha , ETH_ALEN ))
5114+ continue ;
5115+ INIT_WORK (& current_id -> id .net_work , cma_netevent_work_handler );
5116+ cma_id_get (current_id );
5117+ queue_work (cma_wq , & current_id -> id .net_work );
5118+ }
5119+ out :
5120+ spin_unlock_irqrestore (& id_table_lock , flags );
5121+ return NOTIFY_DONE ;
5122+ }
5123+
50505124static struct notifier_block cma_nb = {
50515125 .notifier_call = cma_netdev_callback
50525126};
50535127
5128+ static struct notifier_block cma_netevent_cb = {
5129+ .notifier_call = cma_netevent_callback
5130+ };
5131+
50545132static void cma_send_device_removal_put (struct rdma_id_private * id_priv )
50555133{
50565134 struct rdma_cm_event event = { .event = RDMA_CM_EVENT_DEVICE_REMOVAL };
@@ -5273,6 +5351,7 @@ static int __init cma_init(void)
52735351
52745352 ib_sa_register_client (& sa_client );
52755353 register_netdevice_notifier (& cma_nb );
5354+ register_netevent_notifier (& cma_netevent_cb );
52765355
52775356 ret = ib_register_client (& cma_client );
52785357 if (ret )
@@ -5287,6 +5366,7 @@ static int __init cma_init(void)
52875366err_ib :
52885367 ib_unregister_client (& cma_client );
52895368err :
5369+ unregister_netevent_notifier (& cma_netevent_cb );
52905370 unregister_netdevice_notifier (& cma_nb );
52915371 ib_sa_unregister_client (& sa_client );
52925372 unregister_pernet_subsys (& cma_pernet_operations );
@@ -5299,6 +5379,7 @@ static void __exit cma_cleanup(void)
52995379{
53005380 cma_configfs_exit ();
53015381 ib_unregister_client (& cma_client );
5382+ unregister_netevent_notifier (& cma_netevent_cb );
53025383 unregister_netdevice_notifier (& cma_nb );
53035384 ib_sa_unregister_client (& sa_client );
53045385 unregister_pernet_subsys (& cma_pernet_operations );
0 commit comments