net/ipv4: Plumb support for filtering route dumps
authorDavid Ahern <dsahern@gmail.com>
Tue, 16 Oct 2018 01:56:43 +0000 (18:56 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 16 Oct 2018 07:13:12 +0000 (00:13 -0700)
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>
include/net/ip_fib.h
net/ipv4/fib_frontend.c
net/ipv4/fib_trie.c

index 667013bf42665e49e6333249fbc7618a31f2ebd6..1eabc9edd2b9c2e146b2458b46b03010fc98befa 100644 (file)
@@ -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);
index 850850dd80e1d0f21175bba98accba8edbcc5fd8..37dc8ac366fd038eb22474ec227232148fa05e7a 100644 (file)
@@ -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];
 
@@ -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;
index 5bc0c89e81e4c3ffb8352d18d6851b343b1c79ce..237c9f72b2658ce6c622af1bbdbb4792da12ade1 100644 (file)
@@ -2003,12 +2003,17 @@ 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;
 
@@ -2016,25 +2021,35 @@ 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->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++;
        }
 
@@ -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;
@@ -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;