Branch data Line data Source code
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 : 0 : 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 : 0 : info->net = net;
26 : 0 : err = nb->notifier_call(nb, event_type, info);
27 : 0 : return notifier_to_errno(err);
28 : : }
29 : : EXPORT_SYMBOL(call_fib_notifier);
30 : :
31 : 3334 : 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 : 3334 : info->net = net;
37 : 3334 : err = atomic_notifier_call_chain(&fib_chain, event_type, info);
38 : 3334 : return notifier_to_errno(err);
39 : : }
40 : : EXPORT_SYMBOL(call_fib_notifiers);
41 : :
42 : 0 : 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 : 0 : rtnl_lock();
50 : 0 : down_read(&net_rwsem);
51 [ # # ]: 0 : for_each_net(net) {
52 : 0 : fn_net = net_generic(net, fib_notifier_net_id);
53 : : rcu_read_lock();
54 [ # # ]: 0 : list_for_each_entry_rcu(ops, &fn_net->fib_notifier_ops, list) {
55 [ # # ]: 0 : if (!try_module_get(ops->owner))
56 : 0 : continue;
57 : 0 : fib_seq += ops->fib_seq_read(net);
58 : 0 : module_put(ops->owner);
59 : : }
60 : : rcu_read_unlock();
61 : : }
62 : 0 : up_read(&net_rwsem);
63 : 0 : rtnl_unlock();
64 : :
65 : 0 : return fib_seq;
66 : : }
67 : :
68 : 0 : static int fib_net_dump(struct net *net, struct notifier_block *nb)
69 : : {
70 : 0 : struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id);
71 : : struct fib_notifier_ops *ops;
72 : :
73 [ # # ]: 0 : list_for_each_entry_rcu(ops, &fn_net->fib_notifier_ops, list) {
74 : : int err;
75 : :
76 [ # # ]: 0 : if (!try_module_get(ops->owner))
77 : 0 : continue;
78 : 0 : err = ops->fib_dump(net, nb);
79 : 0 : module_put(ops->owner);
80 [ # # ]: 0 : if (err)
81 : 0 : return err;
82 : : }
83 : :
84 : : return 0;
85 : : }
86 : :
87 : 0 : static bool fib_dump_is_consistent(struct notifier_block *nb,
88 : : void (*cb)(struct notifier_block *nb),
89 : : unsigned int fib_seq)
90 : : {
91 : 0 : atomic_notifier_chain_register(&fib_chain, nb);
92 [ # # ]: 0 : if (fib_seq == fib_seq_sum())
93 : : return true;
94 : 0 : atomic_notifier_chain_unregister(&fib_chain, nb);
95 [ # # ]: 0 : if (cb)
96 : 0 : cb(nb);
97 : : return false;
98 : : }
99 : :
100 : : #define FIB_DUMP_MAX_RETRIES 5
101 : 0 : 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 : 0 : unsigned int fib_seq = fib_seq_sum();
109 : : struct net *net;
110 : :
111 : : rcu_read_lock();
112 [ # # ]: 0 : for_each_net_rcu(net) {
113 : 0 : err = fib_net_dump(net, nb);
114 [ # # ]: 0 : if (err)
115 : : goto err_fib_net_dump;
116 : : }
117 : : rcu_read_unlock();
118 : :
119 [ # # ]: 0 : if (fib_dump_is_consistent(nb, cb, fib_seq))
120 : : return 0;
121 [ # # ]: 0 : } while (++retries < FIB_DUMP_MAX_RETRIES);
122 : :
123 : : return -EBUSY;
124 : :
125 : : err_fib_net_dump:
126 : : rcu_read_unlock();
127 : 0 : return err;
128 : : }
129 : : EXPORT_SYMBOL(register_fib_notifier);
130 : :
131 : 0 : int unregister_fib_notifier(struct notifier_block *nb)
132 : : {
133 : 0 : return atomic_notifier_chain_unregister(&fib_chain, nb);
134 : : }
135 : : EXPORT_SYMBOL(unregister_fib_notifier);
136 : :
137 : 828 : static int __fib_notifier_ops_register(struct fib_notifier_ops *ops,
138 : : struct net *net)
139 : : {
140 : 828 : struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id);
141 : : struct fib_notifier_ops *o;
142 : :
143 [ + + ]: 2070 : list_for_each_entry(o, &fn_net->fib_notifier_ops, list)
144 [ + - ]: 1242 : if (ops->family == o->family)
145 : : return -EEXIST;
146 : 828 : list_add_tail_rcu(&ops->list, &fn_net->fib_notifier_ops);
147 : 828 : return 0;
148 : : }
149 : :
150 : : struct fib_notifier_ops *
151 : 828 : 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 : 828 : ops = kmemdup(tmpl, sizeof(*ops), GFP_KERNEL);
157 [ + - ]: 828 : if (!ops)
158 : : return ERR_PTR(-ENOMEM);
159 : :
160 : 828 : err = __fib_notifier_ops_register(ops, net);
161 [ - + ]: 828 : if (err)
162 : : goto err_register;
163 : :
164 : : return ops;
165 : :
166 : : err_register:
167 : 0 : kfree(ops);
168 : 0 : return ERR_PTR(err);
169 : : }
170 : : EXPORT_SYMBOL(fib_notifier_ops_register);
171 : :
172 : 0 : void fib_notifier_ops_unregister(struct fib_notifier_ops *ops)
173 : : {
174 : : list_del_rcu(&ops->list);
175 [ # # ]: 0 : kfree_rcu(ops, rcu);
176 : 0 : }
177 : : EXPORT_SYMBOL(fib_notifier_ops_unregister);
178 : :
179 : 207 : static int __net_init fib_notifier_net_init(struct net *net)
180 : : {
181 : 207 : struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id);
182 : :
183 : 207 : INIT_LIST_HEAD(&fn_net->fib_notifier_ops);
184 : 207 : return 0;
185 : : }
186 : :
187 : 0 : static void __net_exit fib_notifier_net_exit(struct net *net)
188 : : {
189 : 0 : struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id);
190 : :
191 [ # # # # ]: 0 : WARN_ON_ONCE(!list_empty(&fn_net->fib_notifier_ops));
192 : 0 : }
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 : 207 : static int __init fib_notifier_init(void)
202 : : {
203 : 207 : return register_pernet_subsys(&fib_notifier_net_ops);
204 : : }
205 : :
206 : : subsys_initcall(fib_notifier_init);
|