unsigned int            prl_count;      /* # of entries in PRL */
        unsigned int            ip_tnl_net_id;
        struct gro_cells        gro_cells;
+       __u32                   fwmark;
        bool                    collect_md;
        bool                    ignore_df;
 };
                  const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst,
                  bool log_ecn_error);
 int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[],
-                        struct ip_tunnel_parm *p);
+                        struct ip_tunnel_parm *p, __u32 fwmark);
 int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
-                     struct ip_tunnel_parm *p);
+                     struct ip_tunnel_parm *p, __u32 fwmark);
 void ip_tunnel_setup(struct net_device *dev, unsigned int net_id);
 
 struct ip_tunnel_encap_ops {
 
 static int ipgre_netlink_parms(struct net_device *dev,
                                struct nlattr *data[],
                                struct nlattr *tb[],
-                               struct ip_tunnel_parm *parms)
+                               struct ip_tunnel_parm *parms,
+                               __u32 *fwmark)
 {
        struct ip_tunnel *t = netdev_priv(dev);
 
                t->ignore_df = !!nla_get_u8(data[IFLA_GRE_IGNORE_DF]);
        }
 
+       if (data[IFLA_GRE_FWMARK])
+               *fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]);
+
        return 0;
 }
 
 {
        struct ip_tunnel_parm p;
        struct ip_tunnel_encap ipencap;
+       __u32 fwmark = 0;
        int err;
 
        if (ipgre_netlink_encap_parms(data, &ipencap)) {
                        return err;
        }
 
-       err = ipgre_netlink_parms(dev, data, tb, &p);
+       err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
        if (err < 0)
                return err;
-       return ip_tunnel_newlink(dev, tb, &p);
+       return ip_tunnel_newlink(dev, tb, &p, fwmark);
 }
 
 static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
                            struct nlattr *data[])
 {
+       struct ip_tunnel *t = netdev_priv(dev);
        struct ip_tunnel_parm p;
        struct ip_tunnel_encap ipencap;
+       __u32 fwmark = t->fwmark;
        int err;
 
        if (ipgre_netlink_encap_parms(data, &ipencap)) {
-               struct ip_tunnel *t = netdev_priv(dev);
                err = ip_tunnel_encap_setup(t, &ipencap);
 
                if (err < 0)
                        return err;
        }
 
-       err = ipgre_netlink_parms(dev, data, tb, &p);
+       err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
        if (err < 0)
                return err;
-       return ip_tunnel_changelink(dev, tb, &p);
+       return ip_tunnel_changelink(dev, tb, &p, fwmark);
 }
 
 static size_t ipgre_get_size(const struct net_device *dev)
                nla_total_size(0) +
                /* IFLA_GRE_IGNORE_DF */
                nla_total_size(1) +
+               /* IFLA_GRE_FWMARK */
+               nla_total_size(4) +
                0;
 }
 
            nla_put_u8(skb, IFLA_GRE_TTL, p->iph.ttl) ||
            nla_put_u8(skb, IFLA_GRE_TOS, p->iph.tos) ||
            nla_put_u8(skb, IFLA_GRE_PMTUDISC,
-                      !!(p->iph.frag_off & htons(IP_DF))))
+                      !!(p->iph.frag_off & htons(IP_DF))) ||
+           nla_put_u32(skb, IFLA_GRE_FWMARK, t->fwmark))
                goto nla_put_failure;
 
        if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE,
        [IFLA_GRE_ENCAP_DPORT]  = { .type = NLA_U16 },
        [IFLA_GRE_COLLECT_METADATA]     = { .type = NLA_FLAG },
        [IFLA_GRE_IGNORE_DF]    = { .type = NLA_U8 },
+       [IFLA_GRE_FWMARK]       = { .type = NLA_U32 },
 };
 
 static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
 
 static inline void init_tunnel_flow(struct flowi4 *fl4,
                                    int proto,
                                    __be32 daddr, __be32 saddr,
-                                   __be32 key, __u8 tos, int oif)
+                                   __be32 key, __u8 tos, int oif,
+                                   __u32 mark)
 {
        memset(fl4, 0, sizeof(*fl4));
        fl4->flowi4_oif = oif;
        fl4->flowi4_tos = tos;
        fl4->flowi4_proto = proto;
        fl4->fl4_gre_key = key;
+       fl4->flowi4_mark = mark;
 }
 
 static int ip_tunnel_bind_dev(struct net_device *dev)
 
                init_tunnel_flow(&fl4, iph->protocol, iph->daddr,
                                 iph->saddr, tunnel->parms.o_key,
-                                RT_TOS(iph->tos), tunnel->parms.link);
+                                RT_TOS(iph->tos), tunnel->parms.link,
+                                tunnel->fwmark);
                rt = ip_route_output_key(tunnel->net, &fl4);
 
                if (!IS_ERR(rt)) {
                        tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph);
        }
        init_tunnel_flow(&fl4, proto, key->u.ipv4.dst, key->u.ipv4.src, 0,
-                        RT_TOS(tos), tunnel->parms.link);
+                        RT_TOS(tos), tunnel->parms.link, tunnel->fwmark);
        if (tunnel->encap.type != TUNNEL_ENCAP_NONE)
                goto tx_error;
        rt = ip_route_output_key(tunnel->net, &fl4);
        }
 
        init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr,
