Upgrade to 4.4.50-rt62
[kvmfornfv.git] / kernel / net / ipv4 / ip_tunnel.c
index 626d9e5..3310ac7 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;
 
@@ -652,6 +663,8 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
        inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
        connected = (tunnel->parms.iph.daddr != 0);
 
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
        dst = tnl_params->daddr;
        if (dst == 0) {
                /* NBMA tunnel */
@@ -749,7 +762,6 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
                                tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
                        tunnel->err_count--;
 
-                       memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
                        dst_link_failure(skb);
                } else
                        tunnel->err_count = 0;
@@ -806,7 +818,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;
@@ -936,17 +948,31 @@ done:
 }
 EXPORT_SYMBOL_GPL(ip_tunnel_ioctl);
 
-int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu)
+int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
        int t_hlen = tunnel->hlen + sizeof(struct iphdr);
+       int max_mtu = 0xFFF8 - dev->hard_header_len - t_hlen;
 
-       if (new_mtu < 68 ||
-           new_mtu > 0xFFF8 - dev->hard_header_len - t_hlen)
+       if (new_mtu < 68)
                return -EINVAL;
+
+       if (new_mtu > max_mtu) {
+               if (strict)
+                       return -EINVAL;
+
+               new_mtu = max_mtu;
+       }
+
        dev->mtu = new_mtu;
        return 0;
 }
+EXPORT_SYMBOL_GPL(__ip_tunnel_change_mtu);
+
+int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu)
+{
+       return __ip_tunnel_change_mtu(dev, new_mtu, true);
+}
 EXPORT_SYMBOL_GPL(ip_tunnel_change_mtu);
 
 static void ip_tunnel_dev_free(struct net_device *dev)
@@ -967,7 +993,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 +1098,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 +1120,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 +1193,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 +1210,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);
 }