aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Horman <horms@verge.net.au>2010-08-22 08:37:54 -0400
committerSimon Horman <horms@verge.net.au>2010-10-04 09:45:24 -0400
commit0d1e71b04a04b6912e50926b9987c1e72facb1f3 (patch)
tree1c431b2484ab9bb2911ba8e9e281783cbd922f06
parent8be67a6617b3403551fccb67b1c624c659419515 (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.h3
-rw-r--r--include/net/ip_vs.h1
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c57
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
1230ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) 1246ip_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] = {
2026static void ip_vs_copy_usvc_compat(struct ip_vs_service_user_kern *usvc, 2067static 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,
2043static void ip_vs_copy_udest_compat(struct ip_vs_dest_user_kern *udest, 2086static 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 }