Commit 5533995b62d02dbbf930f2e59221c2d5ea05aab7

Authored by Michal Schmidt
Committed by David S. Miller
1 parent 6a7657f562

[IPIP]: Allow rebinding the tunnel to another interface

Once created, an IP tunnel can't be bound to another device.
(reported as https://bugzilla.redhat.com/show_bug.cgi?id=419671)

To reproduce:

# create a tunnel:
ip tunnel add tunneltest0 mode ipip remote 10.0.0.1 dev eth0
# try to change the bounding device from eth0 to eth1:
ip tunnel change tunneltest0 dev eth1
# show the result:
ip tunnel show tunneltest0

tunneltest0: ip/ip  remote 10.0.0.1  local any  dev eth0  ttl inherit

Notice the bound device has not changed from eth0 to eth1.

This patch fixes it. When changing the binding, it also recalculates the
MTU according to the new bound device's MTU.

If the change is acceptable, I'll do the same for GRE and SIT tunnels.

Signed-off-by: Michal Schmidt <mschmidt@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 1 changed file with 40 additions and 26 deletions Side-by-side Diff

... ... @@ -651,6 +651,40 @@
651 651 return 0;
652 652 }
653 653  
  654 +static void ipip_tunnel_bind_dev(struct net_device *dev)
  655 +{
  656 + struct net_device *tdev = NULL;
  657 + struct ip_tunnel *tunnel;
  658 + struct iphdr *iph;
  659 +
  660 + tunnel = netdev_priv(dev);
  661 + iph = &tunnel->parms.iph;
  662 +
  663 + if (iph->daddr) {
  664 + struct flowi fl = { .oif = tunnel->parms.link,
  665 + .nl_u = { .ip4_u =
  666 + { .daddr = iph->daddr,
  667 + .saddr = iph->saddr,
  668 + .tos = RT_TOS(iph->tos) } },
  669 + .proto = IPPROTO_IPIP };
  670 + struct rtable *rt;
  671 + if (!ip_route_output_key(&rt, &fl)) {
  672 + tdev = rt->u.dst.dev;
  673 + ip_rt_put(rt);
  674 + }
  675 + dev->flags |= IFF_POINTOPOINT;
  676 + }
  677 +
  678 + if (!tdev && tunnel->parms.link)
  679 + tdev = __dev_get_by_index(&init_net, tunnel->parms.link);
  680 +
  681 + if (tdev) {
  682 + dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr);
  683 + dev->mtu = tdev->mtu - sizeof(struct iphdr);
  684 + }
  685 + dev->iflink = tunnel->parms.link;
  686 +}
  687 +
654 688 static int
655 689 ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
656 690 {
... ... @@ -723,6 +757,11 @@
723 757 t->parms.iph.ttl = p.iph.ttl;
724 758 t->parms.iph.tos = p.iph.tos;
725 759 t->parms.iph.frag_off = p.iph.frag_off;
  760 + if (t->parms.link != p.link) {
  761 + t->parms.link = p.link;
  762 + ipip_tunnel_bind_dev(dev);
  763 + netdev_state_change(dev);
  764 + }
726 765 }
727 766 if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
728 767 err = -EFAULT;
729 768  
730 769  
... ... @@ -791,12 +830,9 @@
791 830  
792 831 static int ipip_tunnel_init(struct net_device *dev)
793 832 {
794   - struct net_device *tdev = NULL;
795 833 struct ip_tunnel *tunnel;
796   - struct iphdr *iph;
797 834  
798 835 tunnel = netdev_priv(dev);
799   - iph = &tunnel->parms.iph;
800 836  
801 837 tunnel->dev = dev;
802 838 strcpy(tunnel->parms.name, dev->name);
... ... @@ -804,29 +840,7 @@
804 840 memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
805 841 memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
806 842  
807   - if (iph->daddr) {
808   - struct flowi fl = { .oif = tunnel->parms.link,
809   - .nl_u = { .ip4_u =
810   - { .daddr = iph->daddr,
811   - .saddr = iph->saddr,
812   - .tos = RT_TOS(iph->tos) } },
813   - .proto = IPPROTO_IPIP };
814   - struct rtable *rt;
815   - if (!ip_route_output_key(&rt, &fl)) {
816   - tdev = rt->u.dst.dev;
817   - ip_rt_put(rt);
818   - }
819   - dev->flags |= IFF_POINTOPOINT;
820   - }
821   -
822   - if (!tdev && tunnel->parms.link)
823   - tdev = __dev_get_by_index(&init_net, tunnel->parms.link);
824   -
825   - if (tdev) {
826   - dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr);
827   - dev->mtu = tdev->mtu - sizeof(struct iphdr);
828   - }
829   - dev->iflink = tunnel->parms.link;
  843 + ipip_tunnel_bind_dev(dev);
830 844  
831 845 return 0;
832 846 }