-                        tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link);
+                        tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link,
+                        tunnel->fwmark);
 
        if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0)
                goto tx_error;
                             struct ip_tunnel *t,
                             struct net_device *dev,
                             struct ip_tunnel_parm *p,
-                            bool set_mtu)
+                            bool set_mtu,
+                            __u32 fwmark)
 {
        ip_tunnel_del(itn, t);
        t->parms.iph.saddr = p->iph.saddr;
        t->parms.iph.tos = p->iph.tos;
        t->parms.iph.frag_off = p->iph.frag_off;
 
-       if (t->parms.link != p->link) {
+       if (t->parms.link != p->link || t->fwmark != fwmark) {
                int mtu;
 
                t->parms.link = p->link;
+               t->fwmark = fwmark;
                mtu = ip_tunnel_bind_dev(dev);
                if (set_mtu)
                        dev->mtu = mtu;
 
                if (t) {
                        err = 0;
-                       ip_tunnel_update(itn, t, dev, p, true);
+                       ip_tunnel_update(itn, t, dev, p, true, 0);
                } else {
                        err = -ENOENT;
                }
 EXPORT_SYMBOL_GPL(ip_tunnel_delete_net);
 
 int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
-                     struct ip_tunnel_parm *p)
+                     struct ip_tunnel_parm *p, __u32 fwmark)
 {
        struct ip_tunnel *nt;
        struct net *net = dev_net(dev);
 
        nt->net = net;
        nt->parms = *p;
+       nt->fwmark = fwmark;
        err = register_netdevice(dev);
        if (err)
                goto out;
 EXPORT_SYMBOL_GPL(ip_tunnel_newlink);
 
 int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[],
-                        struct ip_tunnel_parm *p)
+                        struct ip_tunnel_parm *p, __u32 fwmark)
 {
        struct ip_tunnel *t;
        struct ip_tunnel *tunnel = netdev_priv(dev);
                }
        }
 
-       ip_tunnel_update(itn, t, dev, p, !tb[IFLA_MTU]);
+       ip_tunnel_update(itn, t, dev, p, !tb[IFLA_MTU], fwmark);
        return 0;
 }
 EXPORT_SYMBOL_GPL(ip_tunnel_changelink);
 
 }
 
 static void vti_netlink_parms(struct nlattr *data[],
-                             struct ip_tunnel_parm *parms)
+                             struct ip_tunnel_parm *parms,
+                             __u32 *fwmark)
 {
        memset(parms, 0, sizeof(*parms));
 
        if (data[IFLA_VTI_REMOTE])
                parms->iph.daddr = nla_get_in_addr(data[IFLA_VTI_REMOTE]);
 
+       if (data[IFLA_VTI_FWMARK])
+               *fwmark = nla_get_u32(data[IFLA_VTI_FWMARK]);
 }
 
 static int vti_newlink(struct net *src_net, struct net_device *dev,
                       struct nlattr *tb[], struct nlattr *data[])
 {
        struct ip_tunnel_parm parms;
+       __u32 fwmark = 0;
 
-       vti_netlink_parms(data, &parms);
-       return ip_tunnel_newlink(dev, tb, &parms);
+       vti_netlink_parms(data, &parms, &fwmark);
+       return ip_tunnel_newlink(dev, tb, &parms, fwmark);
 }
 
 static int vti_changelink(struct net_device *dev, struct nlattr *tb[],
                          struct nlattr *data[])
 {
+       struct ip_tunnel *t = netdev_priv(dev);
+       __u32 fwmark = t->fwmark;
        struct ip_tunnel_parm p;
 
-       vti_netlink_parms(data, &p);
-       return ip_tunnel_changelink(dev, tb, &p);
+       vti_netlink_parms(data, &p, &fwmark);
+       return ip_tunnel_changelink(dev, tb, &p, fwmark);
 }
 
 static size_t vti_get_size(const struct net_device *dev)
                nla_total_size(4) +
                /* IFLA_VTI_REMOTE */
                nla_total_size(4) +
