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