diff options
Diffstat (limited to 'net/ipv4/ip_tunnel.c')
-rw-r--r-- | net/ipv4/ip_tunnel.c | 31 |
1 files changed, 26 insertions, 5 deletions
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 5fcb17cb426b..de6d94482fe7 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -346,12 +346,17 @@ static struct ip_tunnel *ip_tunnel_create(struct net *net, struct ip_tunnel *nt; struct net_device *dev; int t_hlen; + int mtu; + int err; dev = __ip_tunnel_create(net, itn->rtnl_link_ops, parms); if (IS_ERR(dev)) return ERR_CAST(dev); - dev->mtu = ip_tunnel_bind_dev(dev); + mtu = ip_tunnel_bind_dev(dev); + err = dev_set_mtu(dev, mtu); + if (err) + goto err_dev_set_mtu; nt = netdev_priv(dev); t_hlen = nt->hlen + sizeof(struct iphdr); @@ -359,6 +364,10 @@ static struct ip_tunnel *ip_tunnel_create(struct net *net, dev->max_mtu = 0xFFF8 - dev->hard_header_len - t_hlen; ip_tunnel_add(itn, nt); return nt; + +err_dev_set_mtu: + unregister_netdevice(dev); + return ERR_PTR(err); } int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb, @@ -1090,17 +1099,29 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], nt->fwmark = fwmark; err = register_netdevice(dev); if (err) - goto out; + goto err_register_netdevice; if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS]) eth_hw_addr_random(dev); mtu = ip_tunnel_bind_dev(dev); - if (!tb[IFLA_MTU]) - dev->mtu = mtu; + if (tb[IFLA_MTU]) { + unsigned int max = 0xfff8 - dev->hard_header_len - nt->hlen; + + mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU, + (unsigned int)(max - sizeof(struct iphdr))); + } + + err = dev_set_mtu(dev, mtu); + if (err) + goto err_dev_set_mtu; ip_tunnel_add(itn, nt); -out: + return 0; + +err_dev_set_mtu: + unregister_netdevice(dev); +err_register_netdevice: return err; } EXPORT_SYMBOL_GPL(ip_tunnel_newlink); |