diff options
-rw-r--r-- | net/ipv6/sit.c | 45 |
1 files changed, 25 insertions, 20 deletions
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index d0c1f2db7f21..f82494bc4c58 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -70,15 +70,15 @@ static void ipip6_tunnel_setup(struct net_device *dev); | |||
70 | 70 | ||
71 | static int sit_net_id; | 71 | static int sit_net_id; |
72 | struct sit_net { | 72 | struct sit_net { |
73 | struct ip_tunnel *tunnels_r_l[HASH_SIZE]; | ||
74 | struct ip_tunnel *tunnels_r[HASH_SIZE]; | ||
75 | struct ip_tunnel *tunnels_l[HASH_SIZE]; | ||
76 | struct ip_tunnel *tunnels_wc[1]; | ||
77 | struct ip_tunnel **tunnels[4]; | ||
78 | |||
73 | struct net_device *fb_tunnel_dev; | 79 | struct net_device *fb_tunnel_dev; |
74 | }; | 80 | }; |
75 | 81 | ||
76 | static struct ip_tunnel *tunnels_r_l[HASH_SIZE]; | ||
77 | static struct ip_tunnel *tunnels_r[HASH_SIZE]; | ||
78 | static struct ip_tunnel *tunnels_l[HASH_SIZE]; | ||
79 | static struct ip_tunnel *tunnels_wc[1]; | ||
80 | static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunnels_r_l }; | ||
81 | |||
82 | static DEFINE_RWLOCK(ipip6_lock); | 82 | static DEFINE_RWLOCK(ipip6_lock); |
83 | 83 | ||
84 | static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, | 84 | static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, |
@@ -87,21 +87,22 @@ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, | |||
87 | unsigned h0 = HASH(remote); | 87 | unsigned h0 = HASH(remote); |
88 | unsigned h1 = HASH(local); | 88 | unsigned h1 = HASH(local); |
89 | struct ip_tunnel *t; | 89 | struct ip_tunnel *t; |
90 | struct sit_net *sitn = net_generic(net, sit_net_id); | ||
90 | 91 | ||
91 | for (t = tunnels_r_l[h0^h1]; t; t = t->next) { | 92 | for (t = sitn->tunnels_r_l[h0^h1]; t; t = t->next) { |
92 | if (local == t->parms.iph.saddr && | 93 | if (local == t->parms.iph.saddr && |
93 | remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) | 94 | remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) |
94 | return t; | 95 | return t; |
95 | } | 96 | } |
96 | for (t = tunnels_r[h0]; t; t = t->next) { | 97 | for (t = sitn->tunnels_r[h0]; t; t = t->next) { |
97 | if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) | 98 | if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) |
98 | return t; | 99 | return t; |
99 | } | 100 | } |
100 | for (t = tunnels_l[h1]; t; t = t->next) { | 101 | for (t = sitn->tunnels_l[h1]; t; t = t->next) { |
101 | if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP)) | 102 | if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP)) |
102 | return t; | 103 | return t; |
103 | } | 104 | } |
104 | if ((t = tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP)) | 105 | if ((t = sitn->tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP)) |
105 | return t; | 106 | return t; |
106 | return NULL; | 107 | return NULL; |
107 | } | 108 | } |
@@ -122,7 +123,7 @@ static struct ip_tunnel **__ipip6_bucket(struct sit_net *sitn, | |||
122 | prio |= 1; | 123 | prio |= 1; |
123 | h ^= HASH(local); | 124 | h ^= HASH(local); |
124 | } | 125 | } |
125 | return &tunnels[prio][h]; | 126 | return &sitn->tunnels[prio][h]; |
126 | } | 127 | } |
127 | 128 | ||
128 | static inline struct ip_tunnel **ipip6_bucket(struct sit_net *sitn, | 129 | static inline struct ip_tunnel **ipip6_bucket(struct sit_net *sitn, |
@@ -387,7 +388,7 @@ static void ipip6_tunnel_uninit(struct net_device *dev) | |||
387 | 388 | ||
388 | if (dev == sitn->fb_tunnel_dev) { | 389 | if (dev == sitn->fb_tunnel_dev) { |
389 | write_lock_bh(&ipip6_lock); | 390 | write_lock_bh(&ipip6_lock); |
390 | tunnels_wc[0] = NULL; | 391 | sitn->tunnels_wc[0] = NULL; |
391 | write_unlock_bh(&ipip6_lock); | 392 | write_unlock_bh(&ipip6_lock); |
392 | dev_put(dev); | 393 | dev_put(dev); |
393 | } else { | 394 | } else { |
@@ -1050,6 +1051,8 @@ static int ipip6_fb_tunnel_init(struct net_device *dev) | |||
1050 | { | 1051 | { |
1051 | struct ip_tunnel *tunnel = netdev_priv(dev); | 1052 | struct ip_tunnel *tunnel = netdev_priv(dev); |
1052 | struct iphdr *iph = &tunnel->parms.iph; | 1053 | struct iphdr *iph = &tunnel->parms.iph; |
1054 | struct net *net = dev_net(dev); | ||
1055 | struct sit_net *sitn = net_generic(net, sit_net_id); | ||
1053 | 1056 | ||
1054 | tunnel->dev = dev; | 1057 | tunnel->dev = dev; |
1055 | strcpy(tunnel->parms.name, dev->name); | 1058 | strcpy(tunnel->parms.name, dev->name); |
@@ -1060,7 +1063,7 @@ static int ipip6_fb_tunnel_init(struct net_device *dev) | |||
1060 | iph->ttl = 64; | 1063 | iph->ttl = 64; |
1061 | 1064 | ||
1062 | dev_hold(dev); | 1065 | dev_hold(dev); |
1063 | tunnels_wc[0] = tunnel; | 1066 | sitn->tunnels_wc[0] = tunnel; |
1064 | return 0; | 1067 | return 0; |
1065 | } | 1068 | } |
1066 | 1069 | ||
@@ -1070,7 +1073,7 @@ static struct xfrm_tunnel sit_handler = { | |||
1070 | .priority = 1, | 1073 | .priority = 1, |
1071 | }; | 1074 | }; |
1072 | 1075 | ||
1073 | static void __exit sit_destroy_tunnels(void) | 1076 | static void sit_destroy_tunnels(struct sit_net *sitn) |
1074 | { | 1077 | { |
1075 | int prio; | 1078 | int prio; |
1076 | 1079 | ||
@@ -1078,7 +1081,7 @@ static void __exit sit_destroy_tunnels(void) | |||
1078 | int h; | 1081 | int h; |
1079 | for (h = 0; h < HASH_SIZE; h++) { | 1082 | for (h = 0; h < HASH_SIZE; h++) { |
1080 | struct ip_tunnel *t; | 1083 | struct ip_tunnel *t; |
1081 | while ((t = tunnels[prio][h]) != NULL) | 1084 | while ((t = sitn->tunnels[prio][h]) != NULL) |
1082 | unregister_netdevice(t->dev); | 1085 | unregister_netdevice(t->dev); |
1083 | } | 1086 | } |
1084 | } | 1087 | } |
@@ -1090,7 +1093,7 @@ static int sit_init_net(struct net *net) | |||
1090 | struct sit_net *sitn; | 1093 | struct sit_net *sitn; |
1091 | 1094 | ||
1092 | err = -ENOMEM; | 1095 | err = -ENOMEM; |
1093 | sitn = kmalloc(sizeof(struct sit_net), GFP_KERNEL); | 1096 | sitn = kzalloc(sizeof(struct sit_net), GFP_KERNEL); |
1094 | if (sitn == NULL) | 1097 | if (sitn == NULL) |
1095 | goto err_alloc; | 1098 | goto err_alloc; |
1096 | 1099 | ||
@@ -1098,6 +1101,11 @@ static int sit_init_net(struct net *net) | |||
1098 | if (err < 0) | 1101 | if (err < 0) |
1099 | goto err_assign; | 1102 | goto err_assign; |
1100 | 1103 | ||
1104 | sitn->tunnels[0] = sitn->tunnels_wc; | ||
1105 | sitn->tunnels[1] = sitn->tunnels_l; | ||
1106 | sitn->tunnels[2] = sitn->tunnels_r; | ||
1107 | sitn->tunnels[3] = sitn->tunnels_r_l; | ||
1108 | |||
1101 | sitn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "sit0", | 1109 | sitn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "sit0", |
1102 | ipip6_tunnel_setup); | 1110 | ipip6_tunnel_setup); |
1103 | if (!sitn->fb_tunnel_dev) { | 1111 | if (!sitn->fb_tunnel_dev) { |
@@ -1129,6 +1137,7 @@ static void sit_exit_net(struct net *net) | |||
1129 | 1137 | ||
1130 | sitn = net_generic(net, sit_net_id); | 1138 | sitn = net_generic(net, sit_net_id); |
1131 | rtnl_lock(); | 1139 | rtnl_lock(); |
1140 | sit_destroy_tunnels(sitn); | ||
1132 | unregister_netdevice(sitn->fb_tunnel_dev); | 1141 | unregister_netdevice(sitn->fb_tunnel_dev); |
1133 | rtnl_unlock(); | 1142 | rtnl_unlock(); |
1134 | kfree(sitn); | 1143 | kfree(sitn); |
@@ -1143,10 +1152,6 @@ static void __exit sit_cleanup(void) | |||
1143 | { | 1152 | { |
1144 | xfrm4_tunnel_deregister(&sit_handler, AF_INET6); | 1153 | xfrm4_tunnel_deregister(&sit_handler, AF_INET6); |
1145 | 1154 | ||
1146 | rtnl_lock(); | ||
1147 | sit_destroy_tunnels(); | ||
1148 | rtnl_unlock(); | ||
1149 | |||
1150 | unregister_pernet_gen_device(sit_net_id, &sit_net_ops); | 1155 | unregister_pernet_gen_device(sit_net_id, &sit_net_ops); |
1151 | } | 1156 | } |
1152 | 1157 | ||