On 6/18/19 7:20 AM, Stefano Brivio wrote: > diff --git a/include/net/route.h b/include/net/route.h > index 065b47754f05..f0d0086e76ce 100644 > --- a/include/net/route.h > +++ b/include/net/route.h > @@ -221,6 +221,9 @@ void ip_rt_get_source(u8 *src, struct sk_buff *skb, > struct rtable *rt); > struct rtable *rt_dst_alloc(struct net_device *dev, > unsigned int flags, u16 type, > bool nopolicy, bool noxfrm, bool will_cache); > +int rt_fill_info(struct net *net, __be32 dst, __be32 src, struct rtable *rt, > + u32 table_id, struct flowi4 *fl4, struct sk_buff *skb, > + u32 portid, u32 seq); > > struct in_ifaddr; > void fib_add_ifaddr(struct in_ifaddr *); > diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c > index 868c74771fa9..a00408827ae8 100644 > --- a/net/ipv4/fib_trie.c > +++ b/net/ipv4/fib_trie.c > @@ -2000,28 +2000,92 @@ void fib_free_table(struct fib_table *tb) > call_rcu(&tb->rcu, __trie_free_rcu); > } > > +static int fib_dump_fnhe_from_leaf(struct fib_alias *fa, struct sk_buff *skb, > + struct netlink_callback *cb, > + int *fa_index, int fa_start) > +{ > + struct net *net = sock_net(cb->skb->sk); > + struct fib_info *fi = fa->fa_info; > + struct fnhe_hash_bucket *bucket; > + struct fib_nh_common *nhc; > + int i, genid; > + > + if (!fi || fi->fib_flags & RTNH_F_DEAD) > + return 0; > + > + nhc = fib_info_nhc(fi, 0);
This should be a loop over fi->fib_nhs for net: for (i = 0; i < fi->fib_nhs; i++) { nhc = fib_info_nhc(fi, 0); ... and a loop over fib_info_num_path(fi) for net-next: for (i = 0; i < fib_info_num_path(fi); i++) { nhc = fib_info_nhc(fi, 0); ... > + if (nhc->nhc_flags & RTNH_F_DEAD) > + return 0; And then the loop over the exception bucket could be a helper in route.c in which case you don't need to export rt_fill_info and nhc_exceptions code does not spread to fib_trie.c > + > + bucket = rcu_dereference(nhc->nhc_exceptions); > + if (!bucket) > + return 0; > + > + genid = fnhe_genid(net); > + > + for (i = 0; i < FNHE_HASH_SIZE; i++) { > + struct fib_nh_exception *fnhe; > + > + for (fnhe = rcu_dereference(bucket[i].chain); fnhe; > + fnhe = rcu_dereference(fnhe->fnhe_next)) { > + struct flowi4 fl4 = {}; rather than pass an empty flow struct, update rt_fill_info to handle a NULL fl4; it's only a few checks. > + struct rtable *rt; > + int err; > + > + if (*fa_index < fa_start) > + goto next; > + > + if (fnhe->fnhe_genid != genid) > + goto next; > + > + if (fnhe->fnhe_expires && > + time_after(jiffies, fnhe->fnhe_expires)) > + goto next; > + > + rt = rcu_dereference(fnhe->fnhe_rth_input); > + if (!rt) > + rt = rcu_dereference(fnhe->fnhe_rth_output); > + if (!rt) > + goto next; > + > + err = rt_fill_info(net, fnhe->fnhe_daddr, 0, rt, > + fa->tb_id, &fl4, skb, > + NETLINK_CB(cb->skb).portid, > + cb->nlh->nlmsg_seq); > + if (err) > + return err; > +next: > + (*fa_index)++; > + } > + } > + > + return 0; > +} > +