#include <net/fib_rules.h>
 #include <net/fib_notifier.h>
 #include <uapi/linux/mroute.h>
+#include <linux/mroute_base.h>
 
 #ifdef CONFIG_IP_MROUTE
 static inline int ip_mroute_opt(int opt)
 }
 #endif
 
-struct vif_device {
-       struct net_device       *dev;                   /* Device we are using */
-       struct netdev_phys_item_id dev_parent_id;       /* Device parent ID    */
-       unsigned long   bytes_in,bytes_out;
-       unsigned long   pkt_in,pkt_out;         /* Statistics                   */
-       unsigned long   rate_limit;             /* Traffic shaping (NI)         */
-       unsigned char   threshold;              /* TTL threshold                */
-       unsigned short  flags;                  /* Control flags                */
-       __be32          local,remote;           /* Addresses(remote for tunnels)*/
-       int             link;                   /* Physical interface index     */
-};
-
 struct vif_entry_notifier_info {
        struct fib_notifier_info info;
        struct net_device *dev;
 
 #include <linux/skbuff.h>      /* for struct sk_buff_head */
 #include <net/net_namespace.h>
 #include <uapi/linux/mroute6.h>
+#include <linux/mroute_base.h>
 
 #ifdef CONFIG_IPV6_MROUTE
 static inline int ip6_mroute_opt(int opt)
 }
 #endif
 
-struct mif_device {
-       struct net_device       *dev;                   /* Device we are using */
-       unsigned long   bytes_in,bytes_out;
-       unsigned long   pkt_in,pkt_out;         /* Statistics                   */
-       unsigned long   rate_limit;             /* Traffic shaping (NI)         */
-       unsigned char   threshold;              /* TTL threshold                */
-       unsigned short  flags;                  /* Control flags                */
-       int             link;                   /* Physical interface index     */
-};
-
 #define VIFF_STATIC 0x8000
 
 struct mfc6_cache {
 
--- /dev/null
+#ifndef __LINUX_MROUTE_BASE_H
+#define __LINUX_MROUTE_BASE_H
+
+#include <linux/netdevice.h>
+
+/**
+ * struct vif_device - interface representor for multicast routing
+ * @dev: network device being used
+ * @bytes_in: statistic; bytes ingressing
+ * @bytes_out: statistic; bytes egresing
+ * @pkt_in: statistic; packets ingressing
+ * @pkt_out: statistic; packets egressing
+ * @rate_limit: Traffic shaping (NI)
+ * @threshold: TTL threshold
+ * @flags: Control flags
+ * @link: Physical interface index
+ * @dev_parent_id: device parent id
+ * @local: Local address
+ * @remote: Remote address for tunnels
+ */
+struct vif_device {
+       struct net_device *dev;
+       unsigned long bytes_in, bytes_out;
+       unsigned long pkt_in, pkt_out;
+       unsigned long rate_limit;
+       unsigned char threshold;
+       unsigned short flags;
+       int link;
+
+       /* Currently only used by ipmr */
+       struct netdev_phys_item_id dev_parent_id;
+       __be32 local, remote;
+};
+
+#ifdef CONFIG_IP_MROUTE_COMMON
+void vif_device_init(struct vif_device *v,
+                    struct net_device *dev,
+                    unsigned long rate_limit,
+                    unsigned char threshold,
+                    unsigned short flags,
+                    unsigned short get_iflink_mask);
+#else
+static inline void vif_device_init(struct vif_device *v,
+                                  struct net_device *dev,
+                                  unsigned long rate_limit,
+                                  unsigned char threshold,
+                                  unsigned short flags,
+                                  unsigned short get_iflink_mask)
+{
+}
+#endif
+#endif
 
          Network), but can be distributed all over the Internet. If you want
          to do that, say Y here and to "IP multicast routing" below.
 
+config IP_MROUTE_COMMON
+       bool
+       depends on IP_MROUTE || IPV6_MROUTE
+
 config IP_MROUTE
        bool "IP: multicast routing"
        depends on IP_MULTICAST
