ipmr, ip6mr: Unite dumproute flows
authorYuval Mintz <yuvalm@mellanox.com>
Wed, 28 Feb 2018 21:29:39 +0000 (23:29 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 1 Mar 2018 18:13:23 +0000 (13:13 -0500)
The various MFC entries are being held in the same kind of mr_tables
for both ipmr and ip6mr, and their traversal logic is identical.
Also, with the exception of the addresses [and other small tidbits]
the major bulk of the nla setting is identical.

Unite as much of the dumping as possible between the two.
Notice this requires creating an mr_table iterator for each, as the
for-each preprocessor macro can't be used by the common logic.

Signed-off-by: Yuval Mintz <yuvalm@mellanox.com>
Acked-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/mroute_base.h
net/ipv4/ipmr.c
net/ipv4/ipmr_base.c
net/ipv6/ip6mr.c

index f40202b16dae00bf65d48d41dcdb1ebcb3405113..c2560cb50f1d56733db337be278380a3eb1348eb 100644 (file)
@@ -170,6 +170,16 @@ void *mr_mfc_find_parent(struct mr_table *mrt,
 void *mr_mfc_find_any_parent(struct mr_table *mrt, int vifi);
 void *mr_mfc_find_any(struct mr_table *mrt, int vifi, void *hasharg);
 
+int mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
+                  struct mr_mfc *c, struct rtmsg *rtm);
+int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb,
+                    struct mr_table *(*iter)(struct net *net,
+                                             struct mr_table *mrt),
+                    int (*fill)(struct mr_table *mrt,
+                                struct sk_buff *skb,
+                                u32 portid, u32 seq, struct mr_mfc *c,
+                                int cmd, int flags),
+                    spinlock_t *lock);
 #else
 static inline void vif_device_init(struct vif_device *v,
                                   struct net_device *dev,
@@ -207,6 +217,25 @@ static inline struct mr_mfc *mr_mfc_find_any(struct mr_table *mrt,
 {
        return NULL;
 }
+
+static inline int mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
+                                struct mr_mfc *c, struct rtmsg *rtm)
+{
+       return -EINVAL;
+}
+
+static inline int
+mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb,
+                struct mr_table *(*iter)(struct net *net,
+                                         struct mr_table *mrt),
+                int (*fill)(struct mr_table *mrt,
+                            struct sk_buff *skb,
+                            u32 portid, u32 seq, struct mr_mfc *c,
+                            int cmd, int flags),
+                spinlock_t *lock)
+{
+       return -EINVAL;
+}
 #endif
 
 static inline void *mr_mfc_find(struct mr_table *mrt, void *hasharg)
index f5ff54297824c4197c73de764372cc7678499392..d752a70855d8b6957d201db9772da3c4992b895b 100644 (file)
@@ -105,8 +105,6 @@ static void ip_mr_forward(struct net *net, struct mr_table *mrt,
                          struct mfc_cache *cache, int local);
 static int ipmr_cache_report(struct mr_table *mrt,
                             struct sk_buff *pkt, vifi_t vifi, int assert);
-static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
-                             struct mr_mfc *c, struct rtmsg *rtm);
 static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc,
                                 int cmd);
 static void igmpmsg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt);
@@ -117,6 +115,23 @@ static void ipmr_expire_process(struct timer_list *t);
 #define ipmr_for_each_table(mrt, net) \
        list_for_each_entry_rcu(mrt, &net->ipv4.mr_tables, list)
 
