fib_notifier.c 1.9 KB

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