+       select IP_MROUTE_COMMON
        help
          This is used if you want your machine to act as a router for IP
          packets that have several destination addresses. It is needed on the
 
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
 obj-$(CONFIG_IP_MROUTE) += ipmr.o
+obj-$(CONFIG_IP_MROUTE_COMMON) += ipmr_base.o
 obj-$(CONFIG_NET_IPIP) += ipip.o
 gre-y := gre_demux.o
 obj-$(CONFIG_NET_FOU) += fou.o
 
        ip_rt_multicast_event(in_dev);
 
        /* Fill in the VIF structures */
+       vif_device_init(v, dev, vifc->vifc_rate_limit,
+                       vifc->vifc_threshold,
+                       vifc->vifc_flags | (!mrtsock ? VIFF_STATIC : 0),
+                       (VIFF_TUNNEL | VIFF_REGISTER));
 
        attr.orig_dev = dev;
        if (!switchdev_port_attr_get(dev, &attr)) {
        } else {
                v->dev_parent_id.id_len = 0;
        }
-       v->rate_limit = vifc->vifc_rate_limit;
+
        v->local = vifc->vifc_lcl_addr.s_addr;
        v->remote = vifc->vifc_rmt_addr.s_addr;
-       v->flags = vifc->vifc_flags;
-       if (!mrtsock)
-               v->flags |= VIFF_STATIC;
-       v->threshold = vifc->vifc_threshold;
-       v->bytes_in = 0;
-       v->bytes_out = 0;
-       v->pkt_in = 0;
-       v->pkt_out = 0;
-       v->link = dev->ifindex;
-       if (v->flags & (VIFF_TUNNEL | VIFF_REGISTER))
-               v->link = dev_get_iflink(dev);
 
        /* And finish update writing critical data */
        write_lock_bh(&mrt_lock);
        }
 
        if (VIF_EXISTS(mrt, c->mfc_parent) &&
-           nla_put_u32(skb, RTA_IIF, mrt->vif_table[c->mfc_parent].dev->ifindex) < 0)
+           nla_put_u32(skb, RTA_IIF,
+                       mrt->vif_table[c->mfc_parent].dev->ifindex) < 0)
                return -EMSGSIZE;
 
        if (c->mfc_flags & MFC_OFFLOAD)
 
        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];
