1c0243892SIdo Schimmel #include <linux/rtnetlink.h> 2c0243892SIdo Schimmel #include <linux/notifier.h> 3c0243892SIdo Schimmel #include <linux/rcupdate.h> 4c0243892SIdo Schimmel #include <linux/kernel.h> 5c0243892SIdo Schimmel #include <net/net_namespace.h> 6c0243892SIdo Schimmel #include <net/netns/ipv4.h> 7c0243892SIdo Schimmel #include <net/ip_fib.h> 8c0243892SIdo Schimmel 9c0243892SIdo Schimmel static ATOMIC_NOTIFIER_HEAD(fib_chain); 10c0243892SIdo Schimmel 11c0243892SIdo Schimmel int call_fib_notifier(struct notifier_block *nb, struct net *net, 12c0243892SIdo Schimmel enum fib_event_type event_type, 13c0243892SIdo Schimmel struct fib_notifier_info *info) 14c0243892SIdo Schimmel { 15c0243892SIdo Schimmel info->net = net; 16c0243892SIdo Schimmel return nb->notifier_call(nb, event_type, info); 17c0243892SIdo Schimmel } 18c0243892SIdo Schimmel 19c0243892SIdo Schimmel int call_fib_notifiers(struct net *net, enum fib_event_type event_type, 20c0243892SIdo Schimmel struct fib_notifier_info *info) 21c0243892SIdo Schimmel { 22c0243892SIdo Schimmel net->ipv4.fib_seq++; 23c0243892SIdo Schimmel info->net = net; 24c0243892SIdo Schimmel return atomic_notifier_call_chain(&fib_chain, event_type, info); 25c0243892SIdo Schimmel } 26c0243892SIdo Schimmel 27c0243892SIdo Schimmel static unsigned int fib_seq_sum(void) 28c0243892SIdo Schimmel { 29c0243892SIdo Schimmel unsigned int fib_seq = 0; 30c0243892SIdo Schimmel struct net *net; 31c0243892SIdo Schimmel 32c0243892SIdo Schimmel rtnl_lock(); 33c0243892SIdo Schimmel for_each_net(net) 34c0243892SIdo Schimmel fib_seq += net->ipv4.fib_seq; 35c0243892SIdo Schimmel rtnl_unlock(); 36c0243892SIdo Schimmel 37c0243892SIdo Schimmel return fib_seq; 38c0243892SIdo Schimmel } 39c0243892SIdo Schimmel 40c0243892SIdo Schimmel static bool fib_dump_is_consistent(struct notifier_block *nb, 41c0243892SIdo Schimmel void (*cb)(struct notifier_block *nb), 42c0243892SIdo Schimmel unsigned int fib_seq) 43c0243892SIdo Schimmel { 44c0243892SIdo Schimmel atomic_notifier_chain_register(&fib_chain, nb); 45c0243892SIdo Schimmel if (fib_seq == fib_seq_sum()) 46c0243892SIdo Schimmel return true; 47c0243892SIdo Schimmel atomic_notifier_chain_unregister(&fib_chain, nb); 48c0243892SIdo Schimmel if (cb) 49c0243892SIdo Schimmel cb(nb); 50c0243892SIdo Schimmel return false; 51c0243892SIdo Schimmel } 52c0243892SIdo Schimmel 53c0243892SIdo Schimmel #define FIB_DUMP_MAX_RETRIES 5 54c0243892SIdo Schimmel int register_fib_notifier(struct notifier_block *nb, 55c0243892SIdo Schimmel void (*cb)(struct notifier_block *nb)) 56c0243892SIdo Schimmel { 57c0243892SIdo Schimmel int retries = 0; 58c0243892SIdo Schimmel 59c0243892SIdo Schimmel do { 60c0243892SIdo Schimmel unsigned int fib_seq = fib_seq_sum(); 61c0243892SIdo Schimmel struct net *net; 62c0243892SIdo Schimmel 63c0243892SIdo Schimmel /* Mutex semantics guarantee that every change done to 64c0243892SIdo Schimmel * FIB tries before we read the change sequence counter 65c0243892SIdo Schimmel * is now visible to us. 66c0243892SIdo Schimmel */ 67c0243892SIdo Schimmel rcu_read_lock(); 68c0243892SIdo Schimmel for_each_net_rcu(net) { 69d05f7a7dSIdo Schimmel fib_rules_notify(net, nb); 70d05f7a7dSIdo Schimmel fib_notify(net, nb); 71c0243892SIdo Schimmel } 72c0243892SIdo Schimmel rcu_read_unlock(); 73c0243892SIdo Schimmel 74c0243892SIdo Schimmel if (fib_dump_is_consistent(nb, cb, fib_seq)) 75c0243892SIdo Schimmel return 0; 76c0243892SIdo Schimmel } while (++retries < FIB_DUMP_MAX_RETRIES); 77c0243892SIdo Schimmel 78c0243892SIdo Schimmel return -EBUSY; 79c0243892SIdo Schimmel } 80c0243892SIdo Schimmel EXPORT_SYMBOL(register_fib_notifier); 81c0243892SIdo Schimmel 82c0243892SIdo Schimmel int unregister_fib_notifier(struct notifier_block *nb) 83c0243892SIdo Schimmel { 84c0243892SIdo Schimmel return atomic_notifier_chain_unregister(&fib_chain, nb); 85c0243892SIdo Schimmel } 86c0243892SIdo Schimmel EXPORT_SYMBOL(unregister_fib_notifier); 87