+static struct mr_table *ipmr_mr_table_iter(struct net *net,
+                                          struct mr_table *mrt)
+{
+       struct mr_table *ret;
+
+       if (!mrt)
+               ret = list_entry_rcu(net->ipv4.mr_tables.next,
+                                    struct mr_table, list);
+       else
+               ret = list_entry_rcu(mrt->list.next,
+                                    struct mr_table, list);
+
+       if (&ret->list == &net->ipv4.mr_tables)
+               return NULL;
+       return ret;
+}
+
 static struct mr_table *ipmr_get_table(struct net *net, u32 id)
 {
        struct mr_table *mrt;
@@ -284,6 +299,14 @@ EXPORT_SYMBOL(ipmr_rule_default);
 #define ipmr_for_each_table(mrt, net) \
        for (mrt = net->ipv4.mrt; mrt; mrt = NULL)
 
+static struct mr_table *ipmr_mr_table_iter(struct net *net,
+                                          struct mr_table *mrt)
+{
+       if (!mrt)
+               return net->ipv4.mrt;
+       return NULL;
+}
+
 static struct mr_table *ipmr_get_table(struct net *net, u32 id)
 {
        return net->ipv4.mrt;
@@ -1051,8 +1074,8 @@ static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt,
                        struct nlmsghdr *nlh = skb_pull(skb,
                                                        sizeof(struct iphdr));
 
-                       if (__ipmr_fill_mroute(mrt, skb, &c->_c,
-                                              nlmsg_data(nlh)) > 0) {
+                       if (mr_fill_mroute(mrt, skb, &c->_c,
+                                          nlmsg_data(nlh)) > 0) {
                                nlh->nlmsg_len = skb_tail_pointer(skb) -
                                                 (u8 *)nlh;
                        } else {
@@ -2256,66 +2279,6 @@ drop:
 }
 #endif
 
-static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
-                             struct mr_mfc *c, struct rtmsg *rtm)
-{
-       struct rta_mfc_stats mfcs;
-       struct nlattr *mp_attr;
-       struct rtnexthop *nhp;
-       unsigned long lastuse;
-       int ct;
-
-       /* If cache is unresolved, don't try to parse IIF and OIF */
-       if (c->mfc_parent >= MAXVIFS) {
-               rtm->rtm_flags |= RTNH_F_UNRESOLVED;
-               return -ENOENT;
-       }
-
-       if (VIF_EXISTS(mrt, c->mfc_parent) &&
-           nla_put_u32(skb, RTA_IIF,
-                       mrt->vif_table[c->mfc_parent].dev->ifindex) < 0)
-               return -EMSGSIZE;
-
-       if (c->mfc_flags & MFC_OFFLOAD)
-               rtm->rtm_flags |= RTNH_F_OFFLOAD;
-
-       if (!(mp_attr = nla_nest_start(skb, RTA_MULTIPATH)))
-               return -EMSGSIZE;
-
-       for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
-               if (VIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
-                       struct vif_device *vif;
-
-                       if (!(nhp = nla_reserve_nohdr(skb, sizeof(*nhp)))) {
-                               nla_nest_cancel(skb, mp_attr);
-                               return -EMSGSIZE;
-                       }
-
-                       nhp->rtnh_flags = 0;
-                       nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
-                       vif = &mrt->vif_table[ct];
-                       nhp->rtnh_ifindex = vif->dev->ifindex;
-                       nhp->rtnh_len = sizeof(*nhp);
-               }
-       }
-
-       nla_nest_end(skb, mp_attr);
-
-       lastuse = READ_ONCE(c->mfc_un.res.lastuse);
-       lastuse = time_after_eq(jiffies, lastuse) ? jiffies - lastuse : 0;
-
-       mfcs.mfcs_packets = c->mfc_un.res.pkt;
-       mfcs.mfcs_bytes = c->mfc_un.res.bytes;
-       mfcs.mfcs_wrong_if = c->mfc_un.res.wrong_if;
-       if (nla_put_64bit(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs, RTA_PAD) ||
-           nla_put_u64_64bit(skb, RTA_EXPIRES, jiffies_to_clock_t(lastuse),
-                             RTA_PAD))
-               return -EMSGSIZE;
-
-       rtm->rtm_type = RTN_MULTICAST;
-       return 1;
-}
-
 int ipmr_get_route(struct net *net, struct sk_buff *skb,
                   __be32 saddr, __be32 daddr,
                   struct rtmsg *rtm, u32 portid)
@@ -2373,7 +2336,7 @@ int ipmr_get_route(struct net *net, struct sk_buff *skb,
        }
 
        read_lock(&mrt_lock);
-       err = __ipmr_fill_mroute(mrt, skb, &cache->_c, rtm);
+       err = mr_fill_mroute(mrt, skb, &cache->_c, rtm);
        read_unlock(&mrt_lock);
        rcu_read_unlock();
        return err;
@@ -2410,7 +2373,7 @@ static int ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
        if (nla_put_in_addr(skb, RTA_SRC, c->mfc_origin) ||
            nla_put_in_addr(skb, RTA_DST, c->mfc_mcastgrp))
                goto nla_put_failure;
-       err = __ipmr_fill_mroute(mrt, skb, &c->_c, rtm);
+       err = mr_fill_mroute(mrt, skb, &c->_c, rtm);
        /* do not break the dump if cache is unresolved */
        if (err < 0 && err != -ENOENT)
                goto nla_put_failure;
@@ -2423,6 +2386,14 @@ nla_put_failure:
        return -EMSGSIZE;
 }
 