-                       nhp->rtnh_ifindex = mrt->vif_table[ct].dev->ifindex;
+                       vif = &mrt->vif_table[ct];
+                       nhp->rtnh_ifindex = vif->dev->ifindex;
                        nhp->rtnh_len = sizeof(*nhp);
                }
        }
 };
 
 static struct vif_device *ipmr_vif_seq_idx(struct net *net,
-                                          struct ipmr_vif_iter *iter,
-                                          loff_t pos)
+                                           struct ipmr_vif_iter *iter,
+                                           loff_t pos)
 {
        struct mr_table *mrt = iter->mrt;
 
                         "Interface      BytesIn  PktsIn  BytesOut PktsOut Flags Local    Remote\n");
        } else {
                const struct vif_device *vif = v;
-               const char *name =  vif->dev ? vif->dev->name : "none";
+               const char *name =  vif->dev ?
+                                   vif->dev->name : "none";
 
                seq_printf(seq,
                           "%2td %-10s %8ld %7ld  %8ld %7ld %05X %08X %08X\n",
 
--- /dev/null
+/* Linux multicast routing support
+ * Common logic shared by IPv4 [ipmr] and IPv6 [ip6mr] implementation
+ */
+
+#include <linux/mroute_base.h>
+
+/* Sets everything common except 'dev', since that is done under locking */
+void vif_device_init(struct vif_device *v,
+                    struct net_device *dev,
+                    unsigned long rate_limit,
+                    unsigned char threshold,
+                    unsigned short flags,
+                    unsigned short get_iflink_mask)
+{
+       v->dev = NULL;
+       v->bytes_in = 0;
+       v->bytes_out = 0;
+       v->pkt_in = 0;
+       v->pkt_out = 0;
+       v->rate_limit = rate_limit;
+       v->flags = flags;
+       v->threshold = threshold;
+       if (v->flags & get_iflink_mask)
+               v->link = dev_get_iflink(dev);
+       else
+               v->link = dev->ifindex;
+}
+EXPORT_SYMBOL(vif_device_init);
 
 config IPV6_MROUTE
        bool "IPv6: multicast routing"
        depends on IPV6
+       select IP_MROUTE_COMMON
        ---help---
          Experimental support for IPv6 multicast forwarding.
          If unsure, say N.
 
        struct timer_list       ipmr_expire_timer;
        struct list_head        mfc6_unres_queue;
        struct list_head        mfc6_cache_array[MFC6_LINES];
-       struct mif_device       vif6_table[MAXMIFS];
+       struct vif_device       vif6_table[MAXMIFS];
        int                     maxvif;
        atomic_t                cache_resolve_queue_len;
        bool                    mroute_do_assert;
        int ct;
 };
 
-static struct mif_device *ip6mr_vif_seq_idx(struct net *net,
+static struct vif_device *ip6mr_vif_seq_idx(struct net *net,
                                            struct ipmr_vif_iter *iter,
                                            loff_t pos)
 {
                seq_puts(seq,
                         "Interface      BytesIn  PktsIn  BytesOut PktsOut Flags\n");
        } else {
-               const struct mif_device *vif = v;
+               const struct vif_device *vif = v;
                const char *name = vif->dev ? vif->dev->name : "none";
 
                seq_printf(seq,
 static int mif6_delete(struct mr6_table *mrt, int vifi, int notify,
                       struct list_head *head)
 {
-       struct mif_device *v;
+       struct vif_device *v;
        struct net_device *dev;
        struct inet6_dev *in6_dev;
 
                    struct mif6ctl *vifc, int mrtsock)
 {
        int vifi = vifc->mif6c_mifi;
-       struct mif_device *v = &mrt->vif6_table[vifi];
+       struct vif_device *v = &mrt->vif6_table[vifi];
        struct net_device *dev;
        struct inet6_dev *in6_dev;
        int err;
                                             dev->ifindex, &in6_dev->cnf);
        }
 
-       /*
-        *      Fill in the VIF structures
-        */
-       v->rate_limit = vifc->vifc_rate_limit;
-       v->flags = vifc->mif6c_flags;
-       if (!mrtsock)
-               v->flags |= VIFF_STATIC;
-       v->threshold = vifc->vifc_threshold;
-       v->bytes_in = 0;
-       v->bytes_out = 0;
-       v->pkt_in = 0;
-       v->pkt_out = 0;
-       v->link = dev->ifindex;
-       if (v->flags & MIFF_REGISTER)
-               v->link = dev_get_iflink(dev);
+       /* Fill in the VIF structures */
+       vif_device_init(v, dev, vifc->vifc_rate_limit, vifc->vifc_threshold,
+                       vifc->mif6c_flags | (!mrtsock ? VIFF_STATIC : 0),
+                       MIFF_REGISTER);
 
        /* And finish update writing critical data */
        write_lock_bh(&mrt_lock);
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
        struct net *net = dev_net(dev);
        struct mr6_table *mrt;
-       struct mif_device *v;
+       struct vif_device *v;
        int ct;
 
        if (event != NETDEV_UNREGISTER)
 {
        struct sioc_sg_req6 sr;
        struct sioc_mif_req6 vr;
-       struct mif_device *vif;
+       struct vif_device *vif;
        struct mfc6_cache *c;
        struct net *net = sock_net(sk);
        struct mr6_table *mrt;
 {
        struct compat_sioc_sg_req6 sr;
        struct compat_sioc_mif_req6 vr;
-       struct mif_device *vif;
+       struct vif_device *vif;
        struct mfc6_cache *c;
        struct net *net = sock_net(sk);
        struct mr6_table *mrt;
                          struct sk_buff *skb, struct mfc6_cache *c, int vifi)
 {
        struct ipv6hdr *ipv6h;
-       struct mif_device *vif = &mrt->vif6_table[vifi];
+       struct vif_device *vif = &mrt->vif6_table[vifi];
        struct net_device *dev;
        struct dst_entry *dst;
        struct flowi6 fl6;