Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/horms/lvs-2.6 into lvs-next-2.6

+1343 -568
+160
include/linux/ip_vs.h
··· 242 242 int syncid; 243 243 }; 244 244 245 + /* 246 + * 247 + * IPVS Generic Netlink interface definitions 248 + * 249 + */ 250 + 251 + /* Generic Netlink family info */ 252 + 253 + #define IPVS_GENL_NAME "IPVS" 254 + #define IPVS_GENL_VERSION 0x1 255 + 256 + struct ip_vs_flags { 257 + __be32 flags; 258 + __be32 mask; 259 + }; 260 + 261 + /* Generic Netlink command attributes */ 262 + enum { 263 + IPVS_CMD_UNSPEC = 0, 264 + 265 + IPVS_CMD_NEW_SERVICE, /* add service */ 266 + IPVS_CMD_SET_SERVICE, /* modify service */ 267 + IPVS_CMD_DEL_SERVICE, /* delete service */ 268 + IPVS_CMD_GET_SERVICE, /* get service info */ 269 + 270 + IPVS_CMD_NEW_DEST, /* add destination */ 271 + IPVS_CMD_SET_DEST, /* modify destination */ 272 + IPVS_CMD_DEL_DEST, /* delete destination */ 273 + IPVS_CMD_GET_DEST, /* get destination info */ 274 + 275 + IPVS_CMD_NEW_DAEMON, /* start sync daemon */ 276 + IPVS_CMD_DEL_DAEMON, /* stop sync daemon */ 277 + IPVS_CMD_GET_DAEMON, /* get sync daemon status */ 278 + 279 + IPVS_CMD_SET_CONFIG, /* set config settings */ 280 + IPVS_CMD_GET_CONFIG, /* get config settings */ 281 + 282 + IPVS_CMD_SET_INFO, /* only used in GET_INFO reply */ 283 + IPVS_CMD_GET_INFO, /* get general IPVS info */ 284 + 285 + IPVS_CMD_ZERO, /* zero all counters and stats */ 286 + IPVS_CMD_FLUSH, /* flush services and dests */ 287 + 288 + __IPVS_CMD_MAX, 289 + }; 290 + 291 + #define IPVS_CMD_MAX (__IPVS_CMD_MAX - 1) 292 + 293 + /* Attributes used in the first level of commands */ 294 + enum { 295 + IPVS_CMD_ATTR_UNSPEC = 0, 296 + IPVS_CMD_ATTR_SERVICE, /* nested service attribute */ 297 + IPVS_CMD_ATTR_DEST, /* nested destination attribute */ 298 + IPVS_CMD_ATTR_DAEMON, /* nested sync daemon attribute */ 299 + IPVS_CMD_ATTR_TIMEOUT_TCP, /* TCP connection timeout */ 300 + IPVS_CMD_ATTR_TIMEOUT_TCP_FIN, /* TCP FIN wait timeout */ 301 + IPVS_CMD_ATTR_TIMEOUT_UDP, /* UDP timeout */ 302 + __IPVS_CMD_ATTR_MAX, 303 + }; 304 + 305 + #define IPVS_CMD_ATTR_MAX (__IPVS_SVC_ATTR_MAX - 1) 306 + 307 + /* 308 + * Attributes used to describe a service 309 + * 310 + * Used inside nested attribute IPVS_CMD_ATTR_SERVICE 311 + */ 312 + enum { 313 + IPVS_SVC_ATTR_UNSPEC = 0, 314 + IPVS_SVC_ATTR_AF, /* address family */ 315 + IPVS_SVC_ATTR_PROTOCOL, /* virtual service protocol */ 316 + IPVS_SVC_ATTR_ADDR, /* virtual service address */ 317 + IPVS_SVC_ATTR_PORT, /* virtual service port */ 318 + IPVS_SVC_ATTR_FWMARK, /* firewall mark of service */ 319 + 320 + IPVS_SVC_ATTR_SCHED_NAME, /* name of scheduler */ 321 + IPVS_SVC_ATTR_FLAGS, /* virtual service flags */ 322 + IPVS_SVC_ATTR_TIMEOUT, /* persistent timeout */ 323 + IPVS_SVC_ATTR_NETMASK, /* persistent netmask */ 324 + 325 + IPVS_SVC_ATTR_STATS, /* nested attribute for service stats */ 326 + __IPVS_SVC_ATTR_MAX, 327 + }; 328 + 329 + #define IPVS_SVC_ATTR_MAX (__IPVS_SVC_ATTR_MAX - 1) 330 + 331 + /* 332 + * Attributes used to describe a destination (real server) 333 + * 334 + * Used inside nested attribute IPVS_CMD_ATTR_DEST 335 + */ 336 + enum { 337 + IPVS_DEST_ATTR_UNSPEC = 0, 338 + IPVS_DEST_ATTR_ADDR, /* real server address */ 339 + IPVS_DEST_ATTR_PORT, /* real server port */ 340 + 341 + IPVS_DEST_ATTR_FWD_METHOD, /* forwarding method */ 342 + IPVS_DEST_ATTR_WEIGHT, /* destination weight */ 343 + 344 + IPVS_DEST_ATTR_U_THRESH, /* upper threshold */ 345 + IPVS_DEST_ATTR_L_THRESH, /* lower threshold */ 346 + 347 + IPVS_DEST_ATTR_ACTIVE_CONNS, /* active connections */ 348 + IPVS_DEST_ATTR_INACT_CONNS, /* inactive connections */ 349 + IPVS_DEST_ATTR_PERSIST_CONNS, /* persistent connections */ 350 + 351 + IPVS_DEST_ATTR_STATS, /* nested attribute for dest stats */ 352 + __IPVS_DEST_ATTR_MAX, 353 + }; 354 + 355 + #define IPVS_DEST_ATTR_MAX (__IPVS_DEST_ATTR_MAX - 1) 356 + 357 + /* 358 + * Attributes describing a sync daemon 359 + * 360 + * Used inside nested attribute IPVS_CMD_ATTR_DAEMON 361 + */ 362 + enum { 363 + IPVS_DAEMON_ATTR_UNSPEC = 0, 364 + IPVS_DAEMON_ATTR_STATE, /* sync daemon state (master/backup) */ 365 + IPVS_DAEMON_ATTR_MCAST_IFN, /* multicast interface name */ 366 + IPVS_DAEMON_ATTR_SYNC_ID, /* SyncID we belong to */ 367 + __IPVS_DAEMON_ATTR_MAX, 368 + }; 369 + 370 + #define IPVS_DAEMON_ATTR_MAX (__IPVS_DAEMON_ATTR_MAX - 1) 371 + 372 + /* 373 + * Attributes used to describe service or destination entry statistics 374 + * 375 + * Used inside nested attributes IPVS_SVC_ATTR_STATS and IPVS_DEST_ATTR_STATS 376 + */ 377 + enum { 378 + IPVS_STATS_ATTR_UNSPEC = 0, 379 + IPVS_STATS_ATTR_CONNS, /* connections scheduled */ 380 + IPVS_STATS_ATTR_INPKTS, /* incoming packets */ 381 + IPVS_STATS_ATTR_OUTPKTS, /* outgoing packets */ 382 + IPVS_STATS_ATTR_INBYTES, /* incoming bytes */ 383 + IPVS_STATS_ATTR_OUTBYTES, /* outgoing bytes */ 384 + 385 + IPVS_STATS_ATTR_CPS, /* current connection rate */ 386 + IPVS_STATS_ATTR_INPPS, /* current in packet rate */ 387 + IPVS_STATS_ATTR_OUTPPS, /* current out packet rate */ 388 + IPVS_STATS_ATTR_INBPS, /* current in byte rate */ 389 + IPVS_STATS_ATTR_OUTBPS, /* current out byte rate */ 390 + __IPVS_STATS_ATTR_MAX, 391 + }; 392 + 393 + #define IPVS_STATS_ATTR_MAX (__IPVS_STATS_ATTR_MAX - 1) 394 + 395 + /* Attributes used in response to IPVS_CMD_GET_INFO command */ 396 + enum { 397 + IPVS_INFO_ATTR_UNSPEC = 0, 398 + IPVS_INFO_ATTR_VERSION, /* IPVS version number */ 399 + IPVS_INFO_ATTR_CONN_TAB_SIZE, /* size of connection hash table */ 400 + __IPVS_INFO_ATTR_MAX, 401 + }; 402 + 403 + #define IPVS_INFO_ATTR_MAX (__IPVS_INFO_ATTR_MAX - 1) 404 + 245 405 #endif /* _IP_VS_H */
+2
include/net/ip_vs.h
··· 683 683 /* 684 684 * IPVS rate estimator prototypes (from ip_vs_est.c) 685 685 */ 686 + extern int ip_vs_estimator_init(void); 687 + extern void ip_vs_estimator_cleanup(void); 686 688 extern void ip_vs_new_estimator(struct ip_vs_stats *stats); 687 689 extern void ip_vs_kill_estimator(struct ip_vs_stats *stats); 688 690 extern void ip_vs_zero_estimator(struct ip_vs_stats *stats);
+6
net/ipv4/ipvs/Kconfig
··· 71 71 This option enables support for load balancing UDP transport 72 72 protocol. Say Y if unsure. 73 73 74 + config IP_VS_PROTO_AH_ESP 75 + bool 76 + depends on UNDEFINED 77 + 74 78 config IP_VS_PROTO_ESP 75 79 bool "ESP load balancing support" 80 + select IP_VS_PROTO_AH_ESP 76 81 ---help--- 77 82 This option enables support for load balancing ESP (Encapsulation 78 83 Security Payload) transport protocol. Say Y if unsure. 79 84 80 85 config IP_VS_PROTO_AH 81 86 bool "AH load balancing support" 87 + select IP_VS_PROTO_AH_ESP 82 88 ---help--- 83 89 This option enables support for load balancing AH (Authentication 84 90 Header) transport protocol. Say Y if unsure.
+1 -2
net/ipv4/ipvs/Makefile
··· 6 6 ip_vs_proto-objs-y := 7 7 ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_TCP) += ip_vs_proto_tcp.o 8 8 ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_UDP) += ip_vs_proto_udp.o 9 - ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_ESP) += ip_vs_proto_esp.o 10 - ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_AH) += ip_vs_proto_ah.o 9 + ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_AH_ESP) += ip_vs_proto_ah_esp.o 11 10 12 11 ip_vs-objs := ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o \ 13 12 ip_vs_xmit.o ip_vs_app.o ip_vs_sync.o \
+6 -2
net/ipv4/ipvs/ip_vs_core.c
··· 1070 1070 { 1071 1071 int ret; 1072 1072 1073 + ip_vs_estimator_init(); 1074 + 1073 1075 ret = ip_vs_control_init(); 1074 1076 if (ret < 0) { 1075 1077 IP_VS_ERR("can't setup control.\n"); 1076 - goto cleanup_nothing; 1078 + goto cleanup_estimator; 1077 1079 } 1078 1080 1079 1081 ip_vs_protocol_init(); ··· 1108 1106 cleanup_protocol: 1109 1107 ip_vs_protocol_cleanup(); 1110 1108 ip_vs_control_cleanup(); 1111 - cleanup_nothing: 1109 + cleanup_estimator: 1110 + ip_vs_estimator_cleanup(); 1112 1111 return ret; 1113 1112 } 1114 1113 ··· 1120 1117 ip_vs_app_cleanup(); 1121 1118 ip_vs_protocol_cleanup(); 1122 1119 ip_vs_control_cleanup(); 1120 + ip_vs_estimator_cleanup(); 1123 1121 IP_VS_INFO("ipvs unloaded.\n"); 1124 1122 } 1125 1123
+887 -9
net/ipv4/ipvs/ip_vs_ctl.c
··· 37 37 #include <net/ip.h> 38 38 #include <net/route.h> 39 39 #include <net/sock.h> 40 + #include <net/genetlink.h> 40 41 41 42 #include <asm/uaccess.h> 42 43 ··· 869 868 svc->num_dests++; 870 869 871 870 /* call the update_service function of its scheduler */ 872 - svc->scheduler->update_service(svc); 871 + if (svc->scheduler->update_service) 872 + svc->scheduler->update_service(svc); 873 873 874 874 write_unlock_bh(&__ip_vs_svc_lock); 875 875 return 0; ··· 900 898 svc->num_dests++; 901 899 902 900 /* call the update_service function of its scheduler */ 903 - svc->scheduler->update_service(svc); 901 + if (svc->scheduler->update_service) 902 + svc->scheduler->update_service(svc); 904 903 905 904 write_unlock_bh(&__ip_vs_svc_lock); 906 905 ··· 951 948 IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1); 952 949 953 950 /* call the update_service, because server weight may be changed */ 954 - svc->scheduler->update_service(svc); 951 + if (svc->scheduler->update_service) 952 + svc->scheduler->update_service(svc); 955 953 956 954 write_unlock_bh(&__ip_vs_svc_lock); 957 955 ··· 1015 1011 */ 1016 1012 list_del(&dest->n_list); 1017 1013 svc->num_dests--; 1018 - if (svcupd) { 1019 - /* 1020 - * Call the update_service function of its scheduler 1021 - */ 1022 - svc->scheduler->update_service(svc); 1023 - } 1014 + 1015 + /* 1016 + * Call the update_service function of its scheduler 1017 + */ 1018 + if (svcupd && svc->scheduler->update_service) 1019 + svc->scheduler->update_service(svc); 1024 1020 } 1025 1021 1026 1022 ··· 2324 2320 .owner = THIS_MODULE, 2325 2321 }; 2326 2322 2323 + /* 2324 + * Generic Netlink interface 2325 + */ 2326 + 2327 + /* IPVS genetlink family */ 2328 + static struct genl_family ip_vs_genl_family = { 2329 + .id = GENL_ID_GENERATE, 2330 + .hdrsize = 0, 2331 + .name = IPVS_GENL_NAME, 2332 + .version = IPVS_GENL_VERSION, 2333 + .maxattr = IPVS_CMD_MAX, 2334 + }; 2335 + 2336 + /* Policy used for first-level command attributes */ 2337 + static const struct nla_policy ip_vs_cmd_policy[IPVS_CMD_ATTR_MAX + 1] = { 2338 + [IPVS_CMD_ATTR_SERVICE] = { .type = NLA_NESTED }, 2339 + [IPVS_CMD_ATTR_DEST] = { .type = NLA_NESTED }, 2340 + [IPVS_CMD_ATTR_DAEMON] = { .type = NLA_NESTED }, 2341 + [IPVS_CMD_ATTR_TIMEOUT_TCP] = { .type = NLA_U32 }, 2342 + [IPVS_CMD_ATTR_TIMEOUT_TCP_FIN] = { .type = NLA_U32 }, 2343 + [IPVS_CMD_ATTR_TIMEOUT_UDP] = { .type = NLA_U32 }, 2344 + }; 2345 + 2346 + /* Policy used for attributes in nested attribute IPVS_CMD_ATTR_DAEMON */ 2347 + static const struct nla_policy ip_vs_daemon_policy[IPVS_DAEMON_ATTR_MAX + 1] = { 2348 + [IPVS_DAEMON_ATTR_STATE] = { .type = NLA_U32 }, 2349 + [IPVS_DAEMON_ATTR_MCAST_IFN] = { .type = NLA_NUL_STRING, 2350 + .len = IP_VS_IFNAME_MAXLEN }, 2351 + [IPVS_DAEMON_ATTR_SYNC_ID] = { .type = NLA_U32 }, 2352 + }; 2353 + 2354 + /* Policy used for attributes in nested attribute IPVS_CMD_ATTR_SERVICE */ 2355 + static const struct nla_policy ip_vs_svc_policy[IPVS_SVC_ATTR_MAX + 1] = { 2356 + [IPVS_SVC_ATTR_AF] = { .type = NLA_U16 }, 2357 + [IPVS_SVC_ATTR_PROTOCOL] = { .type = NLA_U16 }, 2358 + [IPVS_SVC_ATTR_ADDR] = { .type = NLA_BINARY, 2359 + .len = sizeof(union nf_inet_addr) }, 2360 + [IPVS_SVC_ATTR_PORT] = { .type = NLA_U16 }, 2361 + [IPVS_SVC_ATTR_FWMARK] = { .type = NLA_U32 }, 2362 + [IPVS_SVC_ATTR_SCHED_NAME] = { .type = NLA_NUL_STRING, 2363 + .len = IP_VS_SCHEDNAME_MAXLEN }, 2364 + [IPVS_SVC_ATTR_FLAGS] = { .type = NLA_BINARY, 2365 + .len = sizeof(struct ip_vs_flags) }, 2366 + [IPVS_SVC_ATTR_TIMEOUT] = { .type = NLA_U32 }, 2367 + [IPVS_SVC_ATTR_NETMASK] = { .type = NLA_U32 }, 2368 + [IPVS_SVC_ATTR_STATS] = { .type = NLA_NESTED }, 2369 + }; 2370 + 2371 + /* Policy used for attributes in nested attribute IPVS_CMD_ATTR_DEST */ 2372 + static const struct nla_policy ip_vs_dest_policy[IPVS_DEST_ATTR_MAX + 1] = { 2373 + [IPVS_DEST_ATTR_ADDR] = { .type = NLA_BINARY, 2374 + .len = sizeof(union nf_inet_addr) }, 2375 + [IPVS_DEST_ATTR_PORT] = { .type = NLA_U16 }, 2376 + [IPVS_DEST_ATTR_FWD_METHOD] = { .type = NLA_U32 }, 2377 + [IPVS_DEST_ATTR_WEIGHT] = { .type = NLA_U32 }, 2378 + [IPVS_DEST_ATTR_U_THRESH] = { .type = NLA_U32 }, 2379 + [IPVS_DEST_ATTR_L_THRESH] = { .type = NLA_U32 }, 2380 + [IPVS_DEST_ATTR_ACTIVE_CONNS] = { .type = NLA_U32 }, 2381 + [IPVS_DEST_ATTR_INACT_CONNS] = { .type = NLA_U32 }, 2382 + [IPVS_DEST_ATTR_PERSIST_CONNS] = { .type = NLA_U32 }, 2383 + [IPVS_DEST_ATTR_STATS] = { .type = NLA_NESTED }, 2384 + }; 2385 + 2386 + static int ip_vs_genl_fill_stats(struct sk_buff *skb, int container_type, 2387 + struct ip_vs_stats *stats) 2388 + { 2389 + struct nlattr *nl_stats = nla_nest_start(skb, container_type); 2390 + if (!nl_stats) 2391 + return -EMSGSIZE; 2392 + 2393 + spin_lock_bh(&stats->lock); 2394 + 2395 + NLA_PUT_U32(skb, IPVS_STATS_ATTR_CONNS, stats->conns); 2396 + NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPKTS, stats->inpkts); 2397 + NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPKTS, stats->outpkts); 2398 + NLA_PUT_U64(skb, IPVS_STATS_ATTR_INBYTES, stats->inbytes); 2399 + NLA_PUT_U64(skb, IPVS_STATS_ATTR_OUTBYTES, stats->outbytes); 2400 + NLA_PUT_U32(skb, IPVS_STATS_ATTR_CPS, stats->cps); 2401 + NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPPS, stats->inpps); 2402 + NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPPS, stats->outpps); 2403 + NLA_PUT_U32(skb, IPVS_STATS_ATTR_INBPS, stats->inbps); 2404 + NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTBPS, stats->outbps); 2405 + 2406 + spin_unlock_bh(&stats->lock); 2407 + 2408 + nla_nest_end(skb, nl_stats); 2409 + 2410 + return 0; 2411 + 2412 + nla_put_failure: 2413 + spin_unlock_bh(&stats->lock); 2414 + nla_nest_cancel(skb, nl_stats); 2415 + return -EMSGSIZE; 2416 + } 2417 + 2418 + static int ip_vs_genl_fill_service(struct sk_buff *skb, 2419 + struct ip_vs_service *svc) 2420 + { 2421 + struct nlattr *nl_service; 2422 + struct ip_vs_flags flags = { .flags = svc->flags, 2423 + .mask = ~0 }; 2424 + 2425 + nl_service = nla_nest_start(skb, IPVS_CMD_ATTR_SERVICE); 2426 + if (!nl_service) 2427 + return -EMSGSIZE; 2428 + 2429 + NLA_PUT_U16(skb, IPVS_SVC_ATTR_AF, AF_INET); 2430 + 2431 + if (svc->fwmark) { 2432 + NLA_PUT_U32(skb, IPVS_SVC_ATTR_FWMARK, svc->fwmark); 2433 + } else { 2434 + NLA_PUT_U16(skb, IPVS_SVC_ATTR_PROTOCOL, svc->protocol); 2435 + NLA_PUT(skb, IPVS_SVC_ATTR_ADDR, sizeof(svc->addr), &svc->addr); 2436 + NLA_PUT_U16(skb, IPVS_SVC_ATTR_PORT, svc->port); 2437 + } 2438 + 2439 + NLA_PUT_STRING(skb, IPVS_SVC_ATTR_SCHED_NAME, svc->scheduler->name); 2440 + NLA_PUT(skb, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags); 2441 + NLA_PUT_U32(skb, IPVS_SVC_ATTR_TIMEOUT, svc->timeout / HZ); 2442 + NLA_PUT_U32(skb, IPVS_SVC_ATTR_NETMASK, svc->netmask); 2443 + 2444 + if (ip_vs_genl_fill_stats(skb, IPVS_SVC_ATTR_STATS, &svc->stats)) 2445 + goto nla_put_failure; 2446 + 2447 + nla_nest_end(skb, nl_service); 2448 + 2449 + return 0; 2450 + 2451 + nla_put_failure: 2452 + nla_nest_cancel(skb, nl_service); 2453 + return -EMSGSIZE; 2454 + } 2455 + 2456 + static int ip_vs_genl_dump_service(struct sk_buff *skb, 2457 + struct ip_vs_service *svc, 2458 + struct netlink_callback *cb) 2459 + { 2460 + void *hdr; 2461 + 2462 + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, 2463 + &ip_vs_genl_family, NLM_F_MULTI, 2464 + IPVS_CMD_NEW_SERVICE); 2465 + if (!hdr) 2466 + return -EMSGSIZE; 2467 + 2468 + if (ip_vs_genl_fill_service(skb, svc) < 0) 2469 + goto nla_put_failure; 2470 + 2471 + return genlmsg_end(skb, hdr); 2472 + 2473 + nla_put_failure: 2474 + genlmsg_cancel(skb, hdr); 2475 + return -EMSGSIZE; 2476 + } 2477 + 2478 + static int ip_vs_genl_dump_services(struct sk_buff *skb, 2479 + struct netlink_callback *cb) 2480 + { 2481 + int idx = 0, i; 2482 + int start = cb->args[0]; 2483 + struct ip_vs_service *svc; 2484 + 2485 + mutex_lock(&__ip_vs_mutex); 2486 + for (i = 0; i < IP_VS_SVC_TAB_SIZE; i++) { 2487 + list_for_each_entry(svc, &ip_vs_svc_table[i], s_list) { 2488 + if (++idx <= start) 2489 + continue; 2490 + if (ip_vs_genl_dump_service(skb, svc, cb) < 0) { 2491 + idx--; 2492 + goto nla_put_failure; 2493 + } 2494 + } 2495 + } 2496 + 2497 + for (i = 0; i < IP_VS_SVC_TAB_SIZE; i++) { 2498 + list_for_each_entry(svc, &ip_vs_svc_fwm_table[i], f_list) { 2499 + if (++idx <= start) 2500 + continue; 2501 + if (ip_vs_genl_dump_service(skb, svc, cb) < 0) { 2502 + idx--; 2503 + goto nla_put_failure; 2504 + } 2505 + } 2506 + } 2507 + 2508 + nla_put_failure: 2509 + mutex_unlock(&__ip_vs_mutex); 2510 + cb->args[0] = idx; 2511 + 2512 + return skb->len; 2513 + } 2514 + 2515 + static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc, 2516 + struct nlattr *nla, int full_entry) 2517 + { 2518 + struct nlattr *attrs[IPVS_SVC_ATTR_MAX + 1]; 2519 + struct nlattr *nla_af, *nla_port, *nla_fwmark, *nla_protocol, *nla_addr; 2520 + 2521 + /* Parse mandatory identifying service fields first */ 2522 + if (nla == NULL || 2523 + nla_parse_nested(attrs, IPVS_SVC_ATTR_MAX, nla, ip_vs_svc_policy)) 2524 + return -EINVAL; 2525 + 2526 + nla_af = attrs[IPVS_SVC_ATTR_AF]; 2527 + nla_protocol = attrs[IPVS_SVC_ATTR_PROTOCOL]; 2528 + nla_addr = attrs[IPVS_SVC_ATTR_ADDR]; 2529 + nla_port = attrs[IPVS_SVC_ATTR_PORT]; 2530 + nla_fwmark = attrs[IPVS_SVC_ATTR_FWMARK]; 2531 + 2532 + if (!(nla_af && (nla_fwmark || (nla_port && nla_protocol && nla_addr)))) 2533 + return -EINVAL; 2534 + 2535 + /* For now, only support IPv4 */ 2536 + if (nla_get_u16(nla_af) != AF_INET) 2537 + return -EAFNOSUPPORT; 2538 + 2539 + if (nla_fwmark) { 2540 + usvc->protocol = IPPROTO_TCP; 2541 + usvc->fwmark = nla_get_u32(nla_fwmark); 2542 + } else { 2543 + usvc->protocol = nla_get_u16(nla_protocol); 2544 + nla_memcpy(&usvc->addr, nla_addr, sizeof(usvc->addr)); 2545 + usvc->port = nla_get_u16(nla_port); 2546 + usvc->fwmark = 0; 2547 + } 2548 + 2549 + /* If a full entry was requested, check for the additional fields */ 2550 + if (full_entry) { 2551 + struct nlattr *nla_sched, *nla_flags, *nla_timeout, 2552 + *nla_netmask; 2553 + struct ip_vs_flags flags; 2554 + struct ip_vs_service *svc; 2555 + 2556 + nla_sched = attrs[IPVS_SVC_ATTR_SCHED_NAME]; 2557 + nla_flags = attrs[IPVS_SVC_ATTR_FLAGS]; 2558 + nla_timeout = attrs[IPVS_SVC_ATTR_TIMEOUT]; 2559 + nla_netmask = attrs[IPVS_SVC_ATTR_NETMASK]; 2560 + 2561 + if (!(nla_sched && nla_flags && nla_timeout && nla_netmask)) 2562 + return -EINVAL; 2563 + 2564 + nla_memcpy(&flags, nla_flags, sizeof(flags)); 2565 + 2566 + /* prefill flags from service if it already exists */ 2567 + if (usvc->fwmark) 2568 + svc = __ip_vs_svc_fwm_get(usvc->fwmark); 2569 + else 2570 + svc = __ip_vs_service_get(usvc->protocol, usvc->addr, 2571 + usvc->port); 2572 + if (svc) { 2573 + usvc->flags = svc->flags; 2574 + ip_vs_service_put(svc); 2575 + } else 2576 + usvc->flags = 0; 2577 + 2578 + /* set new flags from userland */ 2579 + usvc->flags = (usvc->flags & ~flags.mask) | 2580 + (flags.flags & flags.mask); 2581 + 2582 + strlcpy(usvc->sched_name, nla_data(nla_sched), 2583 + sizeof(usvc->sched_name)); 2584 + usvc->timeout = nla_get_u32(nla_timeout); 2585 + usvc->netmask = nla_get_u32(nla_netmask); 2586 + } 2587 + 2588 + return 0; 2589 + } 2590 + 2591 + static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla) 2592 + { 2593 + struct ip_vs_service_user usvc; 2594 + int ret; 2595 + 2596 + ret = ip_vs_genl_parse_service(&usvc, nla, 0); 2597 + if (ret) 2598 + return ERR_PTR(ret); 2599 + 2600 + if (usvc.fwmark) 2601 + return __ip_vs_svc_fwm_get(usvc.fwmark); 2602 + else 2603 + return __ip_vs_service_get(usvc.protocol, usvc.addr, 2604 + usvc.port); 2605 + } 2606 + 2607 + static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest) 2608 + { 2609 + struct nlattr *nl_dest; 2610 + 2611 + nl_dest = nla_nest_start(skb, IPVS_CMD_ATTR_DEST); 2612 + if (!nl_dest) 2613 + return -EMSGSIZE; 2614 + 2615 + NLA_PUT(skb, IPVS_DEST_ATTR_ADDR, sizeof(dest->addr), &dest->addr); 2616 + NLA_PUT_U16(skb, IPVS_DEST_ATTR_PORT, dest->port); 2617 + 2618 + NLA_PUT_U32(skb, IPVS_DEST_ATTR_FWD_METHOD, 2619 + atomic_read(&dest->conn_flags) & IP_VS_CONN_F_FWD_MASK); 2620 + NLA_PUT_U32(skb, IPVS_DEST_ATTR_WEIGHT, atomic_read(&dest->weight)); 2621 + NLA_PUT_U32(skb, IPVS_DEST_ATTR_U_THRESH, dest->u_threshold); 2622 + NLA_PUT_U32(skb, IPVS_DEST_ATTR_L_THRESH, dest->l_threshold); 2623 + NLA_PUT_U32(skb, IPVS_DEST_ATTR_ACTIVE_CONNS, 2624 + atomic_read(&dest->activeconns)); 2625 + NLA_PUT_U32(skb, IPVS_DEST_ATTR_INACT_CONNS, 2626 + atomic_read(&dest->inactconns)); 2627 + NLA_PUT_U32(skb, IPVS_DEST_ATTR_PERSIST_CONNS, 2628 + atomic_read(&dest->persistconns)); 2629 + 2630 + if (ip_vs_genl_fill_stats(skb, IPVS_DEST_ATTR_STATS, &dest->stats)) 2631 + goto nla_put_failure; 2632 + 2633 + nla_nest_end(skb, nl_dest); 2634 + 2635 + return 0; 2636 + 2637 + nla_put_failure: 2638 + nla_nest_cancel(skb, nl_dest); 2639 + return -EMSGSIZE; 2640 + } 2641 + 2642 + static int ip_vs_genl_dump_dest(struct sk_buff *skb, struct ip_vs_dest *dest, 2643 + struct netlink_callback *cb) 2644 + { 2645 + void *hdr; 2646 + 2647 + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, 2648 + &ip_vs_genl_family, NLM_F_MULTI, 2649 + IPVS_CMD_NEW_DEST); 2650 + if (!hdr) 2651 + return -EMSGSIZE; 2652 + 2653 + if (ip_vs_genl_fill_dest(skb, dest) < 0) 2654 + goto nla_put_failure; 2655 + 2656 + return genlmsg_end(skb, hdr); 2657 + 2658 + nla_put_failure: 2659 + genlmsg_cancel(skb, hdr); 2660 + return -EMSGSIZE; 2661 + } 2662 + 2663 + static int ip_vs_genl_dump_dests(struct sk_buff *skb, 2664 + struct netlink_callback *cb) 2665 + { 2666 + int idx = 0; 2667 + int start = cb->args[0]; 2668 + struct ip_vs_service *svc; 2669 + struct ip_vs_dest *dest; 2670 + struct nlattr *attrs[IPVS_CMD_ATTR_MAX + 1]; 2671 + 2672 + mutex_lock(&__ip_vs_mutex); 2673 + 2674 + /* Try to find the service for which to dump destinations */ 2675 + if (nlmsg_parse(cb->nlh, GENL_HDRLEN, attrs, 2676 + IPVS_CMD_ATTR_MAX, ip_vs_cmd_policy)) 2677 + goto out_err; 2678 + 2679 + svc = ip_vs_genl_find_service(attrs[IPVS_CMD_ATTR_SERVICE]); 2680 + if (IS_ERR(svc) || svc == NULL) 2681 + goto out_err; 2682 + 2683 + /* Dump the destinations */ 2684 + list_for_each_entry(dest, &svc->destinations, n_list) { 2685 + if (++idx <= start) 2686 + continue; 2687 + if (ip_vs_genl_dump_dest(skb, dest, cb) < 0) { 2688 + idx--; 2689 + goto nla_put_failure; 2690 + } 2691 + } 2692 + 2693 + nla_put_failure: 2694 + cb->args[0] = idx; 2695 + ip_vs_service_put(svc); 2696 + 2697 + out_err: 2698 + mutex_unlock(&__ip_vs_mutex); 2699 + 2700 + return skb->len; 2701 + } 2702 + 2703 + static int ip_vs_genl_parse_dest(struct ip_vs_dest_user *udest, 2704 + struct nlattr *nla, int full_entry) 2705 + { 2706 + struct nlattr *attrs[IPVS_DEST_ATTR_MAX + 1]; 2707 + struct nlattr *nla_addr, *nla_port; 2708 + 2709 + /* Parse mandatory identifying destination fields first */ 2710 + if (nla == NULL || 2711 + nla_parse_nested(attrs, IPVS_DEST_ATTR_MAX, nla, ip_vs_dest_policy)) 2712 + return -EINVAL; 2713 + 2714 + nla_addr = attrs[IPVS_DEST_ATTR_ADDR]; 2715 + nla_port = attrs[IPVS_DEST_ATTR_PORT]; 2716 + 2717 + if (!(nla_addr && nla_port)) 2718 + return -EINVAL; 2719 + 2720 + nla_memcpy(&udest->addr, nla_addr, sizeof(udest->addr)); 2721 + udest->port = nla_get_u16(nla_port); 2722 + 2723 + /* If a full entry was requested, check for the additional fields */ 2724 + if (full_entry) { 2725 + struct nlattr *nla_fwd, *nla_weight, *nla_u_thresh, 2726 + *nla_l_thresh; 2727 + 2728 + nla_fwd = attrs[IPVS_DEST_ATTR_FWD_METHOD]; 2729 + nla_weight = attrs[IPVS_DEST_ATTR_WEIGHT]; 2730 + nla_u_thresh = attrs[IPVS_DEST_ATTR_U_THRESH]; 2731 + nla_l_thresh = attrs[IPVS_DEST_ATTR_L_THRESH]; 2732 + 2733 + if (!(nla_fwd && nla_weight && nla_u_thresh && nla_l_thresh)) 2734 + return -EINVAL; 2735 + 2736 + udest->conn_flags = nla_get_u32(nla_fwd) 2737 + & IP_VS_CONN_F_FWD_MASK; 2738 + udest->weight = nla_get_u32(nla_weight); 2739 + udest->u_threshold = nla_get_u32(nla_u_thresh); 2740 + udest->l_threshold = nla_get_u32(nla_l_thresh); 2741 + } 2742 + 2743 + return 0; 2744 + } 2745 + 2746 + static int ip_vs_genl_fill_daemon(struct sk_buff *skb, __be32 state, 2747 + const char *mcast_ifn, __be32 syncid) 2748 + { 2749 + struct nlattr *nl_daemon; 2750 + 2751 + nl_daemon = nla_nest_start(skb, IPVS_CMD_ATTR_DAEMON); 2752 + if (!nl_daemon) 2753 + return -EMSGSIZE; 2754 + 2755 + NLA_PUT_U32(skb, IPVS_DAEMON_ATTR_STATE, state); 2756 + NLA_PUT_STRING(skb, IPVS_DAEMON_ATTR_MCAST_IFN, mcast_ifn); 2757 + NLA_PUT_U32(skb, IPVS_DAEMON_ATTR_SYNC_ID, syncid); 2758 + 2759 + nla_nest_end(skb, nl_daemon); 2760 + 2761 + return 0; 2762 + 2763 + nla_put_failure: 2764 + nla_nest_cancel(skb, nl_daemon); 2765 + return -EMSGSIZE; 2766 + } 2767 + 2768 + static int ip_vs_genl_dump_daemon(struct sk_buff *skb, __be32 state, 2769 + const char *mcast_ifn, __be32 syncid, 2770 + struct netlink_callback *cb) 2771 + { 2772 + void *hdr; 2773 + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, 2774 + &ip_vs_genl_family, NLM_F_MULTI, 2775 + IPVS_CMD_NEW_DAEMON); 2776 + if (!hdr) 2777 + return -EMSGSIZE; 2778 + 2779 + if (ip_vs_genl_fill_daemon(skb, state, mcast_ifn, syncid)) 2780 + goto nla_put_failure; 2781 + 2782 + return genlmsg_end(skb, hdr); 2783 + 2784 + nla_put_failure: 2785 + genlmsg_cancel(skb, hdr); 2786 + return -EMSGSIZE; 2787 + } 2788 + 2789 + static int ip_vs_genl_dump_daemons(struct sk_buff *skb, 2790 + struct netlink_callback *cb) 2791 + { 2792 + mutex_lock(&__ip_vs_mutex); 2793 + if ((ip_vs_sync_state & IP_VS_STATE_MASTER) && !cb->args[0]) { 2794 + if (ip_vs_genl_dump_daemon(skb, IP_VS_STATE_MASTER, 2795 + ip_vs_master_mcast_ifn, 2796 + ip_vs_master_syncid, cb) < 0) 2797 + goto nla_put_failure; 2798 + 2799 + cb->args[0] = 1; 2800 + } 2801 + 2802 + if ((ip_vs_sync_state & IP_VS_STATE_BACKUP) && !cb->args[1]) { 2803 + if (ip_vs_genl_dump_daemon(skb, IP_VS_STATE_BACKUP, 2804 + ip_vs_backup_mcast_ifn, 2805 + ip_vs_backup_syncid, cb) < 0) 2806 + goto nla_put_failure; 2807 + 2808 + cb->args[1] = 1; 2809 + } 2810 + 2811 + nla_put_failure: 2812 + mutex_unlock(&__ip_vs_mutex); 2813 + 2814 + return skb->len; 2815 + } 2816 + 2817 + static int ip_vs_genl_new_daemon(struct nlattr **attrs) 2818 + { 2819 + if (!(attrs[IPVS_DAEMON_ATTR_STATE] && 2820 + attrs[IPVS_DAEMON_ATTR_MCAST_IFN] && 2821 + attrs[IPVS_DAEMON_ATTR_SYNC_ID])) 2822 + return -EINVAL; 2823 + 2824 + return start_sync_thread(nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]), 2825 + nla_data(attrs[IPVS_DAEMON_ATTR_MCAST_IFN]), 2826 + nla_get_u32(attrs[IPVS_DAEMON_ATTR_SYNC_ID])); 2827 + } 2828 + 2829 + static int ip_vs_genl_del_daemon(struct nlattr **attrs) 2830 + { 2831 + if (!attrs[IPVS_DAEMON_ATTR_STATE]) 2832 + return -EINVAL; 2833 + 2834 + return stop_sync_thread(nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE])); 2835 + } 2836 + 2837 + static int ip_vs_genl_set_config(struct nlattr **attrs) 2838 + { 2839 + struct ip_vs_timeout_user t; 2840 + 2841 + __ip_vs_get_timeouts(&t); 2842 + 2843 + if (attrs[IPVS_CMD_ATTR_TIMEOUT_TCP]) 2844 + t.tcp_timeout = nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_TCP]); 2845 + 2846 + if (attrs[IPVS_CMD_ATTR_TIMEOUT_TCP_FIN]) 2847 + t.tcp_fin_timeout = 2848 + nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_TCP_FIN]); 2849 + 2850 + if (attrs[IPVS_CMD_ATTR_TIMEOUT_UDP]) 2851 + t.udp_timeout = nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_UDP]); 2852 + 2853 + return ip_vs_set_timeout(&t); 2854 + } 2855 + 2856 + static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info) 2857 + { 2858 + struct ip_vs_service *svc = NULL; 2859 + struct ip_vs_service_user usvc; 2860 + struct ip_vs_dest_user udest; 2861 + int ret = 0, cmd; 2862 + int need_full_svc = 0, need_full_dest = 0; 2863 + 2864 + cmd = info->genlhdr->cmd; 2865 + 2866 + mutex_lock(&__ip_vs_mutex); 2867 + 2868 + if (cmd == IPVS_CMD_FLUSH) { 2869 + ret = ip_vs_flush(); 2870 + goto out; 2871 + } else if (cmd == IPVS_CMD_SET_CONFIG) { 2872 + ret = ip_vs_genl_set_config(info->attrs); 2873 + goto out; 2874 + } else if (cmd == IPVS_CMD_NEW_DAEMON || 2875 + cmd == IPVS_CMD_DEL_DAEMON) { 2876 + 2877 + struct nlattr *daemon_attrs[IPVS_DAEMON_ATTR_MAX + 1]; 2878 + 2879 + if (!info->attrs[IPVS_CMD_ATTR_DAEMON] || 2880 + nla_parse_nested(daemon_attrs, IPVS_DAEMON_ATTR_MAX, 2881 + info->attrs[IPVS_CMD_ATTR_DAEMON], 2882 + ip_vs_daemon_policy)) { 2883 + ret = -EINVAL; 2884 + goto out; 2885 + } 2886 + 2887 + if (cmd == IPVS_CMD_NEW_DAEMON) 2888 + ret = ip_vs_genl_new_daemon(daemon_attrs); 2889 + else 2890 + ret = ip_vs_genl_del_daemon(daemon_attrs); 2891 + goto out; 2892 + } else if (cmd == IPVS_CMD_ZERO && 2893 + !info->attrs[IPVS_CMD_ATTR_SERVICE]) { 2894 + ret = ip_vs_zero_all(); 2895 + goto out; 2896 + } 2897 + 2898 + /* All following commands require a service argument, so check if we 2899 + * received a valid one. We need a full service specification when 2900 + * adding / editing a service. Only identifying members otherwise. */ 2901 + if (cmd == IPVS_CMD_NEW_SERVICE || cmd == IPVS_CMD_SET_SERVICE) 2902 + need_full_svc = 1; 2903 + 2904 + ret = ip_vs_genl_parse_service(&usvc, 2905 + info->attrs[IPVS_CMD_ATTR_SERVICE], 2906 + need_full_svc); 2907 + if (ret) 2908 + goto out; 2909 + 2910 + /* Lookup the exact service by <protocol, addr, port> or fwmark */ 2911 + if (usvc.fwmark == 0) 2912 + svc = __ip_vs_service_get(usvc.protocol, usvc.addr, usvc.port); 2913 + else 2914 + svc = __ip_vs_svc_fwm_get(usvc.fwmark); 2915 + 2916 + /* Unless we're adding a new service, the service must already exist */ 2917 + if ((cmd != IPVS_CMD_NEW_SERVICE) && (svc == NULL)) { 2918 + ret = -ESRCH; 2919 + goto out; 2920 + } 2921 + 2922 + /* Destination commands require a valid destination argument. For 2923 + * adding / editing a destination, we need a full destination 2924 + * specification. */ 2925 + if (cmd == IPVS_CMD_NEW_DEST || cmd == IPVS_CMD_SET_DEST || 2926 + cmd == IPVS_CMD_DEL_DEST) { 2927 + if (cmd != IPVS_CMD_DEL_DEST) 2928 + need_full_dest = 1; 2929 + 2930 + ret = ip_vs_genl_parse_dest(&udest, 2931 + info->attrs[IPVS_CMD_ATTR_DEST], 2932 + need_full_dest); 2933 + if (ret) 2934 + goto out; 2935 + } 2936 + 2937 + switch (cmd) { 2938 + case IPVS_CMD_NEW_SERVICE: 2939 + if (svc == NULL) 2940 + ret = ip_vs_add_service(&usvc, &svc); 2941 + else 2942 + ret = -EEXIST; 2943 + break; 2944 + case IPVS_CMD_SET_SERVICE: 2945 + ret = ip_vs_edit_service(svc, &usvc); 2946 + break; 2947 + case IPVS_CMD_DEL_SERVICE: 2948 + ret = ip_vs_del_service(svc); 2949 + break; 2950 + case IPVS_CMD_NEW_DEST: 2951 + ret = ip_vs_add_dest(svc, &udest); 2952 + break; 2953 + case IPVS_CMD_SET_DEST: 2954 + ret = ip_vs_edit_dest(svc, &udest); 2955 + break; 2956 + case IPVS_CMD_DEL_DEST: 2957 + ret = ip_vs_del_dest(svc, &udest); 2958 + break; 2959 + case IPVS_CMD_ZERO: 2960 + ret = ip_vs_zero_service(svc); 2961 + break; 2962 + default: 2963 + ret = -EINVAL; 2964 + } 2965 + 2966 + out: 2967 + if (svc) 2968 + ip_vs_service_put(svc); 2969 + mutex_unlock(&__ip_vs_mutex); 2970 + 2971 + return ret; 2972 + } 2973 + 2974 + static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info) 2975 + { 2976 + struct sk_buff *msg; 2977 + void *reply; 2978 + int ret, cmd, reply_cmd; 2979 + 2980 + cmd = info->genlhdr->cmd; 2981 + 2982 + if (cmd == IPVS_CMD_GET_SERVICE) 2983 + reply_cmd = IPVS_CMD_NEW_SERVICE; 2984 + else if (cmd == IPVS_CMD_GET_INFO) 2985 + reply_cmd = IPVS_CMD_SET_INFO; 2986 + else if (cmd == IPVS_CMD_GET_CONFIG) 2987 + reply_cmd = IPVS_CMD_SET_CONFIG; 2988 + else { 2989 + IP_VS_ERR("unknown Generic Netlink command\n"); 2990 + return -EINVAL; 2991 + } 2992 + 2993 + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 2994 + if (!msg) 2995 + return -ENOMEM; 2996 + 2997 + mutex_lock(&__ip_vs_mutex); 2998 + 2999 + reply = genlmsg_put_reply(msg, info, &ip_vs_genl_family, 0, reply_cmd); 3000 + if (reply == NULL) 3001 + goto nla_put_failure; 3002 + 3003 + switch (cmd) { 3004 + case IPVS_CMD_GET_SERVICE: 3005 + { 3006 + struct ip_vs_service *svc; 3007 + 3008 + svc = ip_vs_genl_find_service(info->attrs[IPVS_CMD_ATTR_SERVICE]); 3009 + if (IS_ERR(svc)) { 3010 + ret = PTR_ERR(svc); 3011 + goto out_err; 3012 + } else if (svc) { 3013 + ret = ip_vs_genl_fill_service(msg, svc); 3014 + ip_vs_service_put(svc); 3015 + if (ret) 3016 + goto nla_put_failure; 3017 + } else { 3018 + ret = -ESRCH; 3019 + goto out_err; 3020 + } 3021 + 3022 + break; 3023 + } 3024 + 3025 + case IPVS_CMD_GET_CONFIG: 3026 + { 3027 + struct ip_vs_timeout_user t; 3028 + 3029 + __ip_vs_get_timeouts(&t); 3030 + #ifdef CONFIG_IP_VS_PROTO_TCP 3031 + NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP, t.tcp_timeout); 3032 + NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP_FIN, 3033 + t.tcp_fin_timeout); 3034 + #endif 3035 + #ifdef CONFIG_IP_VS_PROTO_UDP 3036 + NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_UDP, t.udp_timeout); 3037 + #endif 3038 + 3039 + break; 3040 + } 3041 + 3042 + case IPVS_CMD_GET_INFO: 3043 + NLA_PUT_U32(msg, IPVS_INFO_ATTR_VERSION, IP_VS_VERSION_CODE); 3044 + NLA_PUT_U32(msg, IPVS_INFO_ATTR_CONN_TAB_SIZE, 3045 + IP_VS_CONN_TAB_SIZE); 3046 + break; 3047 + } 3048 + 3049 + genlmsg_end(msg, reply); 3050 + ret = genlmsg_unicast(msg, info->snd_pid); 3051 + goto out; 3052 + 3053 + nla_put_failure: 3054 + IP_VS_ERR("not enough space in Netlink message\n"); 3055 + ret = -EMSGSIZE; 3056 + 3057 + out_err: 3058 + nlmsg_free(msg); 3059 + out: 3060 + mutex_unlock(&__ip_vs_mutex); 3061 + 3062 + return ret; 3063 + } 3064 + 3065 + 3066 + static struct genl_ops ip_vs_genl_ops[] __read_mostly = { 3067 + { 3068 + .cmd = IPVS_CMD_NEW_SERVICE, 3069 + .flags = GENL_ADMIN_PERM, 3070 + .policy = ip_vs_cmd_policy, 3071 + .doit = ip_vs_genl_set_cmd, 3072 + }, 3073 + { 3074 + .cmd = IPVS_CMD_SET_SERVICE, 3075 + .flags = GENL_ADMIN_PERM, 3076 + .policy = ip_vs_cmd_policy, 3077 + .doit = ip_vs_genl_set_cmd, 3078 + }, 3079 + { 3080 + .cmd = IPVS_CMD_DEL_SERVICE, 3081 + .flags = GENL_ADMIN_PERM, 3082 + .policy = ip_vs_cmd_policy, 3083 + .doit = ip_vs_genl_set_cmd, 3084 + }, 3085 + { 3086 + .cmd = IPVS_CMD_GET_SERVICE, 3087 + .flags = GENL_ADMIN_PERM, 3088 + .doit = ip_vs_genl_get_cmd, 3089 + .dumpit = ip_vs_genl_dump_services, 3090 + .policy = ip_vs_cmd_policy, 3091 + }, 3092 + { 3093 + .cmd = IPVS_CMD_NEW_DEST, 3094 + .flags = GENL_ADMIN_PERM, 3095 + .policy = ip_vs_cmd_policy, 3096 + .doit = ip_vs_genl_set_cmd, 3097 + }, 3098 + { 3099 + .cmd = IPVS_CMD_SET_DEST, 3100 + .flags = GENL_ADMIN_PERM, 3101 + .policy = ip_vs_cmd_policy, 3102 + .doit = ip_vs_genl_set_cmd, 3103 + }, 3104 + { 3105 + .cmd = IPVS_CMD_DEL_DEST, 3106 + .flags = GENL_ADMIN_PERM, 3107 + .policy = ip_vs_cmd_policy, 3108 + .doit = ip_vs_genl_set_cmd, 3109 + }, 3110 + { 3111 + .cmd = IPVS_CMD_GET_DEST, 3112 + .flags = GENL_ADMIN_PERM, 3113 + .policy = ip_vs_cmd_policy, 3114 + .dumpit = ip_vs_genl_dump_dests, 3115 + }, 3116 + { 3117 + .cmd = IPVS_CMD_NEW_DAEMON, 3118 + .flags = GENL_ADMIN_PERM, 3119 + .policy = ip_vs_cmd_policy, 3120 + .doit = ip_vs_genl_set_cmd, 3121 + }, 3122 + { 3123 + .cmd = IPVS_CMD_DEL_DAEMON, 3124 + .flags = GENL_ADMIN_PERM, 3125 + .policy = ip_vs_cmd_policy, 3126 + .doit = ip_vs_genl_set_cmd, 3127 + }, 3128 + { 3129 + .cmd = IPVS_CMD_GET_DAEMON, 3130 + .flags = GENL_ADMIN_PERM, 3131 + .dumpit = ip_vs_genl_dump_daemons, 3132 + }, 3133 + { 3134 + .cmd = IPVS_CMD_SET_CONFIG, 3135 + .flags = GENL_ADMIN_PERM, 3136 + .policy = ip_vs_cmd_policy, 3137 + .doit = ip_vs_genl_set_cmd, 3138 + }, 3139 + { 3140 + .cmd = IPVS_CMD_GET_CONFIG, 3141 + .flags = GENL_ADMIN_PERM, 3142 + .doit = ip_vs_genl_get_cmd, 3143 + }, 3144 + { 3145 + .cmd = IPVS_CMD_GET_INFO, 3146 + .flags = GENL_ADMIN_PERM, 3147 + .doit = ip_vs_genl_get_cmd, 3148 + }, 3149 + { 3150 + .cmd = IPVS_CMD_ZERO, 3151 + .flags = GENL_ADMIN_PERM, 3152 + .policy = ip_vs_cmd_policy, 3153 + .doit = ip_vs_genl_set_cmd, 3154 + }, 3155 + { 3156 + .cmd = IPVS_CMD_FLUSH, 3157 + .flags = GENL_ADMIN_PERM, 3158 + .doit = ip_vs_genl_set_cmd, 3159 + }, 3160 + }; 3161 + 3162 + static int __init ip_vs_genl_register(void) 3163 + { 3164 + int ret, i; 3165 + 3166 + ret = genl_register_family(&ip_vs_genl_family); 3167 + if (ret) 3168 + return ret; 3169 + 3170 + for (i = 0; i < ARRAY_SIZE(ip_vs_genl_ops); i++) { 3171 + ret = genl_register_ops(&ip_vs_genl_family, &ip_vs_genl_ops[i]); 3172 + if (ret) 3173 + goto err_out; 3174 + } 3175 + return 0; 3176 + 3177 + err_out: 3178 + genl_unregister_family(&ip_vs_genl_family); 3179 + return ret; 3180 + } 3181 + 3182 + static void ip_vs_genl_unregister(void) 3183 + { 3184 + genl_unregister_family(&ip_vs_genl_family); 3185 + } 3186 + 3187 + /* End of Generic Netlink interface definitions */ 3188 + 2327 3189 2328 3190 int __init ip_vs_control_init(void) 2329 3191 { ··· 3201 2331 ret = nf_register_sockopt(&ip_vs_sockopts); 3202 2332 if (ret) { 3203 2333 IP_VS_ERR("cannot register sockopt.\n"); 2334 + return ret; 2335 + } 2336 + 2337 + ret = ip_vs_genl_register(); 2338 + if (ret) { 2339 + IP_VS_ERR("cannot register Generic Netlink interface.\n"); 2340 + nf_unregister_sockopt(&ip_vs_sockopts); 3204 2341 return ret; 3205 2342 } 3206 2343 ··· 3245 2368 unregister_sysctl_table(sysctl_header); 3246 2369 proc_net_remove(&init_net, "ip_vs_stats"); 3247 2370 proc_net_remove(&init_net, "ip_vs"); 2371 + ip_vs_genl_unregister(); 3248 2372 nf_unregister_sockopt(&ip_vs_sockopts); 3249 2373 LeaveFunction(2); 3250 2374 }
+11 -7
net/ipv4/ipvs/ip_vs_est.c
··· 124 124 est->outbps = stats->outbps<<5; 125 125 126 126 spin_lock_bh(&est_lock); 127 - if (list_empty(&est_list)) 128 - mod_timer(&est_timer, jiffies + 2 * HZ); 129 127 list_add(&est->list, &est_list); 130 128 spin_unlock_bh(&est_lock); 131 129 } ··· 134 136 135 137 spin_lock_bh(&est_lock); 136 138 list_del(&est->list); 137 - while (list_empty(&est_list) && try_to_del_timer_sync(&est_timer) < 0) { 138 - spin_unlock_bh(&est_lock); 139 - cpu_relax(); 140 - spin_lock_bh(&est_lock); 141 - } 142 139 spin_unlock_bh(&est_lock); 143 140 } 144 141 ··· 152 159 est->outpps = 0; 153 160 est->inbps = 0; 154 161 est->outbps = 0; 162 + } 163 + 164 + int __init ip_vs_estimator_init(void) 165 + { 166 + mod_timer(&est_timer, jiffies + 2 * HZ); 167 + return 0; 168 + } 169 + 170 + void ip_vs_estimator_cleanup(void) 171 + { 172 + del_timer_sync(&est_timer); 155 173 }
+100 -119
net/ipv4/ipvs/ip_vs_lblc.c
··· 96 96 * IPVS lblc hash table 97 97 */ 98 98 struct ip_vs_lblc_table { 99 - rwlock_t lock; /* lock for this table */ 100 99 struct list_head bucket[IP_VS_LBLC_TAB_SIZE]; /* hash bucket */ 101 100 atomic_t entries; /* number of entries */ 102 101 int max_size; /* maximum size of entries */ ··· 122 123 123 124 static struct ctl_table_header * sysctl_header; 124 125 125 - /* 126 - * new/free a ip_vs_lblc_entry, which is a mapping of a destionation 127 - * IP address to a server. 128 - */ 129 - static inline struct ip_vs_lblc_entry * 130 - ip_vs_lblc_new(__be32 daddr, struct ip_vs_dest *dest) 131 - { 132 - struct ip_vs_lblc_entry *en; 133 - 134 - en = kmalloc(sizeof(struct ip_vs_lblc_entry), GFP_ATOMIC); 135 - if (en == NULL) { 136 - IP_VS_ERR("ip_vs_lblc_new(): no memory\n"); 137 - return NULL; 138 - } 139 - 140 - INIT_LIST_HEAD(&en->list); 141 - en->addr = daddr; 142 - 143 - atomic_inc(&dest->refcnt); 144 - en->dest = dest; 145 - 146 - return en; 147 - } 148 - 149 - 150 126 static inline void ip_vs_lblc_free(struct ip_vs_lblc_entry *en) 151 127 { 152 128 list_del(&en->list); ··· 147 173 * Hash an entry in the ip_vs_lblc_table. 148 174 * returns bool success. 149 175 */ 150 - static int 176 + static void 151 177 ip_vs_lblc_hash(struct ip_vs_lblc_table *tbl, struct ip_vs_lblc_entry *en) 152 178 { 153 - unsigned hash; 179 + unsigned hash = ip_vs_lblc_hashkey(en->addr); 154 180 155 - if (!list_empty(&en->list)) { 156 - IP_VS_ERR("ip_vs_lblc_hash(): request for already hashed, " 157 - "called from %p\n", __builtin_return_address(0)); 158 - return 0; 159 - } 160 - 161 - /* 162 - * Hash by destination IP address 163 - */ 164 - hash = ip_vs_lblc_hashkey(en->addr); 165 - 166 - write_lock(&tbl->lock); 167 181 list_add(&en->list, &tbl->bucket[hash]); 168 182 atomic_inc(&tbl->entries); 169 - write_unlock(&tbl->lock); 170 - 171 - return 1; 172 183 } 173 184 174 185 175 186 /* 176 - * Get ip_vs_lblc_entry associated with supplied parameters. 187 + * Get ip_vs_lblc_entry associated with supplied parameters. Called under read 188 + * lock 177 189 */ 178 190 static inline struct ip_vs_lblc_entry * 179 191 ip_vs_lblc_get(struct ip_vs_lblc_table *tbl, __be32 addr) 180 192 { 181 - unsigned hash; 193 + unsigned hash = ip_vs_lblc_hashkey(addr); 182 194 struct ip_vs_lblc_entry *en; 183 195 184 - hash = ip_vs_lblc_hashkey(addr); 185 - 186 - read_lock(&tbl->lock); 187 - 188 - list_for_each_entry(en, &tbl->bucket[hash], list) { 189 - if (en->addr == addr) { 190 - /* HIT */ 191 - read_unlock(&tbl->lock); 196 + list_for_each_entry(en, &tbl->bucket[hash], list) 197 + if (en->addr == addr) 192 198 return en; 193 - } 194 - } 195 - 196 - read_unlock(&tbl->lock); 197 199 198 200 return NULL; 201 + } 202 + 203 + 204 + /* 205 + * Create or update an ip_vs_lblc_entry, which is a mapping of a destination IP 206 + * address to a server. Called under write lock. 207 + */ 208 + static inline struct ip_vs_lblc_entry * 209 + ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, __be32 daddr, 210 + struct ip_vs_dest *dest) 211 + { 212 + struct ip_vs_lblc_entry *en; 213 + 214 + en = ip_vs_lblc_get(tbl, daddr); 215 + if (!en) { 216 + en = kmalloc(sizeof(*en), GFP_ATOMIC); 217 + if (!en) { 218 + IP_VS_ERR("ip_vs_lblc_new(): no memory\n"); 219 + return NULL; 220 + } 221 + 222 + en->addr = daddr; 223 + en->lastuse = jiffies; 224 + 225 + atomic_inc(&dest->refcnt); 226 + en->dest = dest; 227 + 228 + ip_vs_lblc_hash(tbl, en); 229 + } else if (en->dest != dest) { 230 + atomic_dec(&en->dest->refcnt); 231 + atomic_inc(&dest->refcnt); 232 + en->dest = dest; 233 + } 234 + 235 + return en; 199 236 } 200 237 201 238 ··· 215 230 */ 216 231 static void ip_vs_lblc_flush(struct ip_vs_lblc_table *tbl) 217 232 { 218 - int i; 219 233 struct ip_vs_lblc_entry *en, *nxt; 234 + int i; 220 235 221 236 for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) { 222 - write_lock(&tbl->lock); 223 237 list_for_each_entry_safe(en, nxt, &tbl->bucket[i], list) { 224 238 ip_vs_lblc_free(en); 225 239 atomic_dec(&tbl->entries); 226 240 } 227 - write_unlock(&tbl->lock); 228 241 } 229 242 } 230 243 231 244 232 - static inline void ip_vs_lblc_full_check(struct ip_vs_lblc_table *tbl) 245 + static inline void ip_vs_lblc_full_check(struct ip_vs_service *svc) 233 246 { 247 + struct ip_vs_lblc_table *tbl = svc->sched_data; 248 + struct ip_vs_lblc_entry *en, *nxt; 234 249 unsigned long now = jiffies; 235 250 int i, j; 236 - struct ip_vs_lblc_entry *en, *nxt; 237 251 238 252 for (i=0, j=tbl->rover; i<IP_VS_LBLC_TAB_SIZE; i++) { 239 253 j = (j + 1) & IP_VS_LBLC_TAB_MASK; 240 254 241 - write_lock(&tbl->lock); 255 + write_lock(&svc->sched_lock); 242 256 list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) { 243 257 if (time_before(now, 244 258 en->lastuse + sysctl_ip_vs_lblc_expiration)) ··· 246 262 ip_vs_lblc_free(en); 247 263 atomic_dec(&tbl->entries); 248 264 } 249 - write_unlock(&tbl->lock); 265 + write_unlock(&svc->sched_lock); 250 266 } 251 267 tbl->rover = j; 252 268 } ··· 265 281 */ 266 282 static void ip_vs_lblc_check_expire(unsigned long data) 267 283 { 268 - struct ip_vs_lblc_table *tbl; 284 + struct ip_vs_service *svc = (struct ip_vs_service *) data; 285 + struct ip_vs_lblc_table *tbl = svc->sched_data; 269 286 unsigned long now = jiffies; 270 287 int goal; 271 288 int i, j; 272 289 struct ip_vs_lblc_entry *en, *nxt; 273 290 274 - tbl = (struct ip_vs_lblc_table *)data; 275 - 276 291 if ((tbl->counter % COUNT_FOR_FULL_EXPIRATION) == 0) { 277 292 /* do full expiration check */ 278 - ip_vs_lblc_full_check(tbl); 293 + ip_vs_lblc_full_check(svc); 279 294 tbl->counter = 1; 280 295 goto out; 281 296 } ··· 291 308 for (i=0, j=tbl->rover; i<IP_VS_LBLC_TAB_SIZE; i++) { 292 309 j = (j + 1) & IP_VS_LBLC_TAB_MASK; 293 310 294 - write_lock(&tbl->lock); 311 + write_lock(&svc->sched_lock); 295 312 list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) { 296 313 if (time_before(now, en->lastuse + ENTRY_TIMEOUT)) 297 314 continue; ··· 300 317 atomic_dec(&tbl->entries); 301 318 goal--; 302 319 } 303 - write_unlock(&tbl->lock); 320 + write_unlock(&svc->sched_lock); 304 321 if (goal <= 0) 305 322 break; 306 323 } ··· 319 336 /* 320 337 * Allocate the ip_vs_lblc_table for this service 321 338 */ 322 - tbl = kmalloc(sizeof(struct ip_vs_lblc_table), GFP_ATOMIC); 339 + tbl = kmalloc(sizeof(*tbl), GFP_ATOMIC); 323 340 if (tbl == NULL) { 324 341 IP_VS_ERR("ip_vs_lblc_init_svc(): no memory\n"); 325 342 return -ENOMEM; 326 343 } 327 344 svc->sched_data = tbl; 328 345 IP_VS_DBG(6, "LBLC hash table (memory=%Zdbytes) allocated for " 329 - "current service\n", 330 - sizeof(struct ip_vs_lblc_table)); 346 + "current service\n", sizeof(*tbl)); 331 347 332 348 /* 333 349 * Initialize the hash buckets ··· 334 352 for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) { 335 353 INIT_LIST_HEAD(&tbl->bucket[i]); 336 354 } 337 - rwlock_init(&tbl->lock); 338 355 tbl->max_size = IP_VS_LBLC_TAB_SIZE*16; 339 356 tbl->rover = 0; 340 357 tbl->counter = 1; ··· 342 361 * Hook periodic timer for garbage collection 343 362 */ 344 363 setup_timer(&tbl->periodic_timer, ip_vs_lblc_check_expire, 345 - (unsigned long)tbl); 346 - tbl->periodic_timer.expires = jiffies+CHECK_EXPIRE_INTERVAL; 347 - add_timer(&tbl->periodic_timer); 364 + (unsigned long)svc); 365 + mod_timer(&tbl->periodic_timer, jiffies + CHECK_EXPIRE_INTERVAL); 348 366 349 367 return 0; 350 368 } ··· 360 380 ip_vs_lblc_flush(tbl); 361 381 362 382 /* release the table itself */ 363 - kfree(svc->sched_data); 383 + kfree(tbl); 364 384 IP_VS_DBG(6, "LBLC hash table (memory=%Zdbytes) released\n", 365 - sizeof(struct ip_vs_lblc_table)); 385 + sizeof(*tbl)); 366 386 367 - return 0; 368 - } 369 - 370 - 371 - static int ip_vs_lblc_update_svc(struct ip_vs_service *svc) 372 - { 373 387 return 0; 374 388 } 375 389 376 390 377 391 static inline struct ip_vs_dest * 378 - __ip_vs_wlc_schedule(struct ip_vs_service *svc, struct iphdr *iph) 392 + __ip_vs_lblc_schedule(struct ip_vs_service *svc, struct iphdr *iph) 379 393 { 380 394 struct ip_vs_dest *dest, *least; 381 395 int loh, doh; ··· 458 484 static struct ip_vs_dest * 459 485 ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) 460 486 { 461 - struct ip_vs_dest *dest; 462 - struct ip_vs_lblc_table *tbl; 463 - struct ip_vs_lblc_entry *en; 487 + struct ip_vs_lblc_table *tbl = svc->sched_data; 464 488 struct iphdr *iph = ip_hdr(skb); 489 + struct ip_vs_dest *dest = NULL; 490 + struct ip_vs_lblc_entry *en; 465 491 466 492 IP_VS_DBG(6, "ip_vs_lblc_schedule(): Scheduling...\n"); 467 493 468 - tbl = (struct ip_vs_lblc_table *)svc->sched_data; 494 + /* First look in our cache */ 495 + read_lock(&svc->sched_lock); 469 496 en = ip_vs_lblc_get(tbl, iph->daddr); 470 - if (en == NULL) { 471 - dest = __ip_vs_wlc_schedule(svc, iph); 472 - if (dest == NULL) { 473 - IP_VS_DBG(1, "no destination available\n"); 474 - return NULL; 475 - } 476 - en = ip_vs_lblc_new(iph->daddr, dest); 477 - if (en == NULL) { 478 - return NULL; 479 - } 480 - ip_vs_lblc_hash(tbl, en); 481 - } else { 482 - dest = en->dest; 483 - if (!(dest->flags & IP_VS_DEST_F_AVAILABLE) 484 - || atomic_read(&dest->weight) <= 0 485 - || is_overloaded(dest, svc)) { 486 - dest = __ip_vs_wlc_schedule(svc, iph); 487 - if (dest == NULL) { 488 - IP_VS_DBG(1, "no destination available\n"); 489 - return NULL; 490 - } 491 - atomic_dec(&en->dest->refcnt); 492 - atomic_inc(&dest->refcnt); 493 - en->dest = dest; 494 - } 495 - } 496 - en->lastuse = jiffies; 497 + if (en) { 498 + /* We only hold a read lock, but this is atomic */ 499 + en->lastuse = jiffies; 497 500 501 + /* 502 + * If the destination is not available, i.e. it's in the trash, 503 + * we must ignore it, as it may be removed from under our feet, 504 + * if someone drops our reference count. Our caller only makes 505 + * sure that destinations, that are not in the trash, are not 506 + * moved to the trash, while we are scheduling. But anyone can 507 + * free up entries from the trash at any time. 508 + */ 509 + 510 + if (en->dest->flags & IP_VS_DEST_F_AVAILABLE) 511 + dest = en->dest; 512 + } 513 + read_unlock(&svc->sched_lock); 514 + 515 + /* If the destination has a weight and is not overloaded, use it */ 516 + if (dest && atomic_read(&dest->weight) > 0 && !is_overloaded(dest, svc)) 517 + goto out; 518 + 519 + /* No cache entry or it is invalid, time to schedule */ 520 + dest = __ip_vs_lblc_schedule(svc, iph); 521 + if (!dest) { 522 + IP_VS_DBG(1, "no destination available\n"); 523 + return NULL; 524 + } 525 + 526 + /* If we fail to create a cache entry, we'll just use the valid dest */ 527 + write_lock(&svc->sched_lock); 528 + ip_vs_lblc_new(tbl, iph->daddr, dest); 529 + write_unlock(&svc->sched_lock); 530 + 531 + out: 498 532 IP_VS_DBG(6, "LBLC: destination IP address %u.%u.%u.%u " 499 533 "--> server %u.%u.%u.%u:%d\n", 500 - NIPQUAD(en->addr), 534 + NIPQUAD(iph->daddr), 501 535 NIPQUAD(dest->addr), 502 536 ntohs(dest->port)); 503 537 ··· 524 542 .n_list = LIST_HEAD_INIT(ip_vs_lblc_scheduler.n_list), 525 543 .init_service = ip_vs_lblc_init_svc, 526 544 .done_service = ip_vs_lblc_done_svc, 527 - .update_service = ip_vs_lblc_update_svc, 528 545 .schedule = ip_vs_lblc_schedule, 529 546 }; 530 547
+119 -127
net/ipv4/ipvs/ip_vs_lblcr.c
··· 106 106 return NULL; 107 107 } 108 108 109 - e = kmalloc(sizeof(struct ip_vs_dest_list), GFP_ATOMIC); 109 + e = kmalloc(sizeof(*e), GFP_ATOMIC); 110 110 if (e == NULL) { 111 111 IP_VS_ERR("ip_vs_dest_set_insert(): no memory\n"); 112 112 return NULL; ··· 116 116 e->dest = dest; 117 117 118 118 /* link it to the list */ 119 - write_lock(&set->lock); 120 119 e->next = set->list; 121 120 set->list = e; 122 121 atomic_inc(&set->size); 123 - write_unlock(&set->lock); 124 122 125 123 set->lastmod = jiffies; 126 124 return e; ··· 129 131 { 130 132 struct ip_vs_dest_list *e, **ep; 131 133 132 - write_lock(&set->lock); 133 134 for (ep=&set->list, e=*ep; e!=NULL; e=*ep) { 134 135 if (e->dest == dest) { 135 136 /* HIT */ ··· 141 144 } 142 145 ep = &e->next; 143 146 } 144 - write_unlock(&set->lock); 145 147 } 146 148 147 149 static void ip_vs_dest_set_eraseall(struct ip_vs_dest_set *set) ··· 170 174 if (set == NULL) 171 175 return NULL; 172 176 173 - read_lock(&set->lock); 174 177 /* select the first destination server, whose weight > 0 */ 175 178 for (e=set->list; e!=NULL; e=e->next) { 176 179 least = e->dest; ··· 183 188 goto nextstage; 184 189 } 185 190 } 186 - read_unlock(&set->lock); 187 191 return NULL; 188 192 189 193 /* find the destination with the weighted least load */ ··· 201 207 loh = doh; 202 208 } 203 209 } 204 - read_unlock(&set->lock); 205 210 206 211 IP_VS_DBG(6, "ip_vs_dest_set_min: server %d.%d.%d.%d:%d " 207 212 "activeconns %d refcnt %d weight %d overhead %d\n", ··· 222 229 if (set == NULL) 223 230 return NULL; 224 231 225 - read_lock(&set->lock); 226 232 /* select the first destination server, whose weight > 0 */ 227 233 for (e=set->list; e!=NULL; e=e->next) { 228 234 most = e->dest; ··· 231 239 goto nextstage; 232 240 } 233 241 } 234 - read_unlock(&set->lock); 235 242 return NULL; 236 243 237 244 /* find the destination with the weighted most load */ ··· 247 256 moh = doh; 248 257 } 249 258 } 250 - read_unlock(&set->lock); 251 259 252 260 IP_VS_DBG(6, "ip_vs_dest_set_max: server %d.%d.%d.%d:%d " 253 261 "activeconns %d refcnt %d weight %d overhead %d\n", ··· 274 284 * IPVS lblcr hash table 275 285 */ 276 286 struct ip_vs_lblcr_table { 277 - rwlock_t lock; /* lock for this table */ 278 287 struct list_head bucket[IP_VS_LBLCR_TAB_SIZE]; /* hash bucket */ 279 288 atomic_t entries; /* number of entries */ 280 289 int max_size; /* maximum size of entries */ ··· 300 311 301 312 static struct ctl_table_header * sysctl_header; 302 313 303 - /* 304 - * new/free a ip_vs_lblcr_entry, which is a mapping of a destination 305 - * IP address to a server. 306 - */ 307 - static inline struct ip_vs_lblcr_entry *ip_vs_lblcr_new(__be32 daddr) 308 - { 309 - struct ip_vs_lblcr_entry *en; 310 - 311 - en = kmalloc(sizeof(struct ip_vs_lblcr_entry), GFP_ATOMIC); 312 - if (en == NULL) { 313 - IP_VS_ERR("ip_vs_lblcr_new(): no memory\n"); 314 - return NULL; 315 - } 316 - 317 - INIT_LIST_HEAD(&en->list); 318 - en->addr = daddr; 319 - 320 - /* initilize its dest set */ 321 - atomic_set(&(en->set.size), 0); 322 - en->set.list = NULL; 323 - rwlock_init(&en->set.lock); 324 - 325 - return en; 326 - } 327 - 328 - 329 314 static inline void ip_vs_lblcr_free(struct ip_vs_lblcr_entry *en) 330 315 { 331 316 list_del(&en->list); ··· 321 358 * Hash an entry in the ip_vs_lblcr_table. 322 359 * returns bool success. 323 360 */ 324 - static int 361 + static void 325 362 ip_vs_lblcr_hash(struct ip_vs_lblcr_table *tbl, struct ip_vs_lblcr_entry *en) 326 363 { 327 - unsigned hash; 364 + unsigned hash = ip_vs_lblcr_hashkey(en->addr); 328 365 329 - if (!list_empty(&en->list)) { 330 - IP_VS_ERR("ip_vs_lblcr_hash(): request for already hashed, " 331 - "called from %p\n", __builtin_return_address(0)); 332 - return 0; 333 - } 334 - 335 - /* 336 - * Hash by destination IP address 337 - */ 338 - hash = ip_vs_lblcr_hashkey(en->addr); 339 - 340 - write_lock(&tbl->lock); 341 366 list_add(&en->list, &tbl->bucket[hash]); 342 367 atomic_inc(&tbl->entries); 343 - write_unlock(&tbl->lock); 344 - 345 - return 1; 346 368 } 347 369 348 370 349 371 /* 350 - * Get ip_vs_lblcr_entry associated with supplied parameters. 372 + * Get ip_vs_lblcr_entry associated with supplied parameters. Called under 373 + * read lock. 351 374 */ 352 375 static inline struct ip_vs_lblcr_entry * 353 376 ip_vs_lblcr_get(struct ip_vs_lblcr_table *tbl, __be32 addr) 354 377 { 355 - unsigned hash; 378 + unsigned hash = ip_vs_lblcr_hashkey(addr); 356 379 struct ip_vs_lblcr_entry *en; 357 380 358 - hash = ip_vs_lblcr_hashkey(addr); 359 - 360 - read_lock(&tbl->lock); 361 - 362 - list_for_each_entry(en, &tbl->bucket[hash], list) { 363 - if (en->addr == addr) { 364 - /* HIT */ 365 - read_unlock(&tbl->lock); 381 + list_for_each_entry(en, &tbl->bucket[hash], list) 382 + if (en->addr == addr) 366 383 return en; 367 - } 368 - } 369 - 370 - read_unlock(&tbl->lock); 371 384 372 385 return NULL; 386 + } 387 + 388 + 389 + /* 390 + * Create or update an ip_vs_lblcr_entry, which is a mapping of a destination 391 + * IP address to a server. Called under write lock. 392 + */ 393 + static inline struct ip_vs_lblcr_entry * 394 + ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, __be32 daddr, 395 + struct ip_vs_dest *dest) 396 + { 397 + struct ip_vs_lblcr_entry *en; 398 + 399 + en = ip_vs_lblcr_get(tbl, daddr); 400 + if (!en) { 401 + en = kmalloc(sizeof(*en), GFP_ATOMIC); 402 + if (!en) { 403 + IP_VS_ERR("ip_vs_lblcr_new(): no memory\n"); 404 + return NULL; 405 + } 406 + 407 + en->addr = daddr; 408 + en->lastuse = jiffies; 409 + 410 + /* initilize its dest set */ 411 + atomic_set(&(en->set.size), 0); 412 + en->set.list = NULL; 413 + rwlock_init(&en->set.lock); 414 + 415 + ip_vs_lblcr_hash(tbl, en); 416 + } 417 + 418 + write_lock(&en->set.lock); 419 + ip_vs_dest_set_insert(&en->set, dest); 420 + write_unlock(&en->set.lock); 421 + 422 + return en; 373 423 } 374 424 375 425 ··· 394 418 int i; 395 419 struct ip_vs_lblcr_entry *en, *nxt; 396 420 421 + /* No locking required, only called during cleanup. */ 397 422 for (i=0; i<IP_VS_LBLCR_TAB_SIZE; i++) { 398 - write_lock(&tbl->lock); 399 423 list_for_each_entry_safe(en, nxt, &tbl->bucket[i], list) { 400 424 ip_vs_lblcr_free(en); 401 - atomic_dec(&tbl->entries); 402 425 } 403 - write_unlock(&tbl->lock); 404 426 } 405 427 } 406 428 407 429 408 - static inline void ip_vs_lblcr_full_check(struct ip_vs_lblcr_table *tbl) 430 + static inline void ip_vs_lblcr_full_check(struct ip_vs_service *svc) 409 431 { 432 + struct ip_vs_lblcr_table *tbl = svc->sched_data; 410 433 unsigned long now = jiffies; 411 434 int i, j; 412 435 struct ip_vs_lblcr_entry *en, *nxt; ··· 413 438 for (i=0, j=tbl->rover; i<IP_VS_LBLCR_TAB_SIZE; i++) { 414 439 j = (j + 1) & IP_VS_LBLCR_TAB_MASK; 415 440 416 - write_lock(&tbl->lock); 441 + write_lock(&svc->sched_lock); 417 442 list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) { 418 443 if (time_after(en->lastuse+sysctl_ip_vs_lblcr_expiration, 419 444 now)) ··· 422 447 ip_vs_lblcr_free(en); 423 448 atomic_dec(&tbl->entries); 424 449 } 425 - write_unlock(&tbl->lock); 450 + write_unlock(&svc->sched_lock); 426 451 } 427 452 tbl->rover = j; 428 453 } ··· 441 466 */ 442 467 static void ip_vs_lblcr_check_expire(unsigned long data) 443 468 { 444 - struct ip_vs_lblcr_table *tbl; 469 + struct ip_vs_service *svc = (struct ip_vs_service *) data; 470 + struct ip_vs_lblcr_table *tbl = svc->sched_data; 445 471 unsigned long now = jiffies; 446 472 int goal; 447 473 int i, j; 448 474 struct ip_vs_lblcr_entry *en, *nxt; 449 475 450 - tbl = (struct ip_vs_lblcr_table *)data; 451 - 452 476 if ((tbl->counter % COUNT_FOR_FULL_EXPIRATION) == 0) { 453 477 /* do full expiration check */ 454 - ip_vs_lblcr_full_check(tbl); 478 + ip_vs_lblcr_full_check(svc); 455 479 tbl->counter = 1; 456 480 goto out; 457 481 } ··· 467 493 for (i=0, j=tbl->rover; i<IP_VS_LBLCR_TAB_SIZE; i++) { 468 494 j = (j + 1) & IP_VS_LBLCR_TAB_MASK; 469 495 470 - write_lock(&tbl->lock); 496 + write_lock(&svc->sched_lock); 471 497 list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) { 472 498 if (time_before(now, en->lastuse+ENTRY_TIMEOUT)) 473 499 continue; ··· 476 502 atomic_dec(&tbl->entries); 477 503 goal--; 478 504 } 479 - write_unlock(&tbl->lock); 505 + write_unlock(&svc->sched_lock); 480 506 if (goal <= 0) 481 507 break; 482 508 } ··· 494 520 /* 495 521 * Allocate the ip_vs_lblcr_table for this service 496 522 */ 497 - tbl = kmalloc(sizeof(struct ip_vs_lblcr_table), GFP_ATOMIC); 523 + tbl = kmalloc(sizeof(*tbl), GFP_ATOMIC); 498 524 if (tbl == NULL) { 499 525 IP_VS_ERR("ip_vs_lblcr_init_svc(): no memory\n"); 500 526 return -ENOMEM; 501 527 } 502 528 svc->sched_data = tbl; 503 529 IP_VS_DBG(6, "LBLCR hash table (memory=%Zdbytes) allocated for " 504 - "current service\n", 505 - sizeof(struct ip_vs_lblcr_table)); 530 + "current service\n", sizeof(*tbl)); 506 531 507 532 /* 508 533 * Initialize the hash buckets ··· 509 536 for (i=0; i<IP_VS_LBLCR_TAB_SIZE; i++) { 510 537 INIT_LIST_HEAD(&tbl->bucket[i]); 511 538 } 512 - rwlock_init(&tbl->lock); 513 539 tbl->max_size = IP_VS_LBLCR_TAB_SIZE*16; 514 540 tbl->rover = 0; 515 541 tbl->counter = 1; ··· 517 545 * Hook periodic timer for garbage collection 518 546 */ 519 547 setup_timer(&tbl->periodic_timer, ip_vs_lblcr_check_expire, 520 - (unsigned long)tbl); 521 - tbl->periodic_timer.expires = jiffies+CHECK_EXPIRE_INTERVAL; 522 - add_timer(&tbl->periodic_timer); 548 + (unsigned long)svc); 549 + mod_timer(&tbl->periodic_timer, jiffies + CHECK_EXPIRE_INTERVAL); 523 550 524 551 return 0; 525 552 } ··· 535 564 ip_vs_lblcr_flush(tbl); 536 565 537 566 /* release the table itself */ 538 - kfree(svc->sched_data); 567 + kfree(tbl); 539 568 IP_VS_DBG(6, "LBLCR hash table (memory=%Zdbytes) released\n", 540 - sizeof(struct ip_vs_lblcr_table)); 569 + sizeof(*tbl)); 541 570 542 - return 0; 543 - } 544 - 545 - 546 - static int ip_vs_lblcr_update_svc(struct ip_vs_service *svc) 547 - { 548 571 return 0; 549 572 } 550 573 551 574 552 575 static inline struct ip_vs_dest * 553 - __ip_vs_wlc_schedule(struct ip_vs_service *svc, struct iphdr *iph) 576 + __ip_vs_lblcr_schedule(struct ip_vs_service *svc, struct iphdr *iph) 554 577 { 555 578 struct ip_vs_dest *dest, *least; 556 579 int loh, doh; ··· 634 669 static struct ip_vs_dest * 635 670 ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) 636 671 { 637 - struct ip_vs_dest *dest; 638 - struct ip_vs_lblcr_table *tbl; 639 - struct ip_vs_lblcr_entry *en; 672 + struct ip_vs_lblcr_table *tbl = svc->sched_data; 640 673 struct iphdr *iph = ip_hdr(skb); 674 + struct ip_vs_dest *dest = NULL; 675 + struct ip_vs_lblcr_entry *en; 641 676 642 677 IP_VS_DBG(6, "ip_vs_lblcr_schedule(): Scheduling...\n"); 643 678 644 - tbl = (struct ip_vs_lblcr_table *)svc->sched_data; 679 + /* First look in our cache */ 680 + read_lock(&svc->sched_lock); 645 681 en = ip_vs_lblcr_get(tbl, iph->daddr); 646 - if (en == NULL) { 647 - dest = __ip_vs_wlc_schedule(svc, iph); 648 - if (dest == NULL) { 649 - IP_VS_DBG(1, "no destination available\n"); 650 - return NULL; 651 - } 652 - en = ip_vs_lblcr_new(iph->daddr); 653 - if (en == NULL) { 654 - return NULL; 655 - } 656 - ip_vs_dest_set_insert(&en->set, dest); 657 - ip_vs_lblcr_hash(tbl, en); 658 - } else { 682 + if (en) { 683 + /* We only hold a read lock, but this is atomic */ 684 + en->lastuse = jiffies; 685 + 686 + /* Get the least loaded destination */ 687 + read_lock(&en->set.lock); 659 688 dest = ip_vs_dest_set_min(&en->set); 660 - if (!dest || is_overloaded(dest, svc)) { 661 - dest = __ip_vs_wlc_schedule(svc, iph); 662 - if (dest == NULL) { 663 - IP_VS_DBG(1, "no destination available\n"); 664 - return NULL; 665 - } 666 - ip_vs_dest_set_insert(&en->set, dest); 667 - } 689 + read_unlock(&en->set.lock); 690 + 691 + /* More than one destination + enough time passed by, cleanup */ 668 692 if (atomic_read(&en->set.size) > 1 && 669 - jiffies-en->set.lastmod > sysctl_ip_vs_lblcr_expiration) { 693 + time_after(jiffies, en->set.lastmod + 694 + sysctl_ip_vs_lblcr_expiration)) { 670 695 struct ip_vs_dest *m; 696 + 697 + write_lock(&en->set.lock); 671 698 m = ip_vs_dest_set_max(&en->set); 672 699 if (m) 673 700 ip_vs_dest_set_erase(&en->set, m); 701 + write_unlock(&en->set.lock); 674 702 } 675 - } 676 - en->lastuse = jiffies; 677 703 704 + /* If the destination is not overloaded, use it */ 705 + if (dest && !is_overloaded(dest, svc)) { 706 + read_unlock(&svc->sched_lock); 707 + goto out; 708 + } 709 + 710 + /* The cache entry is invalid, time to schedule */ 711 + dest = __ip_vs_lblcr_schedule(svc, iph); 712 + if (!dest) { 713 + IP_VS_DBG(1, "no destination available\n"); 714 + read_unlock(&svc->sched_lock); 715 + return NULL; 716 + } 717 + 718 + /* Update our cache entry */ 719 + write_lock(&en->set.lock); 720 + ip_vs_dest_set_insert(&en->set, dest); 721 + write_unlock(&en->set.lock); 722 + } 723 + read_unlock(&svc->sched_lock); 724 + 725 + if (dest) 726 + goto out; 727 + 728 + /* No cache entry, time to schedule */ 729 + dest = __ip_vs_lblcr_schedule(svc, iph); 730 + if (!dest) { 731 + IP_VS_DBG(1, "no destination available\n"); 732 + return NULL; 733 + } 734 + 735 + /* If we fail to create a cache entry, we'll just use the valid dest */ 736 + write_lock(&svc->sched_lock); 737 + ip_vs_lblcr_new(tbl, iph->daddr, dest); 738 + write_unlock(&svc->sched_lock); 739 + 740 + out: 678 741 IP_VS_DBG(6, "LBLCR: destination IP address %u.%u.%u.%u " 679 742 "--> server %u.%u.%u.%u:%d\n", 680 - NIPQUAD(en->addr), 743 + NIPQUAD(iph->daddr), 681 744 NIPQUAD(dest->addr), 682 745 ntohs(dest->port)); 683 746 ··· 724 731 .n_list = LIST_HEAD_INIT(ip_vs_lblcr_scheduler.n_list), 725 732 .init_service = ip_vs_lblcr_init_svc, 726 733 .done_service = ip_vs_lblcr_done_svc, 727 - .update_service = ip_vs_lblcr_update_svc, 728 734 .schedule = ip_vs_lblcr_schedule, 729 735 }; 730 736
-21
net/ipv4/ipvs/ip_vs_lc.c
··· 20 20 #include <net/ip_vs.h> 21 21 22 22 23 - static int ip_vs_lc_init_svc(struct ip_vs_service *svc) 24 - { 25 - return 0; 26 - } 27 - 28 - 29 - static int ip_vs_lc_done_svc(struct ip_vs_service *svc) 30 - { 31 - return 0; 32 - } 33 - 34 - 35 - static int ip_vs_lc_update_svc(struct ip_vs_service *svc) 36 - { 37 - return 0; 38 - } 39 - 40 - 41 23 static inline unsigned int 42 24 ip_vs_lc_dest_overhead(struct ip_vs_dest *dest) 43 25 { ··· 81 99 .refcnt = ATOMIC_INIT(0), 82 100 .module = THIS_MODULE, 83 101 .n_list = LIST_HEAD_INIT(ip_vs_lc_scheduler.n_list), 84 - .init_service = ip_vs_lc_init_svc, 85 - .done_service = ip_vs_lc_done_svc, 86 - .update_service = ip_vs_lc_update_svc, 87 102 .schedule = ip_vs_lc_schedule, 88 103 }; 89 104
-24
net/ipv4/ipvs/ip_vs_nq.c
··· 37 37 #include <net/ip_vs.h> 38 38 39 39 40 - static int 41 - ip_vs_nq_init_svc(struct ip_vs_service *svc) 42 - { 43 - return 0; 44 - } 45 - 46 - 47 - static int 48 - ip_vs_nq_done_svc(struct ip_vs_service *svc) 49 - { 50 - return 0; 51 - } 52 - 53 - 54 - static int 55 - ip_vs_nq_update_svc(struct ip_vs_service *svc) 56 - { 57 - return 0; 58 - } 59 - 60 - 61 40 static inline unsigned int 62 41 ip_vs_nq_dest_overhead(struct ip_vs_dest *dest) 63 42 { ··· 116 137 .refcnt = ATOMIC_INIT(0), 117 138 .module = THIS_MODULE, 118 139 .n_list = LIST_HEAD_INIT(ip_vs_nq_scheduler.n_list), 119 - .init_service = ip_vs_nq_init_svc, 120 - .done_service = ip_vs_nq_done_svc, 121 - .update_service = ip_vs_nq_update_svc, 122 140 .schedule = ip_vs_nq_schedule, 123 141 }; 124 142
-178
net/ipv4/ipvs/ip_vs_proto_ah.c
··· 1 - /* 2 - * ip_vs_proto_ah.c: AH IPSec load balancing support for IPVS 3 - * 4 - * Authors: Julian Anastasov <ja@ssi.bg>, February 2002 5 - * Wensong Zhang <wensong@linuxvirtualserver.org> 6 - * 7 - * This program is free software; you can redistribute it and/or 8 - * modify it under the terms of the GNU General Public License 9 - * version 2 as published by the Free Software Foundation; 10 - * 11 - */ 12 - 13 - #include <linux/in.h> 14 - #include <linux/ip.h> 15 - #include <linux/module.h> 16 - #include <linux/kernel.h> 17 - #include <linux/netfilter.h> 18 - #include <linux/netfilter_ipv4.h> 19 - 20 - #include <net/ip_vs.h> 21 - 22 - 23 - /* TODO: 24 - 25 - struct isakmp_hdr { 26 - __u8 icookie[8]; 27 - __u8 rcookie[8]; 28 - __u8 np; 29 - __u8 version; 30 - __u8 xchgtype; 31 - __u8 flags; 32 - __u32 msgid; 33 - __u32 length; 34 - }; 35 - 36 - */ 37 - 38 - #define PORT_ISAKMP 500 39 - 40 - 41 - static struct ip_vs_conn * 42 - ah_conn_in_get(const struct sk_buff *skb, 43 - struct ip_vs_protocol *pp, 44 - const struct iphdr *iph, 45 - unsigned int proto_off, 46 - int inverse) 47 - { 48 - struct ip_vs_conn *cp; 49 - 50 - if (likely(!inverse)) { 51 - cp = ip_vs_conn_in_get(IPPROTO_UDP, 52 - iph->saddr, 53 - htons(PORT_ISAKMP), 54 - iph->daddr, 55 - htons(PORT_ISAKMP)); 56 - } else { 57 - cp = ip_vs_conn_in_get(IPPROTO_UDP, 58 - iph->daddr, 59 - htons(PORT_ISAKMP), 60 - iph->saddr, 61 - htons(PORT_ISAKMP)); 62 - } 63 - 64 - if (!cp) { 65 - /* 66 - * We are not sure if the packet is from our 67 - * service, so our conn_schedule hook should return NF_ACCEPT 68 - */ 69 - IP_VS_DBG(12, "Unknown ISAKMP entry for outin packet " 70 - "%s%s %u.%u.%u.%u->%u.%u.%u.%u\n", 71 - inverse ? "ICMP+" : "", 72 - pp->name, 73 - NIPQUAD(iph->saddr), 74 - NIPQUAD(iph->daddr)); 75 - } 76 - 77 - return cp; 78 - } 79 - 80 - 81 - static struct ip_vs_conn * 82 - ah_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp, 83 - const struct iphdr *iph, unsigned int proto_off, int inverse) 84 - { 85 - struct ip_vs_conn *cp; 86 - 87 - if (likely(!inverse)) { 88 - cp = ip_vs_conn_out_get(IPPROTO_UDP, 89 - iph->saddr, 90 - htons(PORT_ISAKMP), 91 - iph->daddr, 92 - htons(PORT_ISAKMP)); 93 - } else { 94 - cp = ip_vs_conn_out_get(IPPROTO_UDP, 95 - iph->daddr, 96 - htons(PORT_ISAKMP), 97 - iph->saddr, 98 - htons(PORT_ISAKMP)); 99 - } 100 - 101 - if (!cp) { 102 - IP_VS_DBG(12, "Unknown ISAKMP entry for inout packet " 103 - "%s%s %u.%u.%u.%u->%u.%u.%u.%u\n", 104 - inverse ? "ICMP+" : "", 105 - pp->name, 106 - NIPQUAD(iph->saddr), 107 - NIPQUAD(iph->daddr)); 108 - } 109 - 110 - return cp; 111 - } 112 - 113 - 114 - static int 115 - ah_conn_schedule(struct sk_buff *skb, 116 - struct ip_vs_protocol *pp, 117 - int *verdict, struct ip_vs_conn **cpp) 118 - { 119 - /* 120 - * AH is only related traffic. Pass the packet to IP stack. 121 - */ 122 - *verdict = NF_ACCEPT; 123 - return 0; 124 - } 125 - 126 - 127 - static void 128 - ah_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb, 129 - int offset, const char *msg) 130 - { 131 - char buf[256]; 132 - struct iphdr _iph, *ih; 133 - 134 - ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph); 135 - if (ih == NULL) 136 - sprintf(buf, "%s TRUNCATED", pp->name); 137 - else 138 - sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u", 139 - pp->name, NIPQUAD(ih->saddr), 140 - NIPQUAD(ih->daddr)); 141 - 142 - printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf); 143 - } 144 - 145 - 146 - static void ah_init(struct ip_vs_protocol *pp) 147 - { 148 - /* nothing to do now */ 149 - } 150 - 151 - 152 - static void ah_exit(struct ip_vs_protocol *pp) 153 - { 154 - /* nothing to do now */ 155 - } 156 - 157 - 158 - struct ip_vs_protocol ip_vs_protocol_ah = { 159 - .name = "AH", 160 - .protocol = IPPROTO_AH, 161 - .num_states = 1, 162 - .dont_defrag = 1, 163 - .init = ah_init, 164 - .exit = ah_exit, 165 - .conn_schedule = ah_conn_schedule, 166 - .conn_in_get = ah_conn_in_get, 167 - .conn_out_get = ah_conn_out_get, 168 - .snat_handler = NULL, 169 - .dnat_handler = NULL, 170 - .csum_check = NULL, 171 - .state_transition = NULL, 172 - .register_app = NULL, 173 - .unregister_app = NULL, 174 - .app_conn_bind = NULL, 175 - .debug_packet = ah_debug_packet, 176 - .timeout_change = NULL, /* ISAKMP */ 177 - .set_state_timeout = NULL, 178 - };
+51 -24
net/ipv4/ipvs/ip_vs_proto_esp.c net/ipv4/ipvs/ip_vs_proto_ah_esp.c
··· 1 1 /* 2 - * ip_vs_proto_esp.c: ESP IPSec load balancing support for IPVS 2 + * ip_vs_proto_ah_esp.c: AH/ESP IPSec load balancing support for IPVS 3 3 * 4 4 * Authors: Julian Anastasov <ja@ssi.bg>, February 2002 5 5 * Wensong Zhang <wensong@linuxvirtualserver.org> ··· 39 39 40 40 41 41 static struct ip_vs_conn * 42 - esp_conn_in_get(const struct sk_buff *skb, 43 - struct ip_vs_protocol *pp, 44 - const struct iphdr *iph, 45 - unsigned int proto_off, 46 - int inverse) 42 + ah_esp_conn_in_get(const struct sk_buff *skb, 43 + struct ip_vs_protocol *pp, 44 + const struct iphdr *iph, 45 + unsigned int proto_off, 46 + int inverse) 47 47 { 48 48 struct ip_vs_conn *cp; 49 49 ··· 79 79 80 80 81 81 static struct ip_vs_conn * 82 - esp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp, 83 - const struct iphdr *iph, unsigned int proto_off, int inverse) 82 + ah_esp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp, 83 + const struct iphdr *iph, unsigned int proto_off, int inverse) 84 84 { 85 85 struct ip_vs_conn *cp; 86 86 ··· 112 112 113 113 114 114 static int 115 - esp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp, 116 - int *verdict, struct ip_vs_conn **cpp) 115 + ah_esp_conn_schedule(struct sk_buff *skb, 116 + struct ip_vs_protocol *pp, 117 + int *verdict, struct ip_vs_conn **cpp) 117 118 { 118 119 /* 119 - * ESP is only related traffic. Pass the packet to IP stack. 120 + * AH/ESP is only related traffic. Pass the packet to IP stack. 120 121 */ 121 122 *verdict = NF_ACCEPT; 122 123 return 0; ··· 125 124 126 125 127 126 static void 128 - esp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb, 129 - int offset, const char *msg) 127 + ah_esp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb, 128 + int offset, const char *msg) 130 129 { 131 130 char buf[256]; 132 131 struct iphdr _iph, *ih; ··· 143 142 } 144 143 145 144 146 - static void esp_init(struct ip_vs_protocol *pp) 145 + static void ah_esp_init(struct ip_vs_protocol *pp) 147 146 { 148 147 /* nothing to do now */ 149 148 } 150 149 151 150 152 - static void esp_exit(struct ip_vs_protocol *pp) 151 + static void ah_esp_exit(struct ip_vs_protocol *pp) 153 152 { 154 153 /* nothing to do now */ 155 154 } 156 155 157 156 158 - struct ip_vs_protocol ip_vs_protocol_esp = { 159 - .name = "ESP", 160 - .protocol = IPPROTO_ESP, 157 + #ifdef CONFIG_IP_VS_PROTO_AH 158 + struct ip_vs_protocol ip_vs_protocol_ah = { 159 + .name = "AH", 160 + .protocol = IPPROTO_AH, 161 161 .num_states = 1, 162 162 .dont_defrag = 1, 163 - .init = esp_init, 164 - .exit = esp_exit, 165 - .conn_schedule = esp_conn_schedule, 166 - .conn_in_get = esp_conn_in_get, 167 - .conn_out_get = esp_conn_out_get, 163 + .init = ah_esp_init, 164 + .exit = ah_esp_exit, 165 + .conn_schedule = ah_esp_conn_schedule, 166 + .conn_in_get = ah_esp_conn_in_get, 167 + .conn_out_get = ah_esp_conn_out_get, 168 168 .snat_handler = NULL, 169 169 .dnat_handler = NULL, 170 170 .csum_check = NULL, ··· 173 171 .register_app = NULL, 174 172 .unregister_app = NULL, 175 173 .app_conn_bind = NULL, 176 - .debug_packet = esp_debug_packet, 174 + .debug_packet = ah_esp_debug_packet, 175 + .timeout_change = NULL, /* ISAKMP */ 176 + .set_state_timeout = NULL, 177 + }; 178 + #endif 179 + 180 + #ifdef CONFIG_IP_VS_PROTO_ESP 181 + struct ip_vs_protocol ip_vs_protocol_esp = { 182 + .name = "ESP", 183 + .protocol = IPPROTO_ESP, 184 + .num_states = 1, 185 + .dont_defrag = 1, 186 + .init = ah_esp_init, 187 + .exit = ah_esp_exit, 188 + .conn_schedule = ah_esp_conn_schedule, 189 + .conn_in_get = ah_esp_conn_in_get, 190 + .conn_out_get = ah_esp_conn_out_get, 191 + .snat_handler = NULL, 192 + .dnat_handler = NULL, 193 + .csum_check = NULL, 194 + .state_transition = NULL, 195 + .register_app = NULL, 196 + .unregister_app = NULL, 197 + .app_conn_bind = NULL, 198 + .debug_packet = ah_esp_debug_packet, 177 199 .timeout_change = NULL, /* ISAKMP */ 178 200 }; 201 + #endif
-7
net/ipv4/ipvs/ip_vs_rr.c
··· 32 32 } 33 33 34 34 35 - static int ip_vs_rr_done_svc(struct ip_vs_service *svc) 36 - { 37 - return 0; 38 - } 39 - 40 - 41 35 static int ip_vs_rr_update_svc(struct ip_vs_service *svc) 42 36 { 43 37 svc->sched_data = &svc->destinations; ··· 90 96 .module = THIS_MODULE, 91 97 .n_list = LIST_HEAD_INIT(ip_vs_rr_scheduler.n_list), 92 98 .init_service = ip_vs_rr_init_svc, 93 - .done_service = ip_vs_rr_done_svc, 94 99 .update_service = ip_vs_rr_update_svc, 95 100 .schedule = ip_vs_rr_schedule, 96 101 };
-24
net/ipv4/ipvs/ip_vs_sed.c
··· 41 41 #include <net/ip_vs.h> 42 42 43 43 44 - static int 45 - ip_vs_sed_init_svc(struct ip_vs_service *svc) 46 - { 47 - return 0; 48 - } 49 - 50 - 51 - static int 52 - ip_vs_sed_done_svc(struct ip_vs_service *svc) 53 - { 54 - return 0; 55 - } 56 - 57 - 58 - static int 59 - ip_vs_sed_update_svc(struct ip_vs_service *svc) 60 - { 61 - return 0; 62 - } 63 - 64 - 65 44 static inline unsigned int 66 45 ip_vs_sed_dest_overhead(struct ip_vs_dest *dest) 67 46 { ··· 118 139 .refcnt = ATOMIC_INIT(0), 119 140 .module = THIS_MODULE, 120 141 .n_list = LIST_HEAD_INIT(ip_vs_sed_scheduler.n_list), 121 - .init_service = ip_vs_sed_init_svc, 122 - .done_service = ip_vs_sed_done_svc, 123 - .update_service = ip_vs_sed_update_svc, 124 142 .schedule = ip_vs_sed_schedule, 125 143 }; 126 144
-24
net/ipv4/ipvs/ip_vs_wlc.c
··· 25 25 #include <net/ip_vs.h> 26 26 27 27 28 - static int 29 - ip_vs_wlc_init_svc(struct ip_vs_service *svc) 30 - { 31 - return 0; 32 - } 33 - 34 - 35 - static int 36 - ip_vs_wlc_done_svc(struct ip_vs_service *svc) 37 - { 38 - return 0; 39 - } 40 - 41 - 42 - static int 43 - ip_vs_wlc_update_svc(struct ip_vs_service *svc) 44 - { 45 - return 0; 46 - } 47 - 48 - 49 28 static inline unsigned int 50 29 ip_vs_wlc_dest_overhead(struct ip_vs_dest *dest) 51 30 { ··· 106 127 .refcnt = ATOMIC_INIT(0), 107 128 .module = THIS_MODULE, 108 129 .n_list = LIST_HEAD_INIT(ip_vs_wlc_scheduler.n_list), 109 - .init_service = ip_vs_wlc_init_svc, 110 - .done_service = ip_vs_wlc_done_svc, 111 - .update_service = ip_vs_wlc_update_svc, 112 130 .schedule = ip_vs_wlc_schedule, 113 131 }; 114 132