+               /* IFLA_VTI_FWMARK */
+               nla_total_size(4) +
                0;
 }
 
        nla_put_be32(skb, IFLA_VTI_OKEY, p->o_key);
        nla_put_in_addr(skb, IFLA_VTI_LOCAL, p->iph.saddr);
        nla_put_in_addr(skb, IFLA_VTI_REMOTE, p->iph.daddr);
+       nla_put_u32(skb, IFLA_VTI_FWMARK, t->fwmark);
 
        return 0;
 }
        [IFLA_VTI_OKEY]         = { .type = NLA_U32 },
        [IFLA_VTI_LOCAL]        = { .len = FIELD_SIZEOF(struct iphdr, saddr) },
        [IFLA_VTI_REMOTE]       = { .len = FIELD_SIZEOF(struct iphdr, daddr) },
+       [IFLA_VTI_FWMARK]       = { .type = NLA_U32 },
 };
 
 static struct rtnl_link_ops vti_link_ops __read_mostly = {
 
 }
 
 static void ipip_netlink_parms(struct nlattr *data[],
-                              struct ip_tunnel_parm *parms, bool *collect_md)
+                              struct ip_tunnel_parm *parms, bool *collect_md,
+                              __u32 *fwmark)
 {
        memset(parms, 0, sizeof(*parms));
 
 
        if (data[IFLA_IPTUN_COLLECT_METADATA])
                *collect_md = true;
+
+       if (data[IFLA_IPTUN_FWMARK])
+               *fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
 }
 
 /* This function returns true when ENCAP attributes are present in the nl msg */
        struct ip_tunnel *t = netdev_priv(dev);
        struct ip_tunnel_parm p;
        struct ip_tunnel_encap ipencap;
+       __u32 fwmark = 0;
 
        if (ipip_netlink_encap_parms(data, &ipencap)) {
                int err = ip_tunnel_encap_setup(t, &ipencap);
                        return err;
        }
 
-       ipip_netlink_parms(data, &p, &t->collect_md);
-       return ip_tunnel_newlink(dev, tb, &p);
+       ipip_netlink_parms(data, &p, &t->collect_md, &fwmark);
+       return ip_tunnel_newlink(dev, tb, &p, fwmark);
 }
 
 static int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
                           struct nlattr *data[])
 {
+       struct ip_tunnel *t = netdev_priv(dev);
        struct ip_tunnel_parm p;
        struct ip_tunnel_encap ipencap;
        bool collect_md;
+       __u32 fwmark = t->fwmark;
 
        if (ipip_netlink_encap_parms(data, &ipencap)) {
-               struct ip_tunnel *t = netdev_priv(dev);
                int err = ip_tunnel_encap_setup(t, &ipencap);
 
                if (err < 0)
                        return err;
        }
 
-       ipip_netlink_parms(data, &p, &collect_md);
+       ipip_netlink_parms(data, &p, &collect_md, &fwmark);
        if (collect_md)
                return -EINVAL;
 
            (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
                return -EINVAL;
 
-       return ip_tunnel_changelink(dev, tb, &p);
+       return ip_tunnel_changelink(dev, tb, &p, fwmark);
 }
 
 static size_t ipip_get_size(const struct net_device *dev)
                nla_total_size(2) +
                /* IFLA_IPTUN_COLLECT_METADATA */
                nla_total_size(0) +
+               /* IFLA_IPTUN_FWMARK */
+               nla_total_size(4) +
                0;
 }
 
            nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) ||
            nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) ||
            nla_put_u8(skb, IFLA_IPTUN_PMTUDISC,
-                      !!(parm->iph.frag_off & htons(IP_DF))))
+                      !!(parm->iph.frag_off & htons(IP_DF))) ||
+           nla_put_u32(skb, IFLA_IPTUN_FWMARK, tunnel->fwmark))
                goto nla_put_failure;
 
        if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE,
        [IFLA_IPTUN_ENCAP_SPORT]        = { .type = NLA_U16 },
        [IFLA_IPTUN_ENCAP_DPORT]        = { .type = NLA_U16 },
        [IFLA_IPTUN_COLLECT_METADATA]   = { .type = NLA_FLAG },