+static int _ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
+                            u32 portid, u32 seq, struct mr_mfc *c, int cmd,
+                            int flags)
+{
+       return ipmr_fill_mroute(mrt, skb, portid, seq, (struct mfc_cache *)c,
+                               cmd, flags);
+}
+
 static size_t mroute_msgsize(bool unresolved, int maxvif)
 {
        size_t len =
@@ -2596,62 +2567,8 @@ errout_free:
 
 static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       struct net *net = sock_net(skb->sk);
-       unsigned int t = 0, s_t;
-       unsigned int e = 0, s_e;
-       struct mr_table *mrt;
-       struct mr_mfc *mfc;
-
-       s_t = cb->args[0];
-       s_e = cb->args[1];
-
-       rcu_read_lock();
-       ipmr_for_each_table(mrt, net) {
-               if (t < s_t)
-                       goto next_table;
-               list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
-                       if (e < s_e)
-                               goto next_entry;
-                       if (ipmr_fill_mroute(mrt, skb,
-                                            NETLINK_CB(cb->skb).portid,
-                                            cb->nlh->nlmsg_seq,
-                                            (struct mfc_cache *)mfc,
-                                            RTM_NEWROUTE, NLM_F_MULTI) < 0)
-                               goto done;
-next_entry:
-                       e++;
-               }
-               e = 0;
-               s_e = 0;
-
-               spin_lock_bh(&mfc_unres_lock);
-               list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) {
-                       if (e < s_e)
-                               goto next_entry2;
-                       if (ipmr_fill_mroute(mrt, skb,
-                                            NETLINK_CB(cb->skb).portid,
-                                            cb->nlh->nlmsg_seq,
-                                            (struct mfc_cache *)mfc,
-                                            RTM_NEWROUTE, NLM_F_MULTI) < 0) {
-                               spin_unlock_bh(&mfc_unres_lock);
-                               goto done;
-                       }
-next_entry2:
-                       e++;
-               }
-               spin_unlock_bh(&mfc_unres_lock);
-               e = 0;
-               s_e = 0;
-next_table:
-               t++;
-       }
-done:
-       rcu_read_unlock();
-
-       cb->args[1] = e;
-       cb->args[0] = t;
-
-       return skb->len;
+       return mr_rtm_dumproute(skb, cb, ipmr_mr_table_iter,
+                               _ipmr_fill_mroute, &mfc_unres_lock);
 }
 
 static const struct nla_policy rtm_ipmr_policy[RTA_MAX + 1] = {
index e1b7b639e9b1fbbfc241668613ca7c8eb218b7be..8ba55bfda81733cec4301e0cd40c0969a19f50c5 100644 (file)
@@ -198,3 +198,126 @@ end_of_list:
 }
 EXPORT_SYMBOL(mr_mfc_seq_next);
 #endif
