aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulius Volz <juliusv@google.com>2008-09-02 09:55:55 -0400
committerSimon Horman <horms@verge.net.au>2008-09-04 21:17:13 -0400
commitf94fd041402e4e70d2b4ed00008b9bb857e6ae87 (patch)
treeb93acee99ffb79aa0d14baa4a2083028663e7710
parent473b23d37b697c66ac0bfcfdcc9badf718e25d2a (diff)
IPVS: Allow adding IPv6 services from userspace
Allow adding IPv6 services through the genetlink interface and add checks to see if the chosen scheduler is supported with IPv6 and whether the supplied prefix length is sane. Make sure the service count exported via the sockopt interface only counts IPv4 services. Signed-off-by: Julius Volz <juliusv@google.com> Signed-off-by: Simon Horman <horms@verge.net.au>
-rw-r--r--net/ipv4/ipvs/ip_vs_ctl.c53
1 files changed, 48 insertions, 5 deletions
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 6dbc527285fa..7f89c588e588 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -1177,6 +1177,19 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u,
1177 goto out_mod_dec; 1177 goto out_mod_dec;
1178 } 1178 }
1179 1179
1180#ifdef CONFIG_IP_VS_IPV6
1181 if (u->af == AF_INET6) {
1182 if (!sched->supports_ipv6) {
1183 ret = -EAFNOSUPPORT;
1184 goto out_err;
1185 }
1186 if ((u->netmask < 1) || (u->netmask > 128)) {
1187 ret = -EINVAL;
1188 goto out_err;
1189 }
1190 }
1191#endif
1192
1180 svc = kzalloc(sizeof(struct ip_vs_service), GFP_ATOMIC); 1193 svc = kzalloc(sizeof(struct ip_vs_service), GFP_ATOMIC);
1181 if (svc == NULL) { 1194 if (svc == NULL) {
1182 IP_VS_DBG(1, "ip_vs_add_service: kmalloc failed.\n"); 1195 IP_VS_DBG(1, "ip_vs_add_service: kmalloc failed.\n");
@@ -1214,7 +1227,10 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u,
1214 atomic_inc(&ip_vs_nullsvc_counter); 1227 atomic_inc(&ip_vs_nullsvc_counter);
1215 1228
1216 ip_vs_new_estimator(&svc->stats); 1229 ip_vs_new_estimator(&svc->stats);
1217 ip_vs_num_services++; 1230
1231 /* Count only IPv4 services for old get/setsockopt interface */
1232 if (svc->af == AF_INET)
1233 ip_vs_num_services++;
1218 1234
1219 /* Hash the service into the service table */ 1235 /* Hash the service into the service table */
1220 write_lock_bh(&__ip_vs_svc_lock); 1236 write_lock_bh(&__ip_vs_svc_lock);
@@ -1265,6 +1281,19 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
1265 } 1281 }
1266 old_sched = sched; 1282 old_sched = sched;
1267 1283
1284#ifdef CONFIG_IP_VS_IPV6
1285 if (u->af == AF_INET6) {
1286 if (!sched->supports_ipv6) {
1287 ret = EAFNOSUPPORT;
1288 goto out;
1289 }
1290 if ((u->netmask < 1) || (u->netmask > 128)) {
1291 ret = EINVAL;
1292 goto out;
1293 }
1294 }
1295#endif
1296
1268 write_lock_bh(&__ip_vs_svc_lock); 1297 write_lock_bh(&__ip_vs_svc_lock);
1269 1298
1270 /* 1299 /*
@@ -1329,7 +1358,10 @@ static void __ip_vs_del_service(struct ip_vs_service *svc)
1329 struct ip_vs_dest *dest, *nxt; 1358 struct ip_vs_dest *dest, *nxt;
1330 struct ip_vs_scheduler *old_sched; 1359 struct ip_vs_scheduler *old_sched;
1331 1360
1332 ip_vs_num_services--; 1361 /* Count only IPv4 services for old get/setsockopt interface */
1362 if (svc->af == AF_INET)
1363 ip_vs_num_services--;
1364
1333 ip_vs_kill_estimator(&svc->stats); 1365 ip_vs_kill_estimator(&svc->stats);
1334 1366
1335 /* Unbind scheduler */ 1367 /* Unbind scheduler */
@@ -2212,6 +2244,10 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get,
2212 2244
2213 for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) { 2245 for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
2214 list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) { 2246 list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
2247 /* Only expose IPv4 entries to old interface */
2248 if (svc->af != AF_INET)
2249 continue;
2250
2215 if (count >= get->num_services) 2251 if (count >= get->num_services)
2216 goto out; 2252 goto out;
2217 memset(&entry, 0, sizeof(entry)); 2253 memset(&entry, 0, sizeof(entry));
@@ -2227,6 +2263,10 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get,
2227 2263
2228 for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) { 2264 for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
2229 list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) { 2265 list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
2266 /* Only expose IPv4 entries to old interface */
2267 if (svc->af != AF_INET)
2268 continue;
2269
2230 if (count >= get->num_services) 2270 if (count >= get->num_services)
2231 goto out; 2271 goto out;
2232 memset(&entry, 0, sizeof(entry)); 2272 memset(&entry, 0, sizeof(entry));
@@ -2584,7 +2624,7 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb,
2584 if (!nl_service) 2624 if (!nl_service)
2585 return -EMSGSIZE; 2625 return -EMSGSIZE;
2586 2626
2587 NLA_PUT_U16(skb, IPVS_SVC_ATTR_AF, AF_INET); 2627 NLA_PUT_U16(skb, IPVS_SVC_ATTR_AF, svc->af);
2588 2628
2589 if (svc->fwmark) { 2629 if (svc->fwmark) {
2590 NLA_PUT_U32(skb, IPVS_SVC_ATTR_FWMARK, svc->fwmark); 2630 NLA_PUT_U32(skb, IPVS_SVC_ATTR_FWMARK, svc->fwmark);
@@ -2691,8 +2731,11 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc,
2691 return -EINVAL; 2731 return -EINVAL;
2692 2732
2693 usvc->af = nla_get_u16(nla_af); 2733 usvc->af = nla_get_u16(nla_af);
2694 /* For now, only support IPv4 */ 2734#ifdef CONFIG_IP_VS_IPV6
2695 if (nla_get_u16(nla_af) != AF_INET) 2735 if (usvc->af != AF_INET && usvc->af != AF_INET6)
2736#else
2737 if (usvc->af != AF_INET)
2738#endif
2696 return -EAFNOSUPPORT; 2739 return -EAFNOSUPPORT;
2697 2740
2698 if (nla_fwmark) { 2741 if (nla_fwmark) {