+       [IFLA_IPTUN_FWMARK]             = { .type = NLA_U32 },
 };
 
 static struct rtnl_link_ops ipip_link_ops __read_mostly = {
 
                        goto tx_error;
        }
 
-       rt = ip_route_output_ports(tunnel->net, &fl4, NULL,
-                                  dst, tiph->saddr,
-                                  0, 0,
-                                  IPPROTO_IPV6, RT_TOS(tos),
-                                  tunnel->parms.link);
+       flowi4_init_output(&fl4, tunnel->parms.link, tunnel->fwmark,
+                          RT_TOS(tos), RT_SCOPE_UNIVERSE, IPPROTO_IPV6,
+                          0, dst, tiph->saddr, 0, 0,
+                          sock_net_uid(tunnel->net, NULL));
+       rt = ip_route_output_flow(tunnel->net, &fl4, NULL);
+
        if (IS_ERR(rt)) {
                dev->stats.tx_carrier_errors++;
                goto tx_error_icmp;
        }
 }
 
-static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
+static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p,
+                               __u32 fwmark)
 {
        struct net *net = t->net;
        struct sit_net *sitn = net_generic(net, sit_net_id);
        ipip6_tunnel_link(sitn, t);
        t->parms.iph.ttl = p->iph.ttl;
        t->parms.iph.tos = p->iph.tos;
-       if (t->parms.link != p->link) {
+       if (t->parms.link != p->link || t->fwmark != fwmark) {
                t->parms.link = p->link;
+               t->fwmark = fwmark;
                ipip6_tunnel_bind_dev(t->dev);
        }
        dst_cache_reset(&t->dst_cache);
                                t = netdev_priv(dev);
                        }
 
-                       ipip6_tunnel_update(t, &p);
+                       ipip6_tunnel_update(t, &p, t->fwmark);
                }
 
                if (t) {
 }
 
 static void ipip6_netlink_parms(struct nlattr *data[],
-                               struct ip_tunnel_parm *parms)
+                               struct ip_tunnel_parm *parms,
+                               __u32 *fwmark)
 {
        memset(parms, 0, sizeof(*parms));
 
        if (data[IFLA_IPTUN_PROTO])
                parms->iph.protocol = nla_get_u8(data[IFLA_IPTUN_PROTO]);
 
+       if (data[IFLA_IPTUN_FWMARK])
+               *fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
 }
 
 /* This function returns true when ENCAP attributes are present in the nl msg */
                        return err;
        }
 
-       ipip6_netlink_parms(data, &nt->parms);
+       ipip6_netlink_parms(data, &nt->parms, &nt->fwmark);
 
        if (ipip6_tunnel_locate(net, &nt->parms, 0))
                return -EEXIST;
 #ifdef CONFIG_IPV6_SIT_6RD
        struct ip_tunnel_6rd ip6rd;
 #endif
+       __u32 fwmark = t->fwmark;
        int err;
 
        if (dev == sitn->fb_tunnel_dev)
                        return err;
        }
 
-       ipip6_netlink_parms(data, &p);
+       ipip6_netlink_parms(data, &p, &fwmark);
 
        if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) ||
            (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
        } else
                t = netdev_priv(dev);
 
-       ipip6_tunnel_update(t, &p);
+       ipip6_tunnel_update(t, &p, fwmark);
 
 #ifdef CONFIG_IPV6_SIT_6RD
        if (ipip6_netlink_6rd_parms(data, &ip6rd))
                nla_total_size(2) +
                /* IFLA_IPTUN_ENCAP_DPORT */
                nla_total_size(2) +
+               /* IFLA_IPTUN_FWMARK */
+               nla_total_size(4) +
                0;
 }
 
            nla_put_u8(skb, IFLA_IPTUN_PMTUDISC,
                       !!(parm->iph.frag_off & htons(IP_DF))) ||
            nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) ||
-           nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags))
+           nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags) ||
+           nla_put_u32(skb, IFLA_IPTUN_FWMARK, tunnel->fwmark))
                goto nla_put_failure;
 
 #ifdef CONFIG_IPV6_SIT_6RD
        [IFLA_IPTUN_ENCAP_FLAGS]        = { .type = NLA_U16 },
        [IFLA_IPTUN_ENCAP_SPORT]        = { .type = NLA_U16 },
        [IFLA_IPTUN_ENCAP_DPORT]        = { .type = NLA_U16 },
+       [IFLA_IPTUN_FWMARK]             = { .type = NLA_U32 },
 };
 
 static void ipip6_dellink(struct net_device *dev, struct list_head *head)