Branch data Line data Source code
1 : : /* Linux multicast routing support
2 : : * Common logic shared by IPv4 [ipmr] and IPv6 [ip6mr] implementation
3 : : */
4 : :
5 : : #include <linux/rhashtable.h>
6 : : #include <linux/mroute_base.h>
7 : :
8 : : /* Sets everything common except 'dev', since that is done under locking */
9 : 0 : void vif_device_init(struct vif_device *v,
10 : : struct net_device *dev,
11 : : unsigned long rate_limit,
12 : : unsigned char threshold,
13 : : unsigned short flags,
14 : : unsigned short get_iflink_mask)
15 : : {
16 : 0 : v->dev = NULL;
17 : 0 : v->bytes_in = 0;
18 : 0 : v->bytes_out = 0;
19 : 0 : v->pkt_in = 0;
20 : 0 : v->pkt_out = 0;
21 : 0 : v->rate_limit = rate_limit;
22 : 0 : v->flags = flags;
23 : 0 : v->threshold = threshold;
24 [ # # ]: 0 : if (v->flags & get_iflink_mask)
25 : 0 : v->link = dev_get_iflink(dev);
26 : : else
27 : 0 : v->link = dev->ifindex;
28 : 0 : }
29 : : EXPORT_SYMBOL(vif_device_init);
30 : :
31 : : struct mr_table *
32 : 13 : mr_table_alloc(struct net *net, u32 id,
33 : : struct mr_table_ops *ops,
34 : : void (*expire_func)(struct timer_list *t),
35 : : void (*table_set)(struct mr_table *mrt,
36 : : struct net *net))
37 : : {
38 : 13 : struct mr_table *mrt;
39 : 13 : int err;
40 : :
41 : 13 : mrt = kzalloc(sizeof(*mrt), GFP_KERNEL);
42 [ + - ]: 13 : if (!mrt)
43 : : return ERR_PTR(-ENOMEM);
44 : 13 : mrt->id = id;
45 : 13 : write_pnet(&mrt->net, net);
46 : :
47 : 13 : mrt->ops = *ops;
48 : 13 : err = rhltable_init(&mrt->mfc_hash, mrt->ops.rht_params);
49 [ - + ]: 13 : if (err) {
50 : 0 : kfree(mrt);
51 : 0 : return ERR_PTR(err);
52 : : }
53 : 13 : INIT_LIST_HEAD(&mrt->mfc_cache_list);
54 : 13 : INIT_LIST_HEAD(&mrt->mfc_unres_queue);
55 : :
56 : 13 : timer_setup(&mrt->ipmr_expire_timer, expire_func, 0);
57 : :
58 : 13 : mrt->mroute_reg_vif_num = -1;
59 : 13 : table_set(mrt, net);
60 : 13 : return mrt;
61 : : }
62 : : EXPORT_SYMBOL(mr_table_alloc);
63 : :
64 : 0 : void *mr_mfc_find_parent(struct mr_table *mrt, void *hasharg, int parent)
65 : : {
66 : 0 : struct rhlist_head *tmp, *list;
67 : 0 : struct mr_mfc *c;
68 : :
69 : 0 : list = rhltable_lookup(&mrt->mfc_hash, hasharg, *mrt->ops.rht_params);
70 [ # # ]: 0 : rhl_for_each_entry_rcu(c, tmp, list, mnode)
71 [ # # # # ]: 0 : if (parent == -1 || parent == c->mfc_parent)
72 : 0 : return c;
73 : :
74 : : return NULL;
75 : : }
76 : : EXPORT_SYMBOL(mr_mfc_find_parent);
77 : :
78 : 0 : void *mr_mfc_find_any_parent(struct mr_table *mrt, int vifi)
79 : : {
80 : 0 : struct rhlist_head *tmp, *list;
81 : 0 : struct mr_mfc *c;
82 : :
83 : 0 : list = rhltable_lookup(&mrt->mfc_hash, mrt->ops.cmparg_any,
84 : 0 : *mrt->ops.rht_params);
85 [ # # ]: 0 : rhl_for_each_entry_rcu(c, tmp, list, mnode)
86 [ # # ]: 0 : if (c->mfc_un.res.ttls[vifi] < 255)
87 : 0 : return c;
88 : :
89 : : return NULL;
90 : : }
91 : : EXPORT_SYMBOL(mr_mfc_find_any_parent);
92 : :
93 : 0 : void *mr_mfc_find_any(struct mr_table *mrt, int vifi, void *hasharg)
94 : : {
95 : 0 : struct rhlist_head *tmp, *list;
96 : 0 : struct mr_mfc *c, *proxy;
97 : :
98 : 0 : list = rhltable_lookup(&mrt->mfc_hash, hasharg, *mrt->ops.rht_params);
99 [ # # ]: 0 : rhl_for_each_entry_rcu(c, tmp, list, mnode) {
100 [ # # ]: 0 : if (c->mfc_un.res.ttls[vifi] < 255)
101 : 0 : return c;
102 : :
103 : : /* It's ok if the vifi is part of the static tree */
104 : 0 : proxy = mr_mfc_find_any_parent(mrt, c->mfc_parent);
105 [ # # # # ]: 0 : if (proxy && proxy->mfc_un.res.ttls[vifi] < 255)
106 : 0 : return c;
107 : : }
108 : :
109 : 0 : return mr_mfc_find_any_parent(mrt, vifi);
110 : : }
111 : : EXPORT_SYMBOL(mr_mfc_find_any);
112 : :
113 : : #ifdef CONFIG_PROC_FS
114 : 0 : void *mr_vif_seq_idx(struct net *net, struct mr_vif_iter *iter, loff_t pos)
115 : : {
116 : 0 : struct mr_table *mrt = iter->mrt;
117 : :
118 [ # # # # ]: 0 : for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) {
119 [ # # # # ]: 0 : if (!VIF_EXISTS(mrt, iter->ct))
120 : 0 : continue;
121 [ # # ]: 0 : if (pos-- == 0)
122 : 0 : return &mrt->vif_table[iter->ct];
123 : : }
124 : : return NULL;
125 : : }
126 : : EXPORT_SYMBOL(mr_vif_seq_idx);
127 : :
128 : 0 : void *mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
129 : : {
130 : 0 : struct mr_vif_iter *iter = seq->private;
131 [ # # ]: 0 : struct net *net = seq_file_net(seq);
132 : 0 : struct mr_table *mrt = iter->mrt;
133 : :
134 : 0 : ++*pos;
135 [ # # ]: 0 : if (v == SEQ_START_TOKEN)
136 : 0 : return mr_vif_seq_idx(net, iter, 0);
137 : :
138 [ # # ]: 0 : while (++iter->ct < mrt->maxvif) {
139 [ # # ]: 0 : if (!VIF_EXISTS(mrt, iter->ct))
140 : 0 : continue;
141 : 0 : return &mrt->vif_table[iter->ct];
142 : : }
143 : : return NULL;
144 : : }
145 : : EXPORT_SYMBOL(mr_vif_seq_next);
146 : :
147 : 0 : void *mr_mfc_seq_idx(struct net *net,
148 : : struct mr_mfc_iter *it, loff_t pos)
149 : : {
150 : 0 : struct mr_table *mrt = it->mrt;
151 : 0 : struct mr_mfc *mfc;
152 : :
153 : 0 : rcu_read_lock();
154 : 0 : it->cache = &mrt->mfc_cache_list;
155 [ # # ]: 0 : list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list)
156 [ # # ]: 0 : if (pos-- == 0)
157 : 0 : return mfc;
158 : 0 : rcu_read_unlock();
159 : :
160 : 0 : spin_lock_bh(it->lock);
161 : 0 : it->cache = &mrt->mfc_unres_queue;
162 [ # # ]: 0 : list_for_each_entry(mfc, it->cache, list)
163 [ # # ]: 0 : if (pos-- == 0)
164 : 0 : return mfc;
165 : 0 : spin_unlock_bh(it->lock);
166 : :
167 : 0 : it->cache = NULL;
168 : 0 : return NULL;
169 : : }
170 : : EXPORT_SYMBOL(mr_mfc_seq_idx);
171 : :
172 : 0 : void *mr_mfc_seq_next(struct seq_file *seq, void *v,
173 : : loff_t *pos)
174 : : {
175 : 0 : struct mr_mfc_iter *it = seq->private;
176 [ # # ]: 0 : struct net *net = seq_file_net(seq);
177 : 0 : struct mr_table *mrt = it->mrt;
178 : 0 : struct mr_mfc *c = v;
179 : :
180 : 0 : ++*pos;
181 : :
182 [ # # ]: 0 : if (v == SEQ_START_TOKEN)
183 : 0 : return mr_mfc_seq_idx(net, seq->private, 0);
184 : :
185 [ # # ]: 0 : if (c->list.next != it->cache)
186 : 0 : return list_entry(c->list.next, struct mr_mfc, list);
187 : :
188 [ # # ]: 0 : if (it->cache == &mrt->mfc_unres_queue)
189 : 0 : goto end_of_list;
190 : :
191 : : /* exhausted cache_array, show unresolved */
192 : 0 : rcu_read_unlock();
193 : 0 : it->cache = &mrt->mfc_unres_queue;
194 : :
195 : 0 : spin_lock_bh(it->lock);
196 [ # # ]: 0 : if (!list_empty(it->cache))
197 : 0 : return list_first_entry(it->cache, struct mr_mfc, list);
198 : :
199 : 0 : end_of_list:
200 : 0 : spin_unlock_bh(it->lock);
201 : 0 : it->cache = NULL;
202 : :
203 : 0 : return NULL;
204 : : }
205 : : EXPORT_SYMBOL(mr_mfc_seq_next);
206 : : #endif
207 : :
208 : 0 : int mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
209 : : struct mr_mfc *c, struct rtmsg *rtm)
210 : : {
211 : 0 : struct rta_mfc_stats mfcs;
212 : 0 : struct nlattr *mp_attr;
213 : 0 : struct rtnexthop *nhp;
214 : 0 : unsigned long lastuse;
215 : 0 : int ct;
216 : :
217 : : /* If cache is unresolved, don't try to parse IIF and OIF */
218 [ # # ]: 0 : if (c->mfc_parent >= MAXVIFS) {
219 : 0 : rtm->rtm_flags |= RTNH_F_UNRESOLVED;
220 : 0 : return -ENOENT;
221 : : }
222 : :
223 [ # # # # ]: 0 : if (VIF_EXISTS(mrt, c->mfc_parent) &&
224 : 0 : nla_put_u32(skb, RTA_IIF,
225 : 0 : mrt->vif_table[c->mfc_parent].dev->ifindex) < 0)
226 : : return -EMSGSIZE;
227 : :
228 [ # # ]: 0 : if (c->mfc_flags & MFC_OFFLOAD)
229 : 0 : rtm->rtm_flags |= RTNH_F_OFFLOAD;
230 : :
231 : 0 : mp_attr = nla_nest_start_noflag(skb, RTA_MULTIPATH);
232 [ # # ]: 0 : if (!mp_attr)
233 : : return -EMSGSIZE;
234 : :
235 [ # # ]: 0 : for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
236 [ # # # # ]: 0 : if (VIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
237 : 0 : struct vif_device *vif;
238 : :
239 : 0 : nhp = nla_reserve_nohdr(skb, sizeof(*nhp));
240 [ # # ]: 0 : if (!nhp) {
241 : 0 : nla_nest_cancel(skb, mp_attr);
242 : 0 : return -EMSGSIZE;
243 : : }
244 : :
245 : 0 : nhp->rtnh_flags = 0;
246 : 0 : nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
247 : 0 : vif = &mrt->vif_table[ct];
248 : 0 : nhp->rtnh_ifindex = vif->dev->ifindex;
249 : 0 : nhp->rtnh_len = sizeof(*nhp);
250 : : }
251 : : }
252 : :
253 [ # # ]: 0 : nla_nest_end(skb, mp_attr);
254 : :
255 [ # # ]: 0 : lastuse = READ_ONCE(c->mfc_un.res.lastuse);
256 [ # # ]: 0 : lastuse = time_after_eq(jiffies, lastuse) ? jiffies - lastuse : 0;
257 : :
258 : 0 : mfcs.mfcs_packets = c->mfc_un.res.pkt;
259 : 0 : mfcs.mfcs_bytes = c->mfc_un.res.bytes;
260 : 0 : mfcs.mfcs_wrong_if = c->mfc_un.res.wrong_if;
261 [ # # # # ]: 0 : if (nla_put_64bit(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs, RTA_PAD) ||
262 : 0 : nla_put_u64_64bit(skb, RTA_EXPIRES, jiffies_to_clock_t(lastuse),
263 : : RTA_PAD))
264 : 0 : return -EMSGSIZE;
265 : :
266 : 0 : rtm->rtm_type = RTN_MULTICAST;
267 : 0 : return 1;
268 : : }
269 : : EXPORT_SYMBOL(mr_fill_mroute);
270 : :
271 : 0 : static bool mr_mfc_uses_dev(const struct mr_table *mrt,
272 : : const struct mr_mfc *c,
273 : : const struct net_device *dev)
274 : : {
275 : 0 : int ct;
276 : :
277 [ # # # # ]: 0 : for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
278 [ # # # # : 0 : if (VIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
# # # # ]
279 : 0 : const struct vif_device *vif;
280 : :
281 : 0 : vif = &mrt->vif_table[ct];
282 [ # # # # ]: 0 : if (vif->dev == dev)
283 : : return true;
284 : : }
285 : : }
286 : : return false;
287 : : }
288 : :
289 : 0 : int mr_table_dump(struct mr_table *mrt, struct sk_buff *skb,
290 : : struct netlink_callback *cb,
291 : : int (*fill)(struct mr_table *mrt, struct sk_buff *skb,
292 : : u32 portid, u32 seq, struct mr_mfc *c,
293 : : int cmd, int flags),
294 : : spinlock_t *lock, struct fib_dump_filter *filter)
295 : : {
296 : 0 : unsigned int e = 0, s_e = cb->args[1];
297 : 0 : unsigned int flags = NLM_F_MULTI;
298 : 0 : struct mr_mfc *mfc;
299 : 0 : int err;
300 : :
301 [ # # ]: 0 : if (filter->filter_set)
302 : 0 : flags |= NLM_F_DUMP_FILTERED;
303 : :
304 [ # # ]: 0 : list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
305 [ # # ]: 0 : if (e < s_e)
306 : 0 : goto next_entry;
307 [ # # # # ]: 0 : if (filter->dev &&
308 : : !mr_mfc_uses_dev(mrt, mfc, filter->dev))
309 : 0 : goto next_entry;
310 : :
311 : 0 : err = fill(mrt, skb, NETLINK_CB(cb->skb).portid,
312 : 0 : cb->nlh->nlmsg_seq, mfc, RTM_NEWROUTE, flags);
313 [ # # ]: 0 : if (err < 0)
314 : 0 : goto out;
315 : 0 : next_entry:
316 : 0 : e++;
317 : : }
318 : :
319 : 0 : spin_lock_bh(lock);
320 [ # # ]: 0 : list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) {
321 [ # # ]: 0 : if (e < s_e)
322 : 0 : goto next_entry2;
323 [ # # # # ]: 0 : if (filter->dev &&
324 : : !mr_mfc_uses_dev(mrt, mfc, filter->dev))
325 : 0 : goto next_entry2;
326 : :
327 : 0 : err = fill(mrt, skb, NETLINK_CB(cb->skb).portid,
328 : 0 : cb->nlh->nlmsg_seq, mfc, RTM_NEWROUTE, flags);
329 [ # # ]: 0 : if (err < 0) {
330 : 0 : spin_unlock_bh(lock);
331 : 0 : goto out;
332 : : }
333 : 0 : next_entry2:
334 : 0 : e++;
335 : : }
336 : 0 : spin_unlock_bh(lock);
337 : 0 : err = 0;
338 : 0 : out:
339 : 0 : cb->args[1] = e;
340 : 0 : return err;
341 : : }
342 : : EXPORT_SYMBOL(mr_table_dump);
343 : :
344 : 0 : int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb,
345 : : struct mr_table *(*iter)(struct net *net,
346 : : struct mr_table *mrt),
347 : : int (*fill)(struct mr_table *mrt,
348 : : struct sk_buff *skb,
349 : : u32 portid, u32 seq, struct mr_mfc *c,
350 : : int cmd, int flags),
351 : : spinlock_t *lock, struct fib_dump_filter *filter)
352 : : {
353 : 0 : unsigned int t = 0, s_t = cb->args[0];
354 [ # # ]: 0 : struct net *net = sock_net(skb->sk);
355 : 0 : struct mr_table *mrt;
356 : 0 : int err;
357 : :
358 : : /* multicast does not track protocol or have route type other
359 : : * than RTN_MULTICAST
360 : : */
361 [ # # ]: 0 : if (filter->filter_set) {
362 [ # # ]: 0 : if (filter->protocol || filter->flags ||
363 [ # # ]: 0 : (filter->rt_type && filter->rt_type != RTN_MULTICAST))
364 : 0 : return skb->len;
365 : : }
366 : :
367 : 0 : rcu_read_lock();
368 [ # # ]: 0 : for (mrt = iter(net, NULL); mrt; mrt = iter(net, mrt)) {
369 [ # # ]: 0 : if (t < s_t)
370 : 0 : goto next_table;
371 : :
372 : 0 : err = mr_table_dump(mrt, skb, cb, fill, lock, filter);
373 [ # # ]: 0 : if (err < 0)
374 : : break;
375 : 0 : cb->args[1] = 0;
376 : 0 : next_table:
377 : 0 : t++;
378 : : }
379 : 0 : rcu_read_unlock();
380 : :
381 : 0 : cb->args[0] = t;
382 : :
383 : 0 : return skb->len;
384 : : }
385 : : EXPORT_SYMBOL(mr_rtm_dumproute);
386 : :
387 : 0 : int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family,
388 : : int (*rules_dump)(struct net *net,
389 : : struct notifier_block *nb,
390 : : struct netlink_ext_ack *extack),
391 : : struct mr_table *(*mr_iter)(struct net *net,
392 : : struct mr_table *mrt),
393 : : rwlock_t *mrt_lock,
394 : : struct netlink_ext_ack *extack)
395 : : {
396 : 0 : struct mr_table *mrt;
397 : 0 : int err;
398 : :
399 : 0 : err = rules_dump(net, nb, extack);
400 [ # # ]: 0 : if (err)
401 : : return err;
402 : :
403 [ # # ]: 0 : for (mrt = mr_iter(net, NULL); mrt; mrt = mr_iter(net, mrt)) {
404 : 0 : struct vif_device *v = &mrt->vif_table[0];
405 : 0 : struct mr_mfc *mfc;
406 : 0 : int vifi;
407 : :
408 : : /* Notifiy on table VIF entries */
409 : 0 : read_lock(mrt_lock);
410 [ # # ]: 0 : for (vifi = 0; vifi < mrt->maxvif; vifi++, v++) {
411 [ # # ]: 0 : if (!v->dev)
412 : 0 : continue;
413 : :
414 : 0 : err = mr_call_vif_notifier(nb, family,
415 : : FIB_EVENT_VIF_ADD,
416 : : v, vifi, mrt->id, extack);
417 [ # # ]: 0 : if (err)
418 : : break;
419 : : }
420 : 0 : read_unlock(mrt_lock);
421 : :
422 [ # # ]: 0 : if (err)
423 : 0 : return err;
424 : :
425 : : /* Notify on table MFC entries */
426 [ # # ]: 0 : list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
427 : 0 : err = mr_call_mfc_notifier(nb, family,
428 : : FIB_EVENT_ENTRY_ADD,
429 : : mfc, mrt->id, extack);
430 [ # # ]: 0 : if (err)
431 : 0 : return err;
432 : : }
433 : : }
434 : :
435 : : return 0;
436 : : }
437 : : EXPORT_SYMBOL(mr_dump);
|