diff options
Diffstat (limited to 'net/ipv4/ip_gre.c')
-rw-r--r-- | net/ipv4/ip_gre.c | 65 |
1 files changed, 31 insertions, 34 deletions
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index a8ec0904e5a6..74d4c515772e 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -124,8 +124,12 @@ static void ipgre_tunnel_setup(struct net_device *dev); | |||
124 | 124 | ||
125 | static int ipgre_fb_tunnel_init(struct net_device *dev); | 125 | static int ipgre_fb_tunnel_init(struct net_device *dev); |
126 | 126 | ||
127 | #define HASH_SIZE 16 | ||
128 | |||
127 | static int ipgre_net_id; | 129 | static int ipgre_net_id; |
128 | struct ipgre_net { | 130 | struct ipgre_net { |
131 | struct ip_tunnel *tunnels[4][HASH_SIZE]; | ||
132 | |||
129 | struct net_device *fb_tunnel_dev; | 133 | struct net_device *fb_tunnel_dev; |
130 | }; | 134 | }; |
131 | 135 | ||
@@ -147,15 +151,12 @@ struct ipgre_net { | |||
147 | will match fallback tunnel. | 151 | will match fallback tunnel. |
148 | */ | 152 | */ |
149 | 153 | ||
150 | #define HASH_SIZE 16 | ||
151 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) | 154 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) |
152 | 155 | ||
153 | static struct ip_tunnel *tunnels[4][HASH_SIZE]; | 156 | #define tunnels_r_l tunnels[3] |
154 | 157 | #define tunnels_r tunnels[2] | |
155 | #define tunnels_r_l (tunnels[3]) | 158 | #define tunnels_l tunnels[1] |
156 | #define tunnels_r (tunnels[2]) | 159 | #define tunnels_wc tunnels[0] |
157 | #define tunnels_l (tunnels[1]) | ||
158 | #define tunnels_wc (tunnels[0]) | ||
159 | 160 | ||
160 | static DEFINE_RWLOCK(ipgre_lock); | 161 | static DEFINE_RWLOCK(ipgre_lock); |
161 | 162 | ||
@@ -169,19 +170,19 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net *net, | |||
169 | struct ip_tunnel *t; | 170 | struct ip_tunnel *t; |
170 | struct ipgre_net *ign = net_generic(net, ipgre_net_id); | 171 | struct ipgre_net *ign = net_generic(net, ipgre_net_id); |
171 | 172 | ||
172 | for (t = tunnels_r_l[h0^h1]; t; t = t->next) { | 173 | for (t = ign->tunnels_r_l[h0^h1]; t; t = t->next) { |
173 | if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) { | 174 | if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) { |
174 | if (t->parms.i_key == key && (t->dev->flags&IFF_UP)) | 175 | if (t->parms.i_key == key && (t->dev->flags&IFF_UP)) |
175 | return t; | 176 | return t; |
176 | } | 177 | } |
177 | } | 178 | } |
178 | for (t = tunnels_r[h0^h1]; t; t = t->next) { | 179 | for (t = ign->tunnels_r[h0^h1]; t; t = t->next) { |
179 | if (remote == t->parms.iph.daddr) { | 180 | if (remote == t->parms.iph.daddr) { |
180 | if (t->parms.i_key == key && (t->dev->flags&IFF_UP)) | 181 | if (t->parms.i_key == key && (t->dev->flags&IFF_UP)) |
181 | return t; | 182 | return t; |
182 | } | 183 | } |
183 | } | 184 | } |
184 | for (t = tunnels_l[h1]; t; t = t->next) { | 185 | for (t = ign->tunnels_l[h1]; t; t = t->next) { |
185 | if (local == t->parms.iph.saddr || | 186 | if (local == t->parms.iph.saddr || |
186 | (local == t->parms.iph.daddr && | 187 | (local == t->parms.iph.daddr && |
187 | ipv4_is_multicast(local))) { | 188 | ipv4_is_multicast(local))) { |
@@ -189,7 +190,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net *net, | |||
189 | return t; | 190 | return t; |
190 | } | 191 | } |
191 | } | 192 | } |
192 | for (t = tunnels_wc[h1]; t; t = t->next) { | 193 | for (t = ign->tunnels_wc[h1]; t; t = t->next) { |
193 | if (t->parms.i_key == key && (t->dev->flags&IFF_UP)) | 194 | if (t->parms.i_key == key && (t->dev->flags&IFF_UP)) |
194 | return t; | 195 | return t; |
195 | } | 196 | } |
@@ -215,7 +216,7 @@ static struct ip_tunnel **__ipgre_bucket(struct ipgre_net *ign, | |||
215 | h ^= HASH(remote); | 216 | h ^= HASH(remote); |
216 | } | 217 | } |
217 | 218 | ||
218 | return &tunnels[prio][h]; | 219 | return &ign->tunnels[prio][h]; |
219 | } | 220 | } |
220 | 221 | ||
221 | static inline struct ip_tunnel **ipgre_bucket(struct ipgre_net *ign, | 222 | static inline struct ip_tunnel **ipgre_bucket(struct ipgre_net *ign, |
@@ -1274,6 +1275,7 @@ static int ipgre_fb_tunnel_init(struct net_device *dev) | |||
1274 | { | 1275 | { |
1275 | struct ip_tunnel *tunnel = netdev_priv(dev); | 1276 | struct ip_tunnel *tunnel = netdev_priv(dev); |
1276 | struct iphdr *iph = &tunnel->parms.iph; | 1277 | struct iphdr *iph = &tunnel->parms.iph; |
1278 | struct ipgre_net *ign = net_generic(dev_net(dev), ipgre_net_id); | ||
1277 | 1279 | ||
1278 | tunnel->dev = dev; | 1280 | tunnel->dev = dev; |
1279 | strcpy(tunnel->parms.name, dev->name); | 1281 | strcpy(tunnel->parms.name, dev->name); |
@@ -1284,7 +1286,7 @@ static int ipgre_fb_tunnel_init(struct net_device *dev) | |||
1284 | tunnel->hlen = sizeof(struct iphdr) + 4; | 1286 | tunnel->hlen = sizeof(struct iphdr) + 4; |
1285 | 1287 | ||
1286 | dev_hold(dev); | 1288 | dev_hold(dev); |
1287 | tunnels_wc[0] = tunnel; | 1289 | ign->tunnels_wc[0] = tunnel; |
1288 | return 0; | 1290 | return 0; |
1289 | } | 1291 | } |
1290 | 1292 | ||
@@ -1294,13 +1296,27 @@ static struct net_protocol ipgre_protocol = { | |||
1294 | .err_handler = ipgre_err, | 1296 | .err_handler = ipgre_err, |
1295 | }; | 1297 | }; |
1296 | 1298 | ||
1299 | static void ipgre_destroy_tunnels(struct ipgre_net *ign) | ||
1300 | { | ||
1301 | int prio; | ||
1302 | |||
1303 | for (prio = 0; prio < 4; prio++) { | ||
1304 | int h; | ||
1305 | for (h = 0; h < HASH_SIZE; h++) { | ||
1306 | struct ip_tunnel *t; | ||
1307 | while ((t = ign->tunnels[prio][h]) != NULL) | ||
1308 | unregister_netdevice(t->dev); | ||
1309 | } | ||
1310 | } | ||
1311 | } | ||
1312 | |||
1297 | static int ipgre_init_net(struct net *net) | 1313 | static int ipgre_init_net(struct net *net) |
1298 | { | 1314 | { |
1299 | int err; | 1315 | int err; |
1300 | struct ipgre_net *ign; | 1316 | struct ipgre_net *ign; |
1301 | 1317 | ||
1302 | err = -ENOMEM; | 1318 | err = -ENOMEM; |
1303 | ign = kmalloc(sizeof(struct ipgre_net), GFP_KERNEL); | 1319 | ign = kzalloc(sizeof(struct ipgre_net), GFP_KERNEL); |
1304 | if (ign == NULL) | 1320 | if (ign == NULL) |
1305 | goto err_alloc; | 1321 | goto err_alloc; |
1306 | 1322 | ||
@@ -1339,8 +1355,7 @@ static void ipgre_exit_net(struct net *net) | |||
1339 | 1355 | ||
1340 | ign = net_generic(net, ipgre_net_id); | 1356 | ign = net_generic(net, ipgre_net_id); |
1341 | rtnl_lock(); | 1357 | rtnl_lock(); |
1342 | if (net != &init_net) | 1358 | ipgre_destroy_tunnels(ign); |
1343 | unregister_netdevice(ign->fb_tunnel_dev); | ||
1344 | rtnl_unlock(); | 1359 | rtnl_unlock(); |
1345 | kfree(ign); | 1360 | kfree(ign); |
1346 | } | 1361 | } |
@@ -1372,29 +1387,11 @@ static int __init ipgre_init(void) | |||
1372 | return err; | 1387 | return err; |
1373 | } | 1388 | } |
1374 | 1389 | ||
1375 | static void __exit ipgre_destroy_tunnels(void) | ||
1376 | { | ||
1377 | int prio; | ||
1378 | |||
1379 | for (prio = 0; prio < 4; prio++) { | ||
1380 | int h; | ||
1381 | for (h = 0; h < HASH_SIZE; h++) { | ||
1382 | struct ip_tunnel *t; | ||
1383 | while ((t = tunnels[prio][h]) != NULL) | ||
1384 | unregister_netdevice(t->dev); | ||
1385 | } | ||
1386 | } | ||
1387 | } | ||
1388 | |||
1389 | static void __exit ipgre_fini(void) | 1390 | static void __exit ipgre_fini(void) |
1390 | { | 1391 | { |
1391 | if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) | 1392 | if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) |
1392 | printk(KERN_INFO "ipgre close: can't remove protocol\n"); | 1393 | printk(KERN_INFO "ipgre close: can't remove protocol\n"); |
1393 | 1394 | ||
1394 | rtnl_lock(); | ||
1395 | ipgre_destroy_tunnels(); | ||
1396 | rtnl_unlock(); | ||
1397 | |||
1398 | unregister_pernet_gen_device(ipgre_net_id, &ipgre_net_ops); | 1395 | unregister_pernet_gen_device(ipgre_net_id, &ipgre_net_ops); |
1399 | } | 1396 | } |
1400 | 1397 | ||