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 0a9c44d64292..5f43a3b2e3ad 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 a6b93a26d4e2..52fbe2308c38 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 5f20caf47a1d..a697591d0e23 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; | ||
