Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.15-rc1 181 lines 3.9 kB view raw
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 10static ATOMIC_NOTIFIER_HEAD(fib_chain); 11 12int call_fib_notifier(struct notifier_block *nb, struct net *net, 13 enum fib_event_type event_type, 14 struct fib_notifier_info *info) 15{ 16 info->net = net; 17 return nb->notifier_call(nb, event_type, info); 18} 19EXPORT_SYMBOL(call_fib_notifier); 20 21int call_fib_notifiers(struct net *net, enum fib_event_type event_type, 22 struct fib_notifier_info *info) 23{ 24 info->net = net; 25 return atomic_notifier_call_chain(&fib_chain, event_type, info); 26} 27EXPORT_SYMBOL(call_fib_notifiers); 28 29static unsigned int fib_seq_sum(void) 30{ 31 struct fib_notifier_ops *ops; 32 unsigned int fib_seq = 0; 33 struct net *net; 34 35 rtnl_lock(); 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 rtnl_unlock(); 47 48 return fib_seq; 49} 50 51static int fib_net_dump(struct net *net, struct notifier_block *nb) 52{ 53 struct fib_notifier_ops *ops; 54 55 list_for_each_entry_rcu(ops, &net->fib_notifier_ops, list) { 56 int err; 57 58 if (!try_module_get(ops->owner)) 59 continue; 60 err = ops->fib_dump(net, nb); 61 module_put(ops->owner); 62 if (err) 63 return err; 64 } 65 66 return 0; 67} 68 69static bool fib_dump_is_consistent(struct notifier_block *nb, 70 void (*cb)(struct notifier_block *nb), 71 unsigned int fib_seq) 72{ 73 atomic_notifier_chain_register(&fib_chain, nb); 74 if (fib_seq == fib_seq_sum()) 75 return true; 76 atomic_notifier_chain_unregister(&fib_chain, nb); 77 if (cb) 78 cb(nb); 79 return false; 80} 81 82#define FIB_DUMP_MAX_RETRIES 5 83int register_fib_notifier(struct notifier_block *nb, 84 void (*cb)(struct notifier_block *nb)) 85{ 86 int retries = 0; 87 int err; 88 89 do { 90 unsigned int fib_seq = fib_seq_sum(); 91 struct net *net; 92 93 rcu_read_lock(); 94 for_each_net_rcu(net) { 95 err = fib_net_dump(net, nb); 96 if (err) 97 goto err_fib_net_dump; 98 } 99 rcu_read_unlock(); 100 101 if (fib_dump_is_consistent(nb, cb, fib_seq)) 102 return 0; 103 } while (++retries < FIB_DUMP_MAX_RETRIES); 104 105 return -EBUSY; 106 107err_fib_net_dump: 108 rcu_read_unlock(); 109 return err; 110} 111EXPORT_SYMBOL(register_fib_notifier); 112 113int unregister_fib_notifier(struct notifier_block *nb) 114{ 115 return atomic_notifier_chain_unregister(&fib_chain, nb); 116} 117EXPORT_SYMBOL(unregister_fib_notifier); 118 119static int __fib_notifier_ops_register(struct fib_notifier_ops *ops, 120 struct net *net) 121{ 122 struct fib_notifier_ops *o; 123 124 list_for_each_entry(o, &net->fib_notifier_ops, list) 125 if (ops->family == o->family) 126 return -EEXIST; 127 list_add_tail_rcu(&ops->list, &net->fib_notifier_ops); 128 return 0; 129} 130 131struct fib_notifier_ops * 132fib_notifier_ops_register(const struct fib_notifier_ops *tmpl, struct net *net) 133{ 134 struct fib_notifier_ops *ops; 135 int err; 136 137 ops = kmemdup(tmpl, sizeof(*ops), GFP_KERNEL); 138 if (!ops) 139 return ERR_PTR(-ENOMEM); 140 141 err = __fib_notifier_ops_register(ops, net); 142 if (err) 143 goto err_register; 144 145 return ops; 146 147err_register: 148 kfree(ops); 149 return ERR_PTR(err); 150} 151EXPORT_SYMBOL(fib_notifier_ops_register); 152 153void fib_notifier_ops_unregister(struct fib_notifier_ops *ops) 154{ 155 list_del_rcu(&ops->list); 156 kfree_rcu(ops, rcu); 157} 158EXPORT_SYMBOL(fib_notifier_ops_unregister); 159 160static int __net_init fib_notifier_net_init(struct net *net) 161{ 162 INIT_LIST_HEAD(&net->fib_notifier_ops); 163 return 0; 164} 165 166static void __net_exit fib_notifier_net_exit(struct net *net) 167{ 168 WARN_ON_ONCE(!list_empty(&net->fib_notifier_ops)); 169} 170 171static struct pernet_operations fib_notifier_net_ops = { 172 .init = fib_notifier_net_init, 173 .exit = fib_notifier_net_exit, 174}; 175 176static int __init fib_notifier_init(void) 177{ 178 return register_pernet_subsys(&fib_notifier_net_ops); 179} 180 181subsys_initcall(fib_notifier_init);