Skip to content

Commit cb16789

Browse files
dsaherndavem330
authored andcommitted
net: Plumb support for filtering ipv4 and ipv6 multicast route dumps
Implement kernel side filtering of routes by egress device index and table id. If the table id is given in the filter, lookup table and call mr_table_dump directly for it. Signed-off-by: David Ahern <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e1cedae commit cb16789

File tree

4 files changed

+74
-12
lines changed

4 files changed

+74
-12
lines changed

include/linux/mroute_base.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <net/net_namespace.h>
88
#include <net/sock.h>
99
#include <net/fib_notifier.h>
10+
#include <net/ip_fib.h>
1011

1112
/**
1213
* struct vif_device - interface representor for multicast routing
@@ -288,15 +289,15 @@ int mr_table_dump(struct mr_table *mrt, struct sk_buff *skb,
288289
int (*fill)(struct mr_table *mrt, struct sk_buff *skb,
289290
u32 portid, u32 seq, struct mr_mfc *c,
290291
int cmd, int flags),
291-
spinlock_t *lock);
292+
spinlock_t *lock, struct fib_dump_filter *filter);
292293
int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb,
293294
struct mr_table *(*iter)(struct net *net,
294295
struct mr_table *mrt),
295296
int (*fill)(struct mr_table *mrt,
296297
struct sk_buff *skb,
297298
u32 portid, u32 seq, struct mr_mfc *c,
298299
int cmd, int flags),
299-
spinlock_t *lock);
300+
spinlock_t *lock, struct fib_dump_filter *filter);
300301

301302
int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family,
302303
int (*rules_dump)(struct net *net,
@@ -346,7 +347,7 @@ mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb,
346347
struct sk_buff *skb,
347348
u32 portid, u32 seq, struct mr_mfc *c,
348349
int cmd, int flags),
349-
spinlock_t *lock)
350+
spinlock_t *lock, struct fib_dump_filter *filter)
350351
{
351352
return -EINVAL;
352353
}

net/ipv4/ipmr.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2528,18 +2528,30 @@ static int ipmr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
25282528
static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
25292529
{
25302530
struct fib_dump_filter filter = {};
2531+
int err;
25312532

25322533
if (cb->strict_check) {
2533-
int err;
2534-
25352534
err = ip_valid_fib_dump_req(sock_net(skb->sk), cb->nlh,
25362535
&filter, cb->extack);
25372536
if (err < 0)
25382537
return err;
25392538
}
25402539

2540+
if (filter.table_id) {
2541+
struct mr_table *mrt;
2542+
2543+
mrt = ipmr_get_table(sock_net(skb->sk), filter.table_id);
2544+
if (!mrt) {
2545+
NL_SET_ERR_MSG(cb->extack, "ipv4: MR table does not exist");
2546+
return -ENOENT;
2547+
}
2548+
err = mr_table_dump(mrt, skb, cb, _ipmr_fill_mroute,
2549+
&mfc_unres_lock, &filter);
2550+
return skb->len ? : err;
2551+
}
2552+
25412553
return mr_rtm_dumproute(skb, cb, ipmr_mr_table_iter,
2542-
_ipmr_fill_mroute, &mfc_unres_lock);
2554+
_ipmr_fill_mroute, &mfc_unres_lock, &filter);
25432555
}
25442556

25452557
static const struct nla_policy rtm_ipmr_policy[RTA_MAX + 1] = {

net/ipv4/ipmr_base.c

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,21 +268,45 @@ int mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
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+
271289
int mr_table_dump(struct mr_table *mrt, struct sk_buff *skb,
272290
struct netlink_callback *cb,
273291
int (*fill)(struct mr_table *mrt, struct sk_buff *skb,
274292
u32 portid, u32 seq, struct mr_mfc *c,
275293
int cmd, int flags),
276-
spinlock_t *lock)
294+
spinlock_t *lock, struct fib_dump_filter *filter)
277295
{
278296
unsigned int e = 0, s_e = cb->args[1];
279297
unsigned int flags = NLM_F_MULTI;
280298
struct mr_mfc *mfc;
281299
int err;
282300

301+
if (filter->filter_set)
302+
flags |= NLM_F_DUMP_FILTERED;
303+
283304
list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
284305
if (e < s_e)
285306
goto next_entry;
307+
if (filter->dev &&
308+
!mr_mfc_uses_dev(mrt, mfc, filter->dev))
309+
goto next_entry;
286310

287311
err = fill(mrt, skb, NETLINK_CB(cb->skb).portid,
288312
cb->nlh->nlmsg_seq, mfc, RTM_NEWROUTE, flags);
@@ -298,6 +322,9 @@ int mr_table_dump(struct mr_table *mrt, struct sk_buff *skb,
298322
list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) {
299323
if (e < s_e)
300324
goto next_entry2;
325+
if (filter->dev &&
326+
!mr_mfc_uses_dev(mrt, mfc, filter->dev))
327+
goto next_entry2;
301328

302329
err = fill(mrt, skb, NETLINK_CB(cb->skb).portid,
303330
cb->nlh->nlmsg_seq, mfc, RTM_NEWROUTE, flags);
@@ -316,6 +343,7 @@ int mr_table_dump(struct mr_table *mrt, struct sk_buff *skb,
316343
cb->args[1] = e;
317344
return err;
318345
}
346+
EXPORT_SYMBOL(mr_table_dump);
319347

320348
int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb,
321349
struct mr_table *(*iter)(struct net *net,
@@ -324,19 +352,28 @@ int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb,
324352
struct sk_buff *skb,
325353
u32 portid, u32 seq, struct mr_mfc *c,
326354
int cmd, int flags),
327-
spinlock_t *lock)
355+
spinlock_t *lock, struct fib_dump_filter *filter)
328356
{
329357
unsigned int t = 0, s_t = cb->args[0];
330358
struct net *net = sock_net(skb->sk);
331359
struct mr_table *mrt;
332360
int err;
333361

362+
/* multicast does not track protocol or have route type other
363+
* than RTN_MULTICAST
364+
*/
365+
if (filter->filter_set) {
366+
if (filter->protocol || filter->flags ||
367+
(filter->rt_type && filter->rt_type != RTN_MULTICAST))
368+
return skb->len;
369+
}
370+
334371
rcu_read_lock();
335372
for (mrt = iter(net, NULL); mrt; mrt = iter(net, mrt)) {
336373
if (t < s_t)
337374
goto next_table;
338375

339-
err = mr_table_dump(mrt, skb, cb, fill, lock);
376+
err = mr_table_dump(mrt, skb, cb, fill, lock, filter);
340377
if (err < 0)
341378
break;
342379
next_table:

net/ipv6/ip6mr.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2459,16 +2459,28 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
24592459
{
24602460
const struct nlmsghdr *nlh = cb->nlh;
24612461
struct fib_dump_filter filter = {};
2462+
int err;
24622463

24632464
if (cb->strict_check) {
2464-
int err;
2465-
24662465
err = ip_valid_fib_dump_req(sock_net(skb->sk), nlh,
24672466
&filter, cb->extack);
24682467
if (err < 0)
24692468
return err;
24702469
}
24712470

2471+
if (filter.table_id) {
2472+
struct mr_table *mrt;
2473+
2474+
mrt = ip6mr_get_table(sock_net(skb->sk), filter.table_id);
2475+
if (!mrt) {
2476+
NL_SET_ERR_MSG_MOD(cb->extack, "MR table does not exist");
2477+
return -ENOENT;
2478+
}
2479+
err = mr_table_dump(mrt, skb, cb, _ip6mr_fill_mroute,
2480+
&mfc_unres_lock, &filter);
2481+
return skb->len ? : err;
2482+
}
2483+
24722484
return mr_rtm_dumproute(skb, cb, ip6mr_mr_table_iter,
2473-
_ip6mr_fill_mroute, &mfc_unres_lock);
2485+
_ip6mr_fill_mroute, &mfc_unres_lock, &filter);
24742486
}

0 commit comments

Comments
 (0)