+
+int mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
+                  struct mr_mfc *c, struct rtmsg *rtm)
+{
+       struct rta_mfc_stats mfcs;
+       struct nlattr *mp_attr;
+       struct rtnexthop *nhp;
+       unsigned long lastuse;
+       int ct;
+
+       /* If cache is unresolved, don't try to parse IIF and OIF */
+       if (c->mfc_parent >= MAXVIFS) {
+               rtm->rtm_flags |= RTNH_F_UNRESOLVED;
+               return -ENOENT;
+       }
+
+       if (VIF_EXISTS(mrt, c->mfc_parent) &&
+           nla_put_u32(skb, RTA_IIF,
+                       mrt->vif_table[c->mfc_parent].dev->ifindex) < 0)
+               return -EMSGSIZE;
+
+       if (c->mfc_flags & MFC_OFFLOAD)
+               rtm->rtm_flags |= RTNH_F_OFFLOAD;
+
+       mp_attr = nla_nest_start(skb, RTA_MULTIPATH);
+       if (!mp_attr)
+               return -EMSGSIZE;
+
+       for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
+               if (VIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
+                       struct vif_device *vif;
+
+                       nhp = nla_reserve_nohdr(skb, sizeof(*nhp));
+                       if (!nhp) {
+                               nla_nest_cancel(skb, mp_attr);
+                               return -EMSGSIZE;
+                       }
+
+                       nhp->rtnh_flags = 0;
+                       nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
+                       vif = &mrt->vif_table[ct];
+                       nhp->rtnh_ifindex = vif->dev->ifindex;
+                       nhp->rtnh_len = sizeof(*nhp);
+               }
+       }
+
+       nla_nest_end(skb, mp_attr);
+
+       lastuse = READ_ONCE(c->mfc_un.res.lastuse);
+       lastuse = time_after_eq(jiffies, lastuse) ? jiffies - lastuse : 0;
+
+       mfcs.mfcs_packets = c->mfc_un.res.pkt;
+       mfcs.mfcs_bytes = c->mfc_un.res.bytes;
+       mfcs.mfcs_wrong_if = c->mfc_un.res.wrong_if;
+       if (nla_put_64bit(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs, RTA_PAD) ||
+           nla_put_u64_64bit(skb, RTA_EXPIRES, jiffies_to_clock_t(lastuse),
+                             RTA_PAD))
+               return -EMSGSIZE;
+
+       rtm->rtm_type = RTN_MULTICAST;
+       return 1;
+}
+EXPORT_SYMBOL(mr_fill_mroute);
+
+int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb,
+                    struct mr_table *(*iter)(struct net *net,
+                                             struct mr_table *mrt),
+                    int (*fill)(struct mr_table *mrt,
+                                struct sk_buff *skb,
+                                u32 portid, u32 seq, struct mr_mfc *c,
+                                int cmd, int flags),
+                    spinlock_t *lock)
+{
+       unsigned int t = 0, e = 0, s_t = cb->args[0], s_e = cb->args[1];
+       struct net *net = sock_net(skb->sk);
+       struct mr_table *mrt;
+       struct mr_mfc *mfc;
+
+       rcu_read_lock();
+       for (mrt = iter(net, NULL); mrt; mrt = iter(net, mrt)) {
+               if (t < s_t)
+                       goto next_table;
+               list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
+                       if (e < s_e)
+                               goto next_entry;
+                       if (fill(mrt, skb, NETLINK_CB(cb->skb).portid,
+                                cb->nlh->nlmsg_seq, mfc,
+                                RTM_NEWROUTE, NLM_F_MULTI) < 0)
+                               goto done;
+next_entry:
+                       e++;
+               }
+               e = 0;
+               s_e = 0;
+
+               spin_lock_bh(lock);
+               list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) {
+                       if (e < s_e)
+                               goto next_entry2;
+                       if (fill(mrt, skb, NETLINK_CB(cb->skb).portid,
+                                cb->nlh->nlmsg_seq, mfc,
+                                RTM_NEWROUTE, NLM_F_MULTI) < 0) {
+                               spin_unlock_bh(lock);
+                               goto done;
+                       }
+next_entry2:
+                       e++;
+               }
+               spin_unlock_bh(lock);
+               e = 0;
+               s_e = 0;
+next_table:
+               t++;
+       }
+done:
+       rcu_read_unlock();
+
+       cb->args[1] = e;
+       cb->args[0] = t;
+
+       return skb->len;
+}
+EXPORT_SYMBOL(mr_rtm_dumproute);
index c3b3f1c381e1564312e27710656236ed383a071b..2a38f9de45d399fafc9f4bcc662b44be17279e51 100644 (file)
@@ -87,8 +87,6 @@ static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
                           struct sk_buff *skb, struct mfc6_cache *cache);
 static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
                              mifi_t mifi, int assert);
