aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ipip.c
diff options
context:
space:
mode:
authorMichal Schmidt <mschmidt@redhat.com>2007-12-12 14:01:43 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:57:25 -0500
commit5533995b62d02dbbf930f2e59221c2d5ea05aab7 (patch)
tree3bb334652439276d5af1ea45fb4003969fb7d8c3 /net/ipv4/ipip.c
parent6a7657f56271bded0ddca1cb1e8772506a10c0a3 (diff)
[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>
Diffstat (limited to 'net/ipv4/ipip.c')
-rw-r--r--net/ipv4/ipip.c66
1 files changed, 40 insertions, 26 deletions
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 8c2b2b0741d..160535b5170 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -651,6 +651,40 @@ tx_error:
651 return 0; 651 return 0;
652} 652}
653 653
654static 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
654static int 688static int
655ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) 689ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
656{ 690{
@@ -723,6 +757,11 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
723 t->parms.iph.ttl = p.iph.ttl; 757 t->parms.iph.ttl = p.iph.ttl;
724 t->parms.iph.tos = p.iph.tos; 758 t->parms.iph.tos = p.iph.tos;
725 t->parms.iph.frag_off = p.iph.frag_off; 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 if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p))) 766 if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
728 err = -EFAULT; 767 err = -EFAULT;
@@ -791,12 +830,9 @@ static void ipip_tunnel_setup(struct net_device *dev)
791 830
792static int ipip_tunnel_init(struct net_device *dev) 831static int ipip_tunnel_init(struct net_device *dev)
793{ 832{
794 struct net_device *tdev = NULL;
795 struct ip_tunnel *tunnel; 833 struct ip_tunnel *tunnel;
796 struct iphdr *iph;
797 834
798 tunnel = netdev_priv(dev); 835 tunnel = netdev_priv(dev);
799 iph = &tunnel->parms.iph;
800 836
801 tunnel->dev = dev; 837 tunnel->dev = dev;
802 strcpy(tunnel->parms.name, dev->name); 838 strcpy(tunnel->parms.name, dev->name);
@@ -804,29 +840,7 @@ static int ipip_tunnel_init(struct net_device *dev)
804 memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); 840 memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
805 memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); 841 memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
806 842
807 if (iph->daddr) { 843 ipip_tunnel_bind_dev(dev);
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;
830 844
831 return 0; 845 return 0;
832} 846}