fib_notifier.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. #include <linux/rtnetlink.h>
  2. #include <linux/notifier.h>
  3. #include <linux/rcupdate.h>
  4. #include <linux/kernel.h>
  5. #include <linux/module.h>
  6. #include <linux/init.h>
  7. #include <net/net_namespace.h>
  8. #include <net/fib_notifier.h>
  9. static ATOMIC_NOTIFIER_HEAD(fib_chain);
  10. int call_fib_notifier(struct notifier_block *nb, struct net *net,
  11. enum fib_event_type event_type,
  12. struct fib_notifier_info *info)
  13. {
  14. int err;
  15. info->net = net;
  16. err = nb->notifier_call(nb, event_type, info);
  17. return notifier_to_errno(err);
  18. }
  19. EXPORT_SYMBOL(call_fib_notifier);
  20. int call_fib_notifiers(struct net *net, enum fib_event_type event_type,
  21. struct fib_notifier_info *info)
  22. {
  23. int err;
  24. info->net = net;
  25. err = atomic_notifier_call_chain(&fib_chain, event_type, info);
  26. return notifier_to_errno(err);
  27. }
  28. EXPORT_SYMBOL(call_fib_notifiers);
  29. static unsigned int fib_seq_sum(void)
  30. {
  31. struct fib_notifier_ops *ops;
  32. unsigned int fib_seq = 0;
  33. struct net *net;
  34. rtnl_lock();
  35. down_read(&net_rwsem);
  36. for_each_net(net) {
  37. rcu_read_lock();
  38. list_for_each_entry_rcu(ops, &net->fib_notifier_ops, list) {
  39. if (!try_module_get(ops->owner))
  40. continue;
  41. fib_seq += ops->fib_seq_read(net);
  42. module_put(ops->owner);
  43. }
  44. rcu_read_unlock();
  45. }
  46. up_read(&net_rwsem);
  47. rtnl_unlock();
  48. return fib_seq;
  49. }
  50. static int fib_net_dump(struct net *net, struct notifier_block *nb)
  51. {
  52. struct fib_notifier_ops *ops;
  53. list_for_each_entry_rcu(ops, &net->fib_notifier_ops, list) {
  54. int err;
  55. if (!try_module_get(ops->owner))
  56. continue;
  57. err = ops->fib_dump(net, nb);
  58. module_put(ops->owner);
  59. if (err)
  60. return err;
  61. }
  62. return 0;
  63. }
  64. static bool fib_dump_is_consistent(struct notifier_block *nb,
  65. void (*cb)(struct notifier_block *nb),
  66. unsigned int fib_seq)
  67. {
  68. atomic_notifier_chain_register(&fib_chain, nb);
  69. if (fib_seq == fib_seq_sum())
  70. return true;
  71. atomic_notifier_chain_unregister(&fib_chain, nb);
  72. if (cb)
  73. cb(nb);
  74. return false;
  75. }
  76. #define FIB_DUMP_MAX_RETRIES 5
  77. int register_fib_notifier(struct notifier_block *nb,
  78. void (*cb)(struct notifier_block *nb))
  79. {
  80. int retries = 0;
  81. int err;
  82. do {
  83. unsigned int fib_seq = fib_seq_sum();
  84. struct net *net;
  85. rcu_read_lock();
  86. for_each_net_rcu(net) {
  87. err = fib_net_dump(net, nb);
  88. if (err)
  89. goto err_fib_net_dump;
  90. }
  91. rcu_read_unlock();
  92. if (fib_dump_is_consistent(nb, cb, fib_seq))
  93. return 0;
  94. } while (++retries < FIB_DUMP_MAX_RETRIES);
  95. return -EBUSY;
  96. err_fib_net_dump:
  97. rcu_read_unlock();
  98. return err;
  99. }
  100. EXPORT_SYMBOL(register_fib_notifier);
  101. int unregister_fib_notifier(struct notifier_block *nb)
  102. {
  103. return atomic_notifier_chain_unregister(&fib_chain, nb);
  104. }
  105. EXPORT_SYMBOL(unregister_fib_notifier);
  106. static int __fib_notifier_ops_register(struct fib_notifier_ops *ops,
  107. struct net *net)
  108. {
  109. struct fib_notifier_ops *o;
  110. list_for_each_entry(o, &net->fib_notifier_ops, list)
  111. if (ops->family == o->family)
  112. return -EEXIST;
  113. list_add_tail_rcu(&ops->list, &net->fib_notifier_ops);
  114. return 0;
  115. }
  116. struct fib_notifier_ops *
  117. fib_notifier_ops_register(const struct fib_notifier_ops *tmpl, struct net *net)
  118. {
  119. struct fib_notifier_ops *ops;
  120. int err;
  121. ops = kmemdup(tmpl, sizeof(*ops), GFP_KERNEL);
  122. if (!ops)
  123. return ERR_PTR(-ENOMEM);
  124. err = __fib_notifier_ops_register(ops, net);
  125. if (err)
  126. goto err_register;
  127. return ops;
  128. err_register:
  129. kfree(ops);
  130. return ERR_PTR(err);
  131. }
  132. EXPORT_SYMBOL(fib_notifier_ops_register);
  133. void fib_notifier_ops_unregister(struct fib_notifier_ops *ops)
  134. {
  135. list_del_rcu(&ops->list);
  136. kfree_rcu(ops, rcu);
  137. }
  138. EXPORT_SYMBOL(fib_notifier_ops_unregister);
  139. static int __net_init fib_notifier_net_init(struct net *net)
  140. {
  141. INIT_LIST_HEAD(&net->fib_notifier_ops);
  142. return 0;
  143. }
  144. static void __net_exit fib_notifier_net_exit(struct net *net)
  145. {
  146. WARN_ON_ONCE(!list_empty(&net->fib_notifier_ops));
  147. }
  148. static struct pernet_operations fib_notifier_net_ops = {
  149. .init = fib_notifier_net_init,
  150. .exit = fib_notifier_net_exit,
  151. };
  152. static int __init fib_notifier_init(void)
  153. {
  154. return register_pernet_subsys(&fib_notifier_net_ops);
  155. }
  156. subsys_initcall(fib_notifier_init);