Skip to content

Commit

Permalink
IPVS: Allow adding IPv6 services from userspace
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Julius Volz authored and Simon Horman committed Sep 5, 2008
1 parent 473b23d commit f94fd04
Showing 1 changed file with 48 additions and 5 deletions.
53 changes: 48 additions & 5 deletions net/ipv4/ipvs/ip_vs_ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1177,6 +1177,19 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u,
goto out_mod_dec;
}

#ifdef CONFIG_IP_VS_IPV6
if (u->af == AF_INET6) {
if (!sched->supports_ipv6) {
ret = -EAFNOSUPPORT;
goto out_err;
}
if ((u->netmask < 1) || (u->netmask > 128)) {
ret = -EINVAL;
goto out_err;
}
}
#endif

svc = kzalloc(sizeof(struct ip_vs_service), GFP_ATOMIC);
if (svc == NULL) {
IP_VS_DBG(1, "ip_vs_add_service: kmalloc failed.\n");
Expand Down Expand Up @@ -1214,7 +1227,10 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u,
atomic_inc(&ip_vs_nullsvc_counter);

ip_vs_new_estimator(&svc->stats);
ip_vs_num_services++;

/* Count only IPv4 services for old get/setsockopt interface */
if (svc->af == AF_INET)
ip_vs_num_services++;

/* Hash the service into the service table */
write_lock_bh(&__ip_vs_svc_lock);
Expand Down Expand Up @@ -1265,6 +1281,19 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
}
old_sched = sched;

#ifdef CONFIG_IP_VS_IPV6
if (u->af == AF_INET6) {
if (!sched->supports_ipv6) {
ret = EAFNOSUPPORT;
goto out;
}
if ((u->netmask < 1) || (u->netmask > 128)) {
ret = EINVAL;
goto out;
}
}
#endif

write_lock_bh(&__ip_vs_svc_lock);

/*
Expand Down Expand Up @@ -1329,7 +1358,10 @@ static void __ip_vs_del_service(struct ip_vs_service *svc)
struct ip_vs_dest *dest, *nxt;
struct ip_vs_scheduler *old_sched;

ip_vs_num_services--;
/* Count only IPv4 services for old get/setsockopt interface */
if (svc->af == AF_INET)
ip_vs_num_services--;

ip_vs_kill_estimator(&svc->stats);

/* Unbind scheduler */
Expand Down Expand Up @@ -2212,6 +2244,10 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get,

for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
/* Only expose IPv4 entries to old interface */
if (svc->af != AF_INET)
continue;

if (count >= get->num_services)
goto out;
memset(&entry, 0, sizeof(entry));
Expand All @@ -2227,6 +2263,10 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get,

for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
/* Only expose IPv4 entries to old interface */
if (svc->af != AF_INET)
continue;

if (count >= get->num_services)
goto out;
memset(&entry, 0, sizeof(entry));
Expand Down Expand Up @@ -2584,7 +2624,7 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb,
if (!nl_service)
return -EMSGSIZE;

NLA_PUT_U16(skb, IPVS_SVC_ATTR_AF, AF_INET);
NLA_PUT_U16(skb, IPVS_SVC_ATTR_AF, svc->af);

if (svc->fwmark) {
NLA_PUT_U32(skb, IPVS_SVC_ATTR_FWMARK, svc->fwmark);
Expand Down Expand Up @@ -2691,8 +2731,11 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc,
return -EINVAL;

usvc->af = nla_get_u16(nla_af);
/* For now, only support IPv4 */
if (nla_get_u16(nla_af) != AF_INET)
#ifdef CONFIG_IP_VS_IPV6
if (usvc->af != AF_INET && usvc->af != AF_INET6)
#else
if (usvc->af != AF_INET)
#endif
return -EAFNOSUPPORT;

if (nla_fwmark) {
Expand Down

0 comments on commit f94fd04

Please sign in to comment.