diff options
-rw-r--r-- | net/ipv4/ipvs/ip_vs_ctl.c | 53 |
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) { |