These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / ipv4 / ip_tunnel.c
index 626d9e5..cbb51f3 100644 (file)
@@ -230,10 +230,13 @@ skip_key_lookup:
        if (cand)
                return cand;
 
+       t = rcu_dereference(itn->collect_md_tun);
+       if (t)
+               return t;
+
        if (itn->fb_tunnel_dev && itn->fb_tunnel_dev->flags & IFF_UP)
                return netdev_priv(itn->fb_tunnel_dev);
 
-
        return NULL;
 }
 EXPORT_SYMBOL_GPL(ip_tunnel_lookup);
@@ -261,11 +264,15 @@ static void ip_tunnel_add(struct ip_tunnel_net *itn, struct ip_tunnel *t)
 {
        struct hlist_head *head = ip_bucket(itn, &t->parms);
 
+       if (t->collect_md)
+               rcu_assign_pointer(itn->collect_md_tun, t);
        hlist_add_head_rcu(&t->hash_node, head);
 }
 
-static void ip_tunnel_del(struct ip_tunnel *t)
+static void ip_tunnel_del(struct ip_tunnel_net *itn, struct ip_tunnel *t)
 {
+       if (t->collect_md)
+               rcu_assign_pointer(itn->collect_md_tun, NULL);
        hlist_del_init_rcu(&t->hash_node);
 }
 
@@ -419,7 +426,8 @@ static struct ip_tunnel *ip_tunnel_create(struct net *net,
 }
 
 int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
-                 const struct tnl_ptk_info *tpi, bool log_ecn_error)
+                 const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst,
+                 bool log_ecn_error)
 {
        struct pcpu_sw_netstats *tstats;
        const struct iphdr *iph = ip_hdr(skb);
@@ -478,6 +486,9 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
                skb->dev = tunnel->dev;
        }
 
+       if (tun_dst)
+               skb_dst_set(skb, (struct dst_entry *)tun_dst);
+
        gro_cells_receive(&tunnel->gro_cells, skb);
        return 0;
 
@@ -806,7 +817,7 @@ static void ip_tunnel_update(struct ip_tunnel_net *itn,
                             struct ip_tunnel_parm *p,
                             bool set_mtu)
 {
-       ip_tunnel_del(t);
+       ip_tunnel_del(itn, t);
        t->parms.iph.saddr = p->iph.saddr;
        t->parms.iph.daddr = p->iph.daddr;
        t->parms.i_key = p->i_key;
@@ -967,7 +978,7 @@ void ip_tunnel_dellink(struct net_device *dev, struct list_head *head)
        itn = net_generic(tunnel->net, tunnel->ip_tnl_net_id);
 
        if (itn->fb_tunnel_dev != dev) {
-               ip_tunnel_del(netdev_priv(dev));
+               ip_tunnel_del(itn, netdev_priv(dev));
                unregister_netdevice_queue(dev, head);
        }
 }
@@ -1072,8 +1083,13 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
        nt = netdev_priv(dev);
        itn = net_generic(net, nt->ip_tnl_net_id);
 
-       if (ip_tunnel_find(itn, p, dev->type))
-               return -EEXIST;
+       if (nt->collect_md) {
+               if (rtnl_dereference(itn->collect_md_tun))
+                       return -EEXIST;
+       } else {
+               if (ip_tunnel_find(itn, p, dev->type))
+                       return -EEXIST;
+       }
 
        nt->net = net;
        nt->parms = *p;
@@ -1089,7 +1105,6 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
                dev->mtu = mtu;
 
        ip_tunnel_add(itn, nt);
-
 out:
        return err;
 }
@@ -1163,6 +1178,10 @@ int ip_tunnel_init(struct net_device *dev)
        iph->version            = 4;
        iph->ihl                = 5;
 
+       if (tunnel->collect_md) {
+               dev->features |= NETIF_F_NETNS_LOCAL;
+               netif_keep_dst(dev);
+       }
        return 0;
 }
 EXPORT_SYMBOL_GPL(ip_tunnel_init);
@@ -1176,7 +1195,7 @@ void ip_tunnel_uninit(struct net_device *dev)
        itn = net_generic(net, tunnel->ip_tnl_net_id);
        /* fb_tunnel_dev will be unregisted in net-exit call. */
        if (itn->fb_tunnel_dev != dev)
-               ip_tunnel_del(netdev_priv(dev));
+               ip_tunnel_del(itn, netdev_priv(dev));
 
        ip_tunnel_dst_reset_all(tunnel);
 }