hc
2024-05-16 8d2a02b24d66aa359e83eebc1ed3c0f85367a1cb
kernel/net/ipv4/ipmr_base.c
....@@ -228,7 +228,7 @@
228228 if (c->mfc_flags & MFC_OFFLOAD)
229229 rtm->rtm_flags |= RTNH_F_OFFLOAD;
230230
231
- mp_attr = nla_nest_start(skb, RTA_MULTIPATH);
231
+ mp_attr = nla_nest_start_noflag(skb, RTA_MULTIPATH);
232232 if (!mp_attr)
233233 return -EMSGSIZE;
234234
....@@ -268,6 +268,79 @@
268268 }
269269 EXPORT_SYMBOL(mr_fill_mroute);
270270
271
+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
+ int ct;
276
+
277
+ for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
278
+ if (VIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
279
+ const struct vif_device *vif;
280
+
281
+ vif = &mrt->vif_table[ct];
282
+ if (vif->dev == dev)
283
+ return true;
284
+ }
285
+ }
286
+ return false;
287
+}
288
+
289
+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
+ unsigned int e = 0, s_e = cb->args[1];
297
+ unsigned int flags = NLM_F_MULTI;
298
+ struct mr_mfc *mfc;
299
+ int err;
300
+
301
+ if (filter->filter_set)
302
+ flags |= NLM_F_DUMP_FILTERED;
303
+
304
+ list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
305
+ if (e < s_e)
306
+ goto next_entry;
307
+ if (filter->dev &&
308
+ !mr_mfc_uses_dev(mrt, mfc, filter->dev))
309
+ goto next_entry;
310
+
311
+ err = fill(mrt, skb, NETLINK_CB(cb->skb).portid,
312
+ cb->nlh->nlmsg_seq, mfc, RTM_NEWROUTE, flags);
313
+ if (err < 0)
314
+ goto out;
315
+next_entry:
316
+ e++;
317
+ }
318
+
319
+ spin_lock_bh(lock);
320
+ list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) {
321
+ if (e < s_e)
322
+ goto next_entry2;
323
+ if (filter->dev &&
324
+ !mr_mfc_uses_dev(mrt, mfc, filter->dev))
325
+ goto next_entry2;
326
+
327
+ err = fill(mrt, skb, NETLINK_CB(cb->skb).portid,
328
+ cb->nlh->nlmsg_seq, mfc, RTM_NEWROUTE, flags);
329
+ if (err < 0) {
330
+ spin_unlock_bh(lock);
331
+ goto out;
332
+ }
333
+next_entry2:
334
+ e++;
335
+ }
336
+ spin_unlock_bh(lock);
337
+ err = 0;
338
+out:
339
+ cb->args[1] = e;
340
+ return err;
341
+}
342
+EXPORT_SYMBOL(mr_table_dump);
343
+
271344 int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb,
272345 struct mr_table *(*iter)(struct net *net,
273346 struct mr_table *mrt),
....@@ -275,51 +348,36 @@
275348 struct sk_buff *skb,
276349 u32 portid, u32 seq, struct mr_mfc *c,
277350 int cmd, int flags),
278
- spinlock_t *lock)
351
+ spinlock_t *lock, struct fib_dump_filter *filter)
279352 {
280
- unsigned int t = 0, e = 0, s_t = cb->args[0], s_e = cb->args[1];
353
+ unsigned int t = 0, s_t = cb->args[0];
281354 struct net *net = sock_net(skb->sk);
282355 struct mr_table *mrt;
283
- struct mr_mfc *mfc;
356
+ int err;
357
+
358
+ /* multicast does not track protocol or have route type other
359
+ * than RTN_MULTICAST
360
+ */
361
+ if (filter->filter_set) {
362
+ if (filter->protocol || filter->flags ||
363
+ (filter->rt_type && filter->rt_type != RTN_MULTICAST))
364
+ return skb->len;
365
+ }
284366
285367 rcu_read_lock();
286368 for (mrt = iter(net, NULL); mrt; mrt = iter(net, mrt)) {
287369 if (t < s_t)
288370 goto next_table;
289
- list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
290
- if (e < s_e)
291
- goto next_entry;
292
- if (fill(mrt, skb, NETLINK_CB(cb->skb).portid,
293
- cb->nlh->nlmsg_seq, mfc,
294
- RTM_NEWROUTE, NLM_F_MULTI) < 0)
295
- goto done;
296
-next_entry:
297
- e++;
298
- }
299371
300
- spin_lock_bh(lock);
301
- list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) {
302
- if (e < s_e)
303
- goto next_entry2;
304
- if (fill(mrt, skb, NETLINK_CB(cb->skb).portid,
305
- cb->nlh->nlmsg_seq, mfc,
306
- RTM_NEWROUTE, NLM_F_MULTI) < 0) {
307
- spin_unlock_bh(lock);
308
- goto done;
309
- }
310
-next_entry2:
311
- e++;
312
- }
313
- spin_unlock_bh(lock);
314
- e = 0;
315
- s_e = 0;
372
+ err = mr_table_dump(mrt, skb, cb, fill, lock, filter);
373
+ if (err < 0)
374
+ break;
375
+ cb->args[1] = 0;
316376 next_table:
317377 t++;
318378 }
319
-done:
320379 rcu_read_unlock();
321380
322
- cb->args[1] = e;
323381 cb->args[0] = t;
324382
325383 return skb->len;
....@@ -328,15 +386,17 @@
328386
329387 int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family,
330388 int (*rules_dump)(struct net *net,
331
- struct notifier_block *nb),
389
+ struct notifier_block *nb,
390
+ struct netlink_ext_ack *extack),
332391 struct mr_table *(*mr_iter)(struct net *net,
333392 struct mr_table *mrt),
334
- rwlock_t *mrt_lock)
393
+ rwlock_t *mrt_lock,
394
+ struct netlink_ext_ack *extack)
335395 {
336396 struct mr_table *mrt;
337397 int err;
338398
339
- err = rules_dump(net, nb);
399
+ err = rules_dump(net, nb, extack);
340400 if (err)
341401 return err;
342402
....@@ -351,17 +411,25 @@
351411 if (!v->dev)
352412 continue;
353413
354
- mr_call_vif_notifier(nb, net, family,
355
- FIB_EVENT_VIF_ADD,
356
- v, vifi, mrt->id);
414
+ err = mr_call_vif_notifier(nb, family,
415
+ FIB_EVENT_VIF_ADD,
416
+ v, vifi, mrt->id, extack);
417
+ if (err)
418
+ break;
357419 }
358420 read_unlock(mrt_lock);
359421
422
+ if (err)
423
+ return err;
424
+
360425 /* Notify on table MFC entries */
361
- list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list)
362
- mr_call_mfc_notifier(nb, net, family,
363
- FIB_EVENT_ENTRY_ADD,
364
- mfc, mrt->id);
426
+ list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
427
+ err = mr_call_mfc_notifier(nb, family,
428
+ FIB_EVENT_ENTRY_ADD,
429
+ mfc, mrt->id, extack);
430
+ if (err)
431
+ return err;
432
+ }
365433 }
366434
367435 return 0;