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