diff options
author | Simon Horman <horms@verge.net.au> | 2010-08-22 08:37:54 -0400 |
---|---|---|
committer | Simon Horman <horms@verge.net.au> | 2010-10-04 09:45:24 -0400 |
commit | 0d1e71b04a04b6912e50926b9987c1e72facb1f3 (patch) | |
tree | 1c431b2484ab9bb2911ba8e9e281783cbd922f06 | |
parent | 8be67a6617b3403551fccb67b1c624c659419515 (diff) |
IPVS: Allow configuration of persistence engines
Allow the persistence engine of a virtual service to be set, edited
and unset.
This feature only works with the netlink user-space interface.
Signed-off-by: Simon Horman <horms@verge.net.au>
Acked-by: Julian Anastasov <ja@ssi.bg>
-rw-r--r-- | include/linux/ip_vs.h | 3 | ||||
-rw-r--r-- | include/net/ip_vs.h | 1 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_ctl.c | 57 |
3 files changed, 58 insertions, 3 deletions
diff --git a/include/linux/ip_vs.h b/include/linux/ip_vs.h index 0a9c44d6429..5f43a3b2e3a 100644 --- a/include/linux/ip_vs.h +++ b/include/linux/ip_vs.h | |||
@@ -336,6 +336,9 @@ enum { | |||
336 | IPVS_SVC_ATTR_NETMASK, /* persistent netmask */ | 336 | IPVS_SVC_ATTR_NETMASK, /* persistent netmask */ |
337 | 337 | ||
338 | IPVS_SVC_ATTR_STATS, /* nested attribute for service stats */ | 338 | IPVS_SVC_ATTR_STATS, /* nested attribute for service stats */ |
339 | |||
340 | IPVS_SVC_ATTR_PE_NAME, /* name of ct retriever */ | ||
341 | |||
339 | __IPVS_SVC_ATTR_MAX, | 342 | __IPVS_SVC_ATTR_MAX, |
340 | }; | 343 | }; |
341 | 344 | ||
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index a6b93a26d4e..52fbe2308c3 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h | |||
@@ -444,6 +444,7 @@ struct ip_vs_service_user_kern { | |||
444 | 444 | ||
445 | /* virtual service options */ | 445 | /* virtual service options */ |
446 | char *sched_name; | 446 | char *sched_name; |
447 | char *pe_name; | ||
447 | unsigned flags; /* virtual service flags */ | 448 | unsigned flags; /* virtual service flags */ |
448 | unsigned timeout; /* persistent timeout in sec */ | 449 | unsigned timeout; /* persistent timeout in sec */ |
449 | u32 netmask; /* persistent netmask */ | 450 | u32 netmask; /* persistent netmask */ |
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 5f20caf47a1..a697591d0e2 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c | |||
@@ -1134,6 +1134,7 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u, | |||
1134 | { | 1134 | { |
1135 | int ret = 0; | 1135 | int ret = 0; |
1136 | struct ip_vs_scheduler *sched = NULL; | 1136 | struct ip_vs_scheduler *sched = NULL; |
1137 | struct ip_vs_pe *pe = NULL; | ||
1137 | struct ip_vs_service *svc = NULL; | 1138 | struct ip_vs_service *svc = NULL; |
1138 | 1139 | ||
1139 | /* increase the module use count */ | 1140 | /* increase the module use count */ |
@@ -1147,6 +1148,16 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u, | |||
1147 | goto out_err; | 1148 | goto out_err; |
1148 | } | 1149 | } |
1149 | 1150 | ||
1151 | if (u->pe_name && *u->pe_name) { | ||
1152 | pe = ip_vs_pe_get(u->pe_name); | ||
1153 | if (pe == NULL) { | ||
1154 | pr_info("persistence engine module ip_vs_pe_%s " | ||
1155 | "not found\n", u->pe_name); | ||
1156 | ret = -ENOENT; | ||
1157 | goto out_err; | ||
1158 | } | ||
1159 | } | ||
1160 | |||
1150 | #ifdef CONFIG_IP_VS_IPV6 | 1161 | #ifdef CONFIG_IP_VS_IPV6 |
1151 | if (u->af == AF_INET6 && (u->netmask < 1 || u->netmask > 128)) { | 1162 | if (u->af == AF_INET6 && (u->netmask < 1 || u->netmask > 128)) { |
1152 | ret = -EINVAL; | 1163 | ret = -EINVAL; |
@@ -1184,6 +1195,10 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u, | |||
1184 | goto out_err; | 1195 | goto out_err; |
1185 | sched = NULL; | 1196 | sched = NULL; |
1186 | 1197 | ||
1198 | /* Bind the ct retriever */ | ||
1199 | ip_vs_bind_pe(svc, pe); | ||
1200 | pe = NULL; | ||
1201 | |||
1187 | /* Update the virtual service counters */ | 1202 | /* Update the virtual service counters */ |
1188 | if (svc->port == FTPPORT) | 1203 | if (svc->port == FTPPORT) |
1189 | atomic_inc(&ip_vs_ftpsvc_counter); | 1204 | atomic_inc(&ip_vs_ftpsvc_counter); |
@@ -1215,6 +1230,7 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u, | |||
1215 | kfree(svc); | 1230 | kfree(svc); |
1216 | } | 1231 | } |
1217 | ip_vs_scheduler_put(sched); | 1232 | ip_vs_scheduler_put(sched); |
1233 | ip_vs_pe_put(pe); | ||
1218 | 1234 | ||
1219 | /* decrease the module use count */ | 1235 | /* decrease the module use count */ |
1220 | ip_vs_use_count_dec(); | 1236 | ip_vs_use_count_dec(); |
@@ -1230,6 +1246,7 @@ static int | |||
1230 | ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) | 1246 | ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) |
1231 | { | 1247 | { |
1232 | struct ip_vs_scheduler *sched, *old_sched; | 1248 | struct ip_vs_scheduler *sched, *old_sched; |
1249 | struct ip_vs_pe *pe = NULL, *old_pe = NULL; | ||
1233 | int ret = 0; | 1250 | int ret = 0; |
1234 | 1251 | ||
1235 | /* | 1252 | /* |
@@ -1242,6 +1259,17 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) | |||
1242 | } | 1259 | } |
1243 | old_sched = sched; | 1260 | old_sched = sched; |
1244 | 1261 | ||
1262 | if (u->pe_name && *u->pe_name) { | ||
1263 | pe = ip_vs_pe_get(u->pe_name); | ||
1264 | if (pe == NULL) { | ||
1265 | pr_info("persistence engine module ip_vs_pe_%s " | ||
1266 | "not found\n", u->pe_name); | ||
1267 | ret = -ENOENT; | ||
1268 | goto out; | ||
1269 | } | ||
1270 | old_pe = pe; | ||
1271 | } | ||
1272 | |||
1245 | #ifdef CONFIG_IP_VS_IPV6 | 1273 | #ifdef CONFIG_IP_VS_IPV6 |
1246 | if (u->af == AF_INET6 && (u->netmask < 1 || u->netmask > 128)) { | 1274 | if (u->af == AF_INET6 && (u->netmask < 1 || u->netmask > 128)) { |
1247 | ret = -EINVAL; | 1275 | ret = -EINVAL; |
@@ -1293,12 +1321,17 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) | |||
1293 | } | 1321 | } |
1294 | } | 1322 | } |
1295 | 1323 | ||
1324 | old_pe = svc->pe; | ||
1325 | if (pe != old_pe) { | ||
1326 | ip_vs_unbind_pe(svc); | ||
1327 | ip_vs_bind_pe(svc, pe); | ||
1328 | } | ||
1329 | |||
1296 | out_unlock: | 1330 | out_unlock: |
1297 | write_unlock_bh(&__ip_vs_svc_lock); | 1331 | write_unlock_bh(&__ip_vs_svc_lock); |
1298 | #ifdef CONFIG_IP_VS_IPV6 | ||
1299 | out: | 1332 | out: |
1300 | #endif | ||
1301 | ip_vs_scheduler_put(old_sched); | 1333 | ip_vs_scheduler_put(old_sched); |
1334 | ip_vs_pe_put(old_pe); | ||
1302 | return ret; | 1335 | return ret; |
1303 | } | 1336 | } |
1304 | 1337 | ||
@@ -1312,6 +1345,9 @@ static void __ip_vs_del_service(struct ip_vs_service *svc) | |||
1312 | { | 1345 | { |
1313 | struct ip_vs_dest *dest, *nxt; | 1346 | struct ip_vs_dest *dest, *nxt; |
1314 | struct ip_vs_scheduler *old_sched; | 1347 | struct ip_vs_scheduler *old_sched; |
1348 | struct ip_vs_pe *old_pe; | ||
1349 | |||
1350 | pr_info("%s: enter\n", __func__); | ||
1315 | 1351 | ||
1316 | /* Count only IPv4 services for old get/setsockopt interface */ | 1352 | /* Count only IPv4 services for old get/setsockopt interface */ |
1317 | if (svc->af == AF_INET) | 1353 | if (svc->af == AF_INET) |
@@ -1324,6 +1360,11 @@ static void __ip_vs_del_service(struct ip_vs_service *svc) | |||
1324 | ip_vs_unbind_scheduler(svc); | 1360 | ip_vs_unbind_scheduler(svc); |
1325 | ip_vs_scheduler_put(old_sched); | 1361 | ip_vs_scheduler_put(old_sched); |
1326 | 1362 | ||
1363 | /* Unbind persistence engine */ | ||
1364 | old_pe = svc->pe; | ||
1365 | ip_vs_unbind_pe(svc); | ||
1366 | ip_vs_pe_put(old_pe); | ||
1367 | |||
1327 | /* Unbind app inc */ | 1368 | /* Unbind app inc */ |
1328 | if (svc->inc) { | 1369 | if (svc->inc) { |
1329 | ip_vs_app_inc_put(svc->inc); | 1370 | ip_vs_app_inc_put(svc->inc); |
@@ -2026,6 +2067,8 @@ static const unsigned char set_arglen[SET_CMDID(IP_VS_SO_SET_MAX)+1] = { | |||
2026 | static void ip_vs_copy_usvc_compat(struct ip_vs_service_user_kern *usvc, | 2067 | static void ip_vs_copy_usvc_compat(struct ip_vs_service_user_kern *usvc, |
2027 | struct ip_vs_service_user *usvc_compat) | 2068 | struct ip_vs_service_user *usvc_compat) |
2028 | { | 2069 | { |
2070 | memset(usvc, 0, sizeof(*usvc)); | ||
2071 | |||
2029 | usvc->af = AF_INET; | 2072 | usvc->af = AF_INET; |
2030 | usvc->protocol = usvc_compat->protocol; | 2073 | usvc->protocol = usvc_compat->protocol; |
2031 | usvc->addr.ip = usvc_compat->addr; | 2074 | usvc->addr.ip = usvc_compat->addr; |
@@ -2043,6 +2086,8 @@ static void ip_vs_copy_usvc_compat(struct ip_vs_service_user_kern *usvc, | |||
2043 | static void ip_vs_copy_udest_compat(struct ip_vs_dest_user_kern *udest, | 2086 | static void ip_vs_copy_udest_compat(struct ip_vs_dest_user_kern *udest, |
2044 | struct ip_vs_dest_user *udest_compat) | 2087 | struct ip_vs_dest_user *udest_compat) |
2045 | { | 2088 | { |
2089 | memset(udest, 0, sizeof(*udest)); | ||
2090 | |||
2046 | udest->addr.ip = udest_compat->addr; | 2091 | udest->addr.ip = udest_compat->addr; |
2047 | udest->port = udest_compat->port; | 2092 | udest->port = udest_compat->port; |
2048 | udest->conn_flags = udest_compat->conn_flags; | 2093 | udest->conn_flags = udest_compat->conn_flags; |
@@ -2539,6 +2584,8 @@ static const struct nla_policy ip_vs_svc_policy[IPVS_SVC_ATTR_MAX + 1] = { | |||
2539 | [IPVS_SVC_ATTR_FWMARK] = { .type = NLA_U32 }, | 2584 | [IPVS_SVC_ATTR_FWMARK] = { .type = NLA_U32 }, |
2540 | [IPVS_SVC_ATTR_SCHED_NAME] = { .type = NLA_NUL_STRING, | 2585 | [IPVS_SVC_ATTR_SCHED_NAME] = { .type = NLA_NUL_STRING, |
2541 | .len = IP_VS_SCHEDNAME_MAXLEN }, | 2586 | .len = IP_VS_SCHEDNAME_MAXLEN }, |
2587 | [IPVS_SVC_ATTR_PE_NAME] = { .type = NLA_NUL_STRING, | ||
2588 | .len = IP_VS_PENAME_MAXLEN }, | ||
2542 | [IPVS_SVC_ATTR_FLAGS] = { .type = NLA_BINARY, | 2589 | [IPVS_SVC_ATTR_FLAGS] = { .type = NLA_BINARY, |
2543 | .len = sizeof(struct ip_vs_flags) }, | 2590 | .len = sizeof(struct ip_vs_flags) }, |
2544 | [IPVS_SVC_ATTR_TIMEOUT] = { .type = NLA_U32 }, | 2591 | [IPVS_SVC_ATTR_TIMEOUT] = { .type = NLA_U32 }, |
@@ -2615,6 +2662,8 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb, | |||
2615 | } | 2662 | } |
2616 | 2663 | ||
2617 | NLA_PUT_STRING(skb, IPVS_SVC_ATTR_SCHED_NAME, svc->scheduler->name); | 2664 | NLA_PUT_STRING(skb, IPVS_SVC_ATTR_SCHED_NAME, svc->scheduler->name); |
2665 | if (svc->pe) | ||
2666 | NLA_PUT_STRING(skb, IPVS_SVC_ATTR_PE_NAME, svc->pe->name); | ||
2618 | NLA_PUT(skb, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags); | 2667 | NLA_PUT(skb, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags); |
2619 | NLA_PUT_U32(skb, IPVS_SVC_ATTR_TIMEOUT, svc->timeout / HZ); | 2668 | NLA_PUT_U32(skb, IPVS_SVC_ATTR_TIMEOUT, svc->timeout / HZ); |
2620 | NLA_PUT_U32(skb, IPVS_SVC_ATTR_NETMASK, svc->netmask); | 2669 | NLA_PUT_U32(skb, IPVS_SVC_ATTR_NETMASK, svc->netmask); |
@@ -2741,11 +2790,12 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc, | |||
2741 | 2790 | ||
2742 | /* If a full entry was requested, check for the additional fields */ | 2791 | /* If a full entry was requested, check for the additional fields */ |
2743 | if (full_entry) { | 2792 | if (full_entry) { |
2744 | struct nlattr *nla_sched, *nla_flags, *nla_timeout, | 2793 | struct nlattr *nla_sched, *nla_flags, *nla_pe, *nla_timeout, |
2745 | *nla_netmask; | 2794 | *nla_netmask; |
2746 | struct ip_vs_flags flags; | 2795 | struct ip_vs_flags flags; |
2747 | 2796 | ||
2748 | nla_sched = attrs[IPVS_SVC_ATTR_SCHED_NAME]; | 2797 | nla_sched = attrs[IPVS_SVC_ATTR_SCHED_NAME]; |
2798 | nla_pe = attrs[IPVS_SVC_ATTR_PE_NAME]; | ||
2749 | nla_flags = attrs[IPVS_SVC_ATTR_FLAGS]; | 2799 | nla_flags = attrs[IPVS_SVC_ATTR_FLAGS]; |
2750 | nla_timeout = attrs[IPVS_SVC_ATTR_TIMEOUT]; | 2800 | nla_timeout = attrs[IPVS_SVC_ATTR_TIMEOUT]; |
2751 | nla_netmask = attrs[IPVS_SVC_ATTR_NETMASK]; | 2801 | nla_netmask = attrs[IPVS_SVC_ATTR_NETMASK]; |
@@ -2763,6 +2813,7 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc, | |||
2763 | usvc->flags = (usvc->flags & ~flags.mask) | | 2813 | usvc->flags = (usvc->flags & ~flags.mask) | |
2764 | (flags.flags & flags.mask); | 2814 | (flags.flags & flags.mask); |
2765 | usvc->sched_name = nla_data(nla_sched); | 2815 | usvc->sched_name = nla_data(nla_sched); |
2816 | usvc->pe_name = nla_pe ? nla_data(nla_pe) : NULL; | ||
2766 | usvc->timeout = nla_get_u32(nla_timeout); | 2817 | usvc->timeout = nla_get_u32(nla_timeout); |
2767 | usvc->netmask = nla_get_u32(nla_netmask); | 2818 | usvc->netmask = nla_get_u32(nla_netmask); |
2768 | } | 2819 | } |