-static int __ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
-                              struct mfc6_cache *c, struct rtmsg *rtm);
 static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,
                              int cmd);
 static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt);
@@ -101,6 +99,23 @@ static void ipmr_expire_process(struct timer_list *t);
 #define ip6mr_for_each_table(mrt, net) \
        list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list)
 
+static struct mr_table *ip6mr_mr_table_iter(struct net *net,
+                                           struct mr_table *mrt)
+{
+       struct mr_table *ret;
+
+       if (!mrt)
+               ret = list_entry_rcu(net->ipv6.mr6_tables.next,
+                                    struct mr_table, list);
+       else
+               ret = list_entry_rcu(mrt->list.next,
+                                    struct mr_table, list);
+
+       if (&ret->list == &net->ipv6.mr6_tables)
+               return NULL;
+       return ret;
+}
+
 static struct mr_table *ip6mr_get_table(struct net *net, u32 id)
 {
        struct mr_table *mrt;
@@ -247,6 +262,14 @@ static void __net_exit ip6mr_rules_exit(struct net *net)
 #define ip6mr_for_each_table(mrt, net) \
        for (mrt = net->ipv6.mrt6; mrt; mrt = NULL)
 
+static struct mr_table *ip6mr_mr_table_iter(struct net *net,
+                                           struct mr_table *mrt)
+{
+       if (!mrt)
+               return net->ipv6.mrt6;
+       return NULL;
+}
+
 static struct mr_table *ip6mr_get_table(struct net *net, u32 id)
 {
        return net->ipv6.mrt6;
@@ -948,7 +971,8 @@ static void ip6mr_cache_resolve(struct net *net, struct mr_table *mrt,
                        struct nlmsghdr *nlh = skb_pull(skb,
                                                        sizeof(struct ipv6hdr));
 
-                       if (__ip6mr_fill_mroute(mrt, skb, c, nlmsg_data(nlh)) > 0) {
+                       if (mr_fill_mroute(mrt, skb, &c->_c,
+                                          nlmsg_data(nlh)) > 0) {
                                nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh;
                        } else {
                                nlh->nlmsg_type = NLMSG_ERROR;
@@ -2081,63 +2105,6 @@ int ip6_mr_input(struct sk_buff *skb)
        return 0;
 }
 
-
-static int __ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
-                              struct mfc6_cache *c, struct rtmsg *rtm)
-{
-       struct rta_mfc_stats mfcs;
-       struct nlattr *mp_attr;
-       struct rtnexthop *nhp;
-       unsigned long lastuse;
-       int ct;
-
-       /* If cache is unresolved, don't try to parse IIF and OIF */
-       if (c->_c.mfc_parent >= MAXMIFS) {
-               rtm->rtm_flags |= RTNH_F_UNRESOLVED;
-               return -ENOENT;
-       }
-
-       if (VIF_EXISTS(mrt, c->_c.mfc_parent) &&
-           nla_put_u32(skb, RTA_IIF,
-                       mrt->vif_table[c->_c.mfc_parent].dev->ifindex) < 0)
-               return -EMSGSIZE;
-       mp_attr = nla_nest_start(skb, RTA_MULTIPATH);
-       if (!mp_attr)
-               return -EMSGSIZE;
-
-       for (ct = c->_c.mfc_un.res.minvif;
-            ct < c->_c.mfc_un.res.maxvif; ct++) {
-               if (VIF_EXISTS(mrt, ct) && c->_c.mfc_un.res.ttls[ct] < 255) {
-                       nhp = nla_reserve_nohdr(skb, sizeof(*nhp));
-                       if (!nhp) {
-                               nla_nest_cancel(skb, mp_attr);
-                               return -EMSGSIZE;
-                       }
-
-                       nhp->rtnh_flags = 0;
-                       nhp->rtnh_hops = c->_c.mfc_un.res.ttls[ct];
-                       nhp->rtnh_ifindex = mrt->vif_table[ct].dev->ifindex;
-                       nhp->rtnh_len = sizeof(*nhp);
-               }
-       }
-
-       nla_nest_end(skb, mp_attr);
-
-       lastuse = READ_ONCE(c->_c.mfc_un.res.lastuse);
-       lastuse = time_after_eq(jiffies, lastuse) ? jiffies - lastuse : 0;
-
-       mfcs.mfcs_packets = c->_c.mfc_un.res.pkt;
-       mfcs.mfcs_bytes = c->_c.mfc_un.res.bytes;
-       mfcs.mfcs_wrong_if = c->_c.mfc_un.res.wrong_if;
-       if (nla_put_64bit(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs, RTA_PAD) ||
-           nla_put_u64_64bit(skb, RTA_EXPIRES, jiffies_to_clock_t(lastuse),
-                             RTA_PAD))
-               return -EMSGSIZE;
-
-       rtm->rtm_type = RTN_MULTICAST;
-       return 1;
-}
-
 int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm,
                    u32 portid)
 {
@@ -2203,7 +2170,7 @@ int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm,
                return err;
        }
 
-       err = __ip6mr_fill_mroute(mrt, skb, cache, rtm);
+       err = mr_fill_mroute(mrt, skb, &cache->_c, rtm);
        read_unlock(&mrt_lock);
        return err;
 }
@@ -2239,7 +2206,7 @@ static int ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
        if (nla_put_in6_addr(skb, RTA_SRC, &c->mf6c_origin) ||
            nla_put_in6_addr(skb, RTA_DST, &c->mf6c_mcastgrp))
                goto nla_put_failure;
-       err = __ip6mr_fill_mroute(mrt, skb, c, rtm);
+       err = mr_fill_mroute(mrt, skb, &c->_c, rtm);
        /* do not break the dump if cache is unresolved */
        if (err < 0 && err != -ENOENT)
                goto nla_put_failure;
@@ -2252,6 +2219,14 @@ nla_put_failure:
        return -EMSGSIZE;
 }
 
