From: David Ahern <dsah...@gmail.com> Implement kernel side filtering of routes by table id, egress device index, protocol, tos, scope, and route type.
Signed-off-by: David Ahern <dsah...@gmail.com> --- include/net/ip_fib.h | 2 +- net/ipv4/fib_frontend.c | 13 ++++++++++++- net/ipv4/fib_trie.c | 33 ++++++++++++++++++++++----------- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index d0cd838ca00c..e064c37a2a9f 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -240,7 +240,7 @@ int fib_table_insert(struct net *, struct fib_table *, struct fib_config *, int fib_table_delete(struct net *, struct fib_table *, struct fib_config *, struct netlink_ext_ack *extack); int fib_table_dump(struct fib_table *table, struct sk_buff *skb, - struct netlink_callback *cb); + struct netlink_callback *cb, struct fib_dump_filter *filter); int fib_table_flush(struct net *net, struct fib_table *table); struct fib_table *fib_trie_unmerge(struct fib_table *main_tb); void fib_table_flush_external(struct fib_table *table); diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 9d872a4900cd..a3f4073e509a 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -861,16 +861,27 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) rcu_read_lock(); + if (filter.ifindex) { + filter.dev = dev_get_by_index_rcu(net, filter.ifindex); + if (!filter.dev) { + err = -ENODEV; + goto out_err; + } + } + for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) { e = 0; head = &net->ipv4.fib_table_hash[h]; hlist_for_each_entry_rcu(tb, head, tb_hlist) { if (e < s_e) goto next; + if (filter.table_id && filter.table_id != tb->tb_id) + goto next; + if (dumped) memset(&cb->args[2], 0, sizeof(cb->args) - 2 * sizeof(cb->args[0])); - err = fib_table_dump(tb, skb, cb); + err = fib_table_dump(tb, skb, cb, &filter); if (err < 0) { if (likely(skb->len)) goto out; diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 5bc0c89e81e4..0e7b4233851a 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2003,7 +2003,8 @@ void fib_free_table(struct fib_table *tb) } static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb, - struct sk_buff *skb, struct netlink_callback *cb) + struct sk_buff *skb, struct netlink_callback *cb, + struct fib_dump_filter *filter) { __be32 xkey = htonl(l->key); struct fib_alias *fa; @@ -2016,15 +2017,24 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb, hlist_for_each_entry_rcu(fa, &l->leaf, fa_list) { int err; - if (i < s_i) { - i++; - continue; - } + if (i < s_i) + goto next; - if (tb->tb_id != fa->tb_id) { - i++; - continue; - } + if (tb->tb_id != fa->tb_id) + goto next; + + if ((filter->tos && fa->fa_tos != filter->tos) || + (filter->rt_type && fa->fa_type != filter->rt_type)) + goto next; + + if ((filter->protocol && + fa->fa_info->fib_protocol != filter->protocol) || + (filter->scope && fa->fa_info->fib_scope != filter->scope)) + goto next; + + if (filter->dev && + !fib_info_nh_uses_dev(fa->fa_info, filter->dev)) + goto next; err = fib_dump_info(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, RTM_NEWROUTE, @@ -2035,6 +2045,7 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb, cb->args[4] = i; return err; } +next: i++; } @@ -2044,7 +2055,7 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb, /* rcu_read_lock needs to be hold by caller from readside */ int fib_table_dump(struct fib_table *tb, struct sk_buff *skb, - struct netlink_callback *cb) + struct netlink_callback *cb, struct fib_dump_filter *filter) { struct trie *t = (struct trie *)tb->tb_data; struct key_vector *l, *tp = t->kv; @@ -2057,7 +2068,7 @@ int fib_table_dump(struct fib_table *tb, struct sk_buff *skb, while ((l = leaf_walk_rcu(&tp, key)) != NULL) { int err; - err = fn_trie_dump_leaf(l, tb, skb, cb); + err = fn_trie_dump_leaf(l, tb, skb, cb, filter); if (err < 0) { cb->args[3] = key; cb->args[2] = count; -- 2.11.0