Skip to content

Commit

Permalink
net/ipv4: Plumb support for filtering route dumps
Browse files Browse the repository at this point in the history
Implement kernel side filtering of routes by table id, egress device index,
protocol and route type. If the table id is given in the filter, lookup the
table and call fib_table_dump directly for it.

Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David Ahern authored and David S. Miller committed Oct 16, 2018
1 parent 4724676 commit 18a8021
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 13 deletions.
2 changes: 1 addition & 1 deletion include/net/ip_fib.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,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);
Expand Down
13 changes: 12 additions & 1 deletion net/ipv4/fib_frontend.c
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,17 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
((struct rtmsg *)nlmsg_data(nlh))->rtm_flags & RTM_F_CLONED)
return skb->len;

if (filter.table_id) {
tb = fib_get_table(net, filter.table_id);
if (!tb) {
NL_SET_ERR_MSG(cb->extack, "ipv4: FIB table does not exist");
return -ENOENT;
}

err = fib_table_dump(tb, skb, cb, &filter);
return skb->len ? : err;
}

s_h = cb->args[0];
s_e = cb->args[1];

Expand All @@ -869,7 +880,7 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
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;
Expand Down
37 changes: 26 additions & 11 deletions net/ipv4/fib_trie.c
Original file line number Diff line number Diff line change
Expand Up @@ -2003,38 +2003,53 @@ 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)
{
unsigned int flags = NLM_F_MULTI;
__be32 xkey = htonl(l->key);
struct fib_alias *fa;
int i, s_i;

if (filter->filter_set)
flags |= NLM_F_DUMP_FILTERED;

s_i = cb->args[4];
i = 0;

/* rcu_read_lock is hold by caller */
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->filter_set) {
if (filter->rt_type && fa->fa_type != filter->rt_type)
goto next;

if ((filter->protocol &&
fa->fa_info->fib_protocol != filter->protocol))
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,
tb->tb_id, fa->fa_type,
xkey, KEYLENGTH - fa->fa_slen,
fa->fa_tos, fa->fa_info, NLM_F_MULTI);
fa->fa_tos, fa->fa_info, flags);
if (err < 0) {
cb->args[4] = i;
return err;
}
next:
i++;
}

Expand All @@ -2044,7 +2059,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;
Expand All @@ -2057,7 +2072,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;
Expand Down

0 comments on commit 18a8021

Please sign in to comment.