+static int _ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
+                             u32 portid, u32 seq, struct mr_mfc *c,
+                             int cmd, int flags)
+{
+       return ip6mr_fill_mroute(mrt, skb, portid, seq, (struct mfc6_cache *)c,
+                                cmd, flags);
+}
+
 static int mr6_msgsize(bool unresolved, int maxvif)
 {
        size_t len =
@@ -2365,59 +2340,6 @@ errout:
 
 static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       struct net *net = sock_net(skb->sk);
-       unsigned int t = 0, s_t;
-       unsigned int e = 0, s_e;
-       struct mr_table *mrt;
-       struct mr_mfc *mfc;
-
-       s_t = cb->args[0];
-       s_e = cb->args[1];
-
-       rcu_read_lock();
-       ip6mr_for_each_table(mrt, net) {
-               if (t < s_t)
-                       goto next_table;
-               list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
-                       if (e < s_e)
-                               goto next_entry;
-                       if (ip6mr_fill_mroute(mrt, skb,
-                                             NETLINK_CB(cb->skb).portid,
-                                             cb->nlh->nlmsg_seq,
-                                             (struct mfc6_cache *)mfc,
-                                             RTM_NEWROUTE, NLM_F_MULTI) < 0)
-                               goto done;
-next_entry:
-                       e++;
-               }
-               e = 0;
-               s_e = 0;
-
-               spin_lock_bh(&mfc_unres_lock);
-               list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) {
-                       if (e < s_e)
-                               goto next_entry2;
-                       if (ip6mr_fill_mroute(mrt, skb,
-                                             NETLINK_CB(cb->skb).portid,
-                                             cb->nlh->nlmsg_seq,
-                                            (struct mfc6_cache *)mfc,
-                                             RTM_NEWROUTE, NLM_F_MULTI) < 0) {
-                               spin_unlock_bh(&mfc_unres_lock);
-                               goto done;
-                       }
-next_entry2:
-                       e++;
-               }
-               spin_unlock_bh(&mfc_unres_lock);
-               e = s_e = 0;
-next_table:
-               t++;
-       }
-done:
-       rcu_read_unlock();
-
-       cb->args[1] = e;
-       cb->args[0] = t;
-
-       return skb->len;
+       return mr_rtm_dumproute(skb, cb, ip6mr_mr_table_iter,
+                               _ip6mr_fill_mroute, &mfc_unres_lock);
 }