Commit 8a4a50f98bc13670bee94c40b94bc169e1263cd9

Authored by Michal Schmidt
Committed by David S. Miller
1 parent ee34c1eb35

[IPV6] sit: Rebinding of SIT tunnels to other interfaces

This is similar to the change already done for IPIP tunnels.

Once created, a SIT tunnel can't be bound to another device.
To reproduce:

# create a tunnel:
ip tunnel add tunneltest0 mode sit 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: ipv6/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.

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

Showing 1 changed file with 42 additions and 28 deletions Side-by-side Diff

... ... @@ -669,6 +669,42 @@
669 669 return 0;
670 670 }
671 671  
  672 +static void ipip6_tunnel_bind_dev(struct net_device *dev)
  673 +{
  674 + struct net_device *tdev = NULL;
  675 + struct ip_tunnel *tunnel;
  676 + struct iphdr *iph;
  677 +
  678 + tunnel = netdev_priv(dev);
  679 + iph = &tunnel->parms.iph;
  680 +
  681 + if (iph->daddr) {
  682 + struct flowi fl = { .nl_u = { .ip4_u =
  683 + { .daddr = iph->daddr,
  684 + .saddr = iph->saddr,
  685 + .tos = RT_TOS(iph->tos) } },
  686 + .oif = tunnel->parms.link,
  687 + .proto = IPPROTO_IPV6 };
  688 + struct rtable *rt;
  689 + if (!ip_route_output_key(&rt, &fl)) {
  690 + tdev = rt->u.dst.dev;
  691 + ip_rt_put(rt);
  692 + }
  693 + dev->flags |= IFF_POINTOPOINT;
  694 + }
  695 +
  696 + if (!tdev && tunnel->parms.link)
  697 + tdev = __dev_get_by_index(&init_net, tunnel->parms.link);
  698 +
  699 + if (tdev) {
  700 + dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr);
  701 + dev->mtu = tdev->mtu - sizeof(struct iphdr);
  702 + if (dev->mtu < IPV6_MIN_MTU)
  703 + dev->mtu = IPV6_MIN_MTU;
  704 + }
  705 + dev->iflink = tunnel->parms.link;
  706 +}
  707 +
672 708 static int
673 709 ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
674 710 {
... ... @@ -740,6 +776,11 @@
740 776 if (cmd == SIOCCHGTUNNEL) {
741 777 t->parms.iph.ttl = p.iph.ttl;
742 778 t->parms.iph.tos = p.iph.tos;
  779 + if (t->parms.link != p.link) {
  780 + t->parms.link = p.link;
  781 + ipip6_tunnel_bind_dev(dev);
  782 + netdev_state_change(dev);
  783 + }
743 784 }
744 785 if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
745 786 err = -EFAULT;
746 787  
747 788  
... ... @@ -808,12 +849,9 @@
808 849  
809 850 static int ipip6_tunnel_init(struct net_device *dev)
810 851 {
811   - struct net_device *tdev = NULL;
812 852 struct ip_tunnel *tunnel;
813   - struct iphdr *iph;
814 853  
815 854 tunnel = netdev_priv(dev);
816   - iph = &tunnel->parms.iph;
817 855  
818 856 tunnel->dev = dev;
819 857 strcpy(tunnel->parms.name, dev->name);
... ... @@ -821,31 +859,7 @@
821 859 memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
822 860 memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
823 861  
824   - if (iph->daddr) {
825   - struct flowi fl = { .nl_u = { .ip4_u =
826   - { .daddr = iph->daddr,
827   - .saddr = iph->saddr,
828   - .tos = RT_TOS(iph->tos) } },
829   - .oif = tunnel->parms.link,
830   - .proto = IPPROTO_IPV6 };
831   - struct rtable *rt;
832   - if (!ip_route_output_key(&rt, &fl)) {
833   - tdev = rt->u.dst.dev;
834   - ip_rt_put(rt);
835   - }
836   - dev->flags |= IFF_POINTOPOINT;
837   - }
838   -
839   - if (!tdev && tunnel->parms.link)
840   - tdev = __dev_get_by_index(&init_net, tunnel->parms.link);
841   -
842   - if (tdev) {
843   - dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr);
844   - dev->mtu = tdev->mtu - sizeof(struct iphdr);
845   - if (dev->mtu < IPV6_MIN_MTU)
846   - dev->mtu = IPV6_MIN_MTU;
847   - }
848   - dev->iflink = tunnel->parms.link;
  862 + ipip6_tunnel_bind_dev(dev);
849 863  
850 864 return 0;
851 865 }