aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Schmidt <mschmidt@redhat.com>2007-12-13 12:46:32 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:57:56 -0500
commitee34c1eb35923cc98b1c47488a615bf51a2a2afb (patch)
tree882a6b0d4645e1d070a2474f227d5e341339ef25
parent528c4ceb427dad4a3893ba3d1913782efae0cd0e (diff)
[IP_GRE]: Rebinding of GRE tunnels to other interfaces
This is similar to the change already done for IPIP tunnels. Once created, a GRE tunnel can't be bound to another device. To reproduce: # create a tunnel: ip tunnel add tunneltest0 mode gre 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: gre/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>
-rw-r--r--net/ipv4/ip_gre.c102
1 files changed, 60 insertions, 42 deletions
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 4b93f32de10d..0832f6e028b8 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -896,6 +896,59 @@ tx_error:
896 return 0; 896 return 0;
897} 897}
898 898
899static void ipgre_tunnel_bind_dev(struct net_device *dev)
900{
901 struct net_device *tdev = NULL;
902 struct ip_tunnel *tunnel;
903 struct iphdr *iph;
904 int hlen = LL_MAX_HEADER;
905 int mtu = ETH_DATA_LEN;
906 int addend = sizeof(struct iphdr) + 4;
907
908 tunnel = netdev_priv(dev);
909 iph = &tunnel->parms.iph;
910
911 /* Guess output device to choose reasonable mtu and hard_header_len */
912
913 if (iph->daddr) {
914 struct flowi fl = { .oif = tunnel->parms.link,
915 .nl_u = { .ip4_u =
916 { .daddr = iph->daddr,
917 .saddr = iph->saddr,
918 .tos = RT_TOS(iph->tos) } },
919 .proto = IPPROTO_GRE };
920 struct rtable *rt;
921 if (!ip_route_output_key(&rt, &fl)) {
922 tdev = rt->u.dst.dev;
923 ip_rt_put(rt);
924 }
925 dev->flags |= IFF_POINTOPOINT;
926 }
927
928 if (!tdev && tunnel->parms.link)
929 tdev = __dev_get_by_index(&init_net, tunnel->parms.link);
930
931 if (tdev) {
932 hlen = tdev->hard_header_len;
933 mtu = tdev->mtu;
934 }
935 dev->iflink = tunnel->parms.link;
936
937 /* Precalculate GRE options length */
938 if (tunnel->parms.o_flags&(GRE_CSUM|GRE_KEY|GRE_SEQ)) {
939 if (tunnel->parms.o_flags&GRE_CSUM)
940 addend += 4;
941 if (tunnel->parms.o_flags&GRE_KEY)
942 addend += 4;
943 if (tunnel->parms.o_flags&GRE_SEQ)
944 addend += 4;
945 }
946 dev->hard_header_len = hlen + addend;
947 dev->mtu = mtu - addend;
948 tunnel->hlen = addend;
949
950}
951
899static int 952static int
900ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) 953ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
901{ 954{
@@ -983,6 +1036,11 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
983 t->parms.iph.ttl = p.iph.ttl; 1036 t->parms.iph.ttl = p.iph.ttl;
984 t->parms.iph.tos = p.iph.tos; 1037 t->parms.iph.tos = p.iph.tos;
985 t->parms.iph.frag_off = p.iph.frag_off; 1038 t->parms.iph.frag_off = p.iph.frag_off;
1039 if (t->parms.link != p.link) {
1040 t->parms.link = p.link;
1041 ipgre_tunnel_bind_dev(dev);
1042 netdev_state_change(dev);
1043 }
986 } 1044 }
987 if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p))) 1045 if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
988 err = -EFAULT; 1046 err = -EFAULT;
@@ -1162,12 +1220,8 @@ static void ipgre_tunnel_setup(struct net_device *dev)
1162 1220
1163static int ipgre_tunnel_init(struct net_device *dev) 1221static int ipgre_tunnel_init(struct net_device *dev)
1164{ 1222{
1165 struct net_device *tdev = NULL;
1166 struct ip_tunnel *tunnel; 1223 struct ip_tunnel *tunnel;
1167 struct iphdr *iph; 1224 struct iphdr *iph;
1168 int hlen = LL_MAX_HEADER;
1169 int mtu = ETH_DATA_LEN;
1170 int addend = sizeof(struct iphdr) + 4;
1171 1225
1172 tunnel = netdev_priv(dev); 1226 tunnel = netdev_priv(dev);
1173 iph = &tunnel->parms.iph; 1227 iph = &tunnel->parms.iph;
@@ -1178,23 +1232,9 @@ static int ipgre_tunnel_init(struct net_device *dev)
1178 memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); 1232 memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
1179 memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); 1233 memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
1180 1234
1181 /* Guess output device to choose reasonable mtu and hard_header_len */ 1235 ipgre_tunnel_bind_dev(dev);
1182 1236
1183 if (iph->daddr) { 1237 if (iph->daddr) {
1184 struct flowi fl = { .oif = tunnel->parms.link,
1185 .nl_u = { .ip4_u =
1186 { .daddr = iph->daddr,
1187 .saddr = iph->saddr,
1188 .tos = RT_TOS(iph->tos) } },
1189 .proto = IPPROTO_GRE };
1190 struct rtable *rt;
1191 if (!ip_route_output_key(&rt, &fl)) {
1192 tdev = rt->u.dst.dev;
1193 ip_rt_put(rt);
1194 }
1195
1196 dev->flags |= IFF_POINTOPOINT;
1197
1198#ifdef CONFIG_NET_IPGRE_BROADCAST 1238#ifdef CONFIG_NET_IPGRE_BROADCAST
1199 if (MULTICAST(iph->daddr)) { 1239 if (MULTICAST(iph->daddr)) {
1200 if (!iph->saddr) 1240 if (!iph->saddr)
@@ -1205,31 +1245,9 @@ static int ipgre_tunnel_init(struct net_device *dev)
1205 dev->stop = ipgre_close; 1245 dev->stop = ipgre_close;
1206 } 1246 }
1207#endif 1247#endif
1208 } else { 1248 } else
1209 dev->header_ops = &ipgre_header_ops; 1249 dev->header_ops = &ipgre_header_ops;
1210 }
1211
1212 if (!tdev && tunnel->parms.link)
1213 tdev = __dev_get_by_index(&init_net, tunnel->parms.link);
1214
1215 if (tdev) {
1216 hlen = tdev->hard_header_len;
1217 mtu = tdev->mtu;
1218 }
1219 dev->iflink = tunnel->parms.link;
1220 1250
1221 /* Precalculate GRE options length */
1222 if (tunnel->parms.o_flags&(GRE_CSUM|GRE_KEY|GRE_SEQ)) {
1223 if (tunnel->parms.o_flags&GRE_CSUM)
1224 addend += 4;
1225 if (tunnel->parms.o_flags&GRE_KEY)
1226 addend += 4;
1227 if (tunnel->parms.o_flags&GRE_SEQ)
1228 addend += 4;
1229 }
1230 dev->hard_header_len = hlen + addend;
1231 dev->mtu = mtu - addend;
1232 tunnel->hlen = addend;
1233 return 0; 1251 return 0;
1234} 1252}
1235 1253