aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ipvs/ip_vs_ctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/ipvs/ip_vs_ctl.c')
-rw-r--r--net/ipv4/ipvs/ip_vs_ctl.c896
1 files changed, 887 insertions, 9 deletions
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 6379705a8dcb..ede101eeec17 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -37,6 +37,7 @@
37#include <net/ip.h> 37#include <net/ip.h>
38#include <net/route.h> 38#include <net/route.h>
39#include <net/sock.h> 39#include <net/sock.h>
40#include <net/genetlink.h>
40 41
41#include <asm/uaccess.h> 42#include <asm/uaccess.h>
42 43
@@ -868,7 +869,8 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
868 svc->num_dests++; 869 svc->num_dests++;
869 870
870 /* call the update_service function of its scheduler */ 871 /* call the update_service function of its scheduler */
871 svc->scheduler->update_service(svc); 872 if (svc->scheduler->update_service)
873 svc->scheduler->update_service(svc);
872 874
873 write_unlock_bh(&__ip_vs_svc_lock); 875 write_unlock_bh(&__ip_vs_svc_lock);
874 return 0; 876 return 0;
@@ -898,7 +900,8 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
898 svc->num_dests++; 900 svc->num_dests++;
899 901
900 /* call the update_service function of its scheduler */ 902 /* call the update_service function of its scheduler */
901 svc->scheduler->update_service(svc); 903 if (svc->scheduler->update_service)
904 svc->scheduler->update_service(svc);
902 905
903 write_unlock_bh(&__ip_vs_svc_lock); 906 write_unlock_bh(&__ip_vs_svc_lock);
904 907
@@ -948,7 +951,8 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
948 IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1); 951 IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 1);
949 952
950 /* call the update_service, because server weight may be changed */ 953 /* call the update_service, because server weight may be changed */
951 svc->scheduler->update_service(svc); 954 if (svc->scheduler->update_service)
955 svc->scheduler->update_service(svc);
952 956
953 write_unlock_bh(&__ip_vs_svc_lock); 957 write_unlock_bh(&__ip_vs_svc_lock);
954 958
@@ -1011,12 +1015,12 @@ static void __ip_vs_unlink_dest(struct ip_vs_service *svc,
1011 */ 1015 */
1012 list_del(&dest->n_list); 1016 list_del(&dest->n_list);
1013 svc->num_dests--; 1017 svc->num_dests--;
1014 if (svcupd) { 1018
1015 /* 1019 /*
1016 * Call the update_service function of its scheduler 1020 * Call the update_service function of its scheduler
1017 */ 1021 */
1018 svc->scheduler->update_service(svc); 1022 if (svcupd && svc->scheduler->update_service)
1019 } 1023 svc->scheduler->update_service(svc);
1020} 1024}
1021 1025
1022 1026
@@ -2320,6 +2324,872 @@ static struct nf_sockopt_ops ip_vs_sockopts = {
2320 .owner = THIS_MODULE, 2324 .owner = THIS_MODULE,
2321}; 2325};
2322 2326
2327/*
2328 * Generic Netlink interface
2329 */
2330
2331/* IPVS genetlink family */
2332static struct genl_family ip_vs_genl_family = {
2333 .id = GENL_ID_GENERATE,
2334 .hdrsize = 0,
2335 .name = IPVS_GENL_NAME,
2336 .version = IPVS_GENL_VERSION,
2337 .maxattr = IPVS_CMD_MAX,
2338};
2339
2340/* Policy used for first-level command attributes */
2341static const struct nla_policy ip_vs_cmd_policy[IPVS_CMD_ATTR_MAX + 1] = {
2342 [IPVS_CMD_ATTR_SERVICE] = { .type = NLA_NESTED },
2343 [IPVS_CMD_ATTR_DEST] = { .type = NLA_NESTED },
2344 [IPVS_CMD_ATTR_DAEMON] = { .type = NLA_NESTED },
2345 [IPVS_CMD_ATTR_TIMEOUT_TCP] = { .type = NLA_U32 },
2346 [IPVS_CMD_ATTR_TIMEOUT_TCP_FIN] = { .type = NLA_U32 },
2347 [IPVS_CMD_ATTR_TIMEOUT_UDP] = { .type = NLA_U32 },
2348};
2349
2350/* Policy used for attributes in nested attribute IPVS_CMD_ATTR_DAEMON */
2351static const struct nla_policy ip_vs_daemon_policy[IPVS_DAEMON_ATTR_MAX + 1] = {
2352 [IPVS_DAEMON_ATTR_STATE] = { .type = NLA_U32 },
2353 [IPVS_DAEMON_ATTR_MCAST_IFN] = { .type = NLA_NUL_STRING,
2354 .len = IP_VS_IFNAME_MAXLEN },
2355 [IPVS_DAEMON_ATTR_SYNC_ID] = { .type = NLA_U32 },
2356};
2357
2358/* Policy used for attributes in nested attribute IPVS_CMD_ATTR_SERVICE */
2359static const struct nla_policy ip_vs_svc_policy[IPVS_SVC_ATTR_MAX + 1] = {
2360 [IPVS_SVC_ATTR_AF] = { .type = NLA_U16 },
2361 [IPVS_SVC_ATTR_PROTOCOL] = { .type = NLA_U16 },
2362 [IPVS_SVC_ATTR_ADDR] = { .type = NLA_BINARY,
2363 .len = sizeof(union nf_inet_addr) },
2364 [IPVS_SVC_ATTR_PORT] = { .type = NLA_U16 },
2365 [IPVS_SVC_ATTR_FWMARK] = { .type = NLA_U32 },
2366 [IPVS_SVC_ATTR_SCHED_NAME] = { .type = NLA_NUL_STRING,
2367 .len = IP_VS_SCHEDNAME_MAXLEN },
2368 [IPVS_SVC_ATTR_FLAGS] = { .type = NLA_BINARY,
2369 .len = sizeof(struct ip_vs_flags) },
2370 [IPVS_SVC_ATTR_TIMEOUT] = { .type = NLA_U32 },
2371 [IPVS_SVC_ATTR_NETMASK] = { .type = NLA_U32 },
2372 [IPVS_SVC_ATTR_STATS] = { .type = NLA_NESTED },
2373};
2374
2375/* Policy used for attributes in nested attribute IPVS_CMD_ATTR_DEST */
2376static const struct nla_policy ip_vs_dest_policy[IPVS_DEST_ATTR_MAX + 1] = {
2377 [IPVS_DEST_ATTR_ADDR] = { .type = NLA_BINARY,
2378 .len = sizeof(union nf_inet_addr) },
2379 [IPVS_DEST_ATTR_PORT] = { .type = NLA_U16 },
2380 [IPVS_DEST_ATTR_FWD_METHOD] = { .type = NLA_U32 },
2381 [IPVS_DEST_ATTR_WEIGHT] = { .type = NLA_U32 },
2382 [IPVS_DEST_ATTR_U_THRESH] = { .type = NLA_U32 },
2383 [IPVS_DEST_ATTR_L_THRESH] = { .type = NLA_U32 },
2384 [IPVS_DEST_ATTR_ACTIVE_CONNS] = { .type = NLA_U32 },
2385 [IPVS_DEST_ATTR_INACT_CONNS] = { .type = NLA_U32 },
2386 [IPVS_DEST_ATTR_PERSIST_CONNS] = { .type = NLA_U32 },
2387 [IPVS_DEST_ATTR_STATS] = { .type = NLA_NESTED },
2388};
2389
2390static int ip_vs_genl_fill_stats(struct sk_buff *skb, int container_type,
2391 struct ip_vs_stats *stats)
2392{
2393 struct nlattr *nl_stats = nla_nest_start(skb, container_type);
2394 if (!nl_stats)
2395 return -EMSGSIZE;
2396
2397 spin_lock_bh(&stats->lock);
2398
2399 NLA_PUT_U32(skb, IPVS_STATS_ATTR_CONNS, stats->conns);
2400 NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPKTS, stats->inpkts);
2401 NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPKTS, stats->outpkts);
2402 NLA_PUT_U64(skb, IPVS_STATS_ATTR_INBYTES, stats->inbytes);
2403 NLA_PUT_U64(skb, IPVS_STATS_ATTR_OUTBYTES, stats->outbytes);
2404 NLA_PUT_U32(skb, IPVS_STATS_ATTR_CPS, stats->cps);
2405 NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPPS, stats->inpps);
2406 NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPPS, stats->outpps);
2407 NLA_PUT_U32(skb, IPVS_STATS_ATTR_INBPS, stats->inbps);
2408 NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTBPS, stats->outbps);
2409
2410 spin_unlock_bh(&stats->lock);
2411
2412 nla_nest_end(skb, nl_stats);
2413
2414 return 0;
2415
2416nla_put_failure:
2417 spin_unlock_bh(&stats->lock);
2418 nla_nest_cancel(skb, nl_stats);
2419 return -EMSGSIZE;
2420}
2421
2422static int ip_vs_genl_fill_service(struct sk_buff *skb,
2423 struct ip_vs_service *svc)
2424{
2425 struct nlattr *nl_service;
2426 struct ip_vs_flags flags = { .flags = svc->flags,
2427 .mask = ~0 };
2428
2429 nl_service = nla_nest_start(skb, IPVS_CMD_ATTR_SERVICE);
2430 if (!nl_service)
2431 return -EMSGSIZE;
2432
2433 NLA_PUT_U16(skb, IPVS_SVC_ATTR_AF, AF_INET);
2434
2435 if (svc->fwmark) {
2436 NLA_PUT_U32(skb, IPVS_SVC_ATTR_FWMARK, svc->fwmark);
2437 } else {
2438 NLA_PUT_U16(skb, IPVS_SVC_ATTR_PROTOCOL, svc->protocol);
2439 NLA_PUT(skb, IPVS_SVC_ATTR_ADDR, sizeof(svc->addr), &svc->addr);
2440 NLA_PUT_U16(skb, IPVS_SVC_ATTR_PORT, svc->port);
2441 }
2442
2443 NLA_PUT_STRING(skb, IPVS_SVC_ATTR_SCHED_NAME, svc->scheduler->name);
2444 NLA_PUT(skb, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags);
2445 NLA_PUT_U32(skb, IPVS_SVC_ATTR_TIMEOUT, svc->timeout / HZ);
2446 NLA_PUT_U32(skb, IPVS_SVC_ATTR_NETMASK, svc->netmask);
2447
2448 if (ip_vs_genl_fill_stats(skb, IPVS_SVC_ATTR_STATS, &svc->stats))
2449 goto nla_put_failure;
2450
2451 nla_nest_end(skb, nl_service);
2452
2453 return 0;
2454
2455nla_put_failure:
2456 nla_nest_cancel(skb, nl_service);
2457 return -EMSGSIZE;
2458}
2459
2460static int ip_vs_genl_dump_service(struct sk_buff *skb,
2461 struct ip_vs_service *svc,
2462 struct netlink_callback *cb)
2463{
2464 void *hdr;
2465
2466 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
2467 &ip_vs_genl_family, NLM_F_MULTI,
2468 IPVS_CMD_NEW_SERVICE);
2469 if (!hdr)
2470 return -EMSGSIZE;
2471
2472 if (ip_vs_genl_fill_service(skb, svc) < 0)
2473 goto nla_put_failure;
2474
2475 return genlmsg_end(skb, hdr);
2476
2477nla_put_failure:
2478 genlmsg_cancel(skb, hdr);
2479 return -EMSGSIZE;
2480}
2481
2482static int ip_vs_genl_dump_services(struct sk_buff *skb,
2483 struct netlink_callback *cb)
2484{
2485 int idx = 0, i;
2486 int start = cb->args[0];
2487 struct ip_vs_service *svc;
2488
2489 mutex_lock(&__ip_vs_mutex);
2490 for (i = 0; i < IP_VS_SVC_TAB_SIZE; i++) {
2491 list_for_each_entry(svc, &ip_vs_svc_table[i], s_list) {
2492 if (++idx <= start)
2493 continue;
2494 if (ip_vs_genl_dump_service(skb, svc, cb) < 0) {
2495 idx--;
2496 goto nla_put_failure;
2497 }
2498 }
2499 }
2500
2501 for (i = 0; i < IP_VS_SVC_TAB_SIZE; i++) {
2502 list_for_each_entry(svc, &ip_vs_svc_fwm_table[i], f_list) {
2503 if (++idx <= start)
2504 continue;
2505 if (ip_vs_genl_dump_service(skb, svc, cb) < 0) {
2506 idx--;
2507 goto nla_put_failure;
2508 }
2509 }
2510 }
2511
2512nla_put_failure:
2513 mutex_unlock(&__ip_vs_mutex);
2514 cb->args[0] = idx;
2515
2516 return skb->len;
2517}
2518
2519static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc,
2520 struct nlattr *nla, int full_entry)
2521{
2522 struct nlattr *attrs[IPVS_SVC_ATTR_MAX + 1];
2523 struct nlattr *nla_af, *nla_port, *nla_fwmark, *nla_protocol, *nla_addr;
2524
2525 /* Parse mandatory identifying service fields first */
2526 if (nla == NULL ||
2527 nla_parse_nested(attrs, IPVS_SVC_ATTR_MAX, nla, ip_vs_svc_policy))
2528 return -EINVAL;
2529
2530 nla_af = attrs[IPVS_SVC_ATTR_AF];
2531 nla_protocol = attrs[IPVS_SVC_ATTR_PROTOCOL];
2532 nla_addr = attrs[IPVS_SVC_ATTR_ADDR];
2533 nla_port = attrs[IPVS_SVC_ATTR_PORT];
2534 nla_fwmark = attrs[IPVS_SVC_ATTR_FWMARK];
2535
2536 if (!(nla_af && (nla_fwmark || (nla_port && nla_protocol && nla_addr))))
2537 return -EINVAL;
2538
2539 /* For now, only support IPv4 */
2540 if (nla_get_u16(nla_af) != AF_INET)
2541 return -EAFNOSUPPORT;
2542
2543 if (nla_fwmark) {
2544 usvc->protocol = IPPROTO_TCP;
2545 usvc->fwmark = nla_get_u32(nla_fwmark);
2546 } else {
2547 usvc->protocol = nla_get_u16(nla_protocol);
2548 nla_memcpy(&usvc->addr, nla_addr, sizeof(usvc->addr));
2549 usvc->port = nla_get_u16(nla_port);
2550 usvc->fwmark = 0;
2551 }
2552
2553 /* If a full entry was requested, check for the additional fields */
2554 if (full_entry) {
2555 struct nlattr *nla_sched, *nla_flags, *nla_timeout,
2556 *nla_netmask;
2557 struct ip_vs_flags flags;
2558 struct ip_vs_service *svc;
2559
2560 nla_sched = attrs[IPVS_SVC_ATTR_SCHED_NAME];
2561 nla_flags = attrs[IPVS_SVC_ATTR_FLAGS];
2562 nla_timeout = attrs[IPVS_SVC_ATTR_TIMEOUT];
2563 nla_netmask = attrs[IPVS_SVC_ATTR_NETMASK];
2564
2565 if (!(nla_sched && nla_flags && nla_timeout && nla_netmask))
2566 return -EINVAL;
2567
2568 nla_memcpy(&flags, nla_flags, sizeof(flags));
2569
2570 /* prefill flags from service if it already exists */
2571 if (usvc->fwmark)
2572 svc = __ip_vs_svc_fwm_get(usvc->fwmark);
2573 else
2574 svc = __ip_vs_service_get(usvc->protocol, usvc->addr,
2575 usvc->port);
2576 if (svc) {
2577 usvc->flags = svc->flags;
2578 ip_vs_service_put(svc);
2579 } else
2580 usvc->flags = 0;
2581
2582 /* set new flags from userland */
2583 usvc->flags = (usvc->flags & ~flags.mask) |
2584 (flags.flags & flags.mask);
2585
2586 strlcpy(usvc->sched_name, nla_data(nla_sched),
2587 sizeof(usvc->sched_name));
2588 usvc->timeout = nla_get_u32(nla_timeout);
2589 usvc->netmask = nla_get_u32(nla_netmask);
2590 }
2591
2592 return 0;
2593}
2594
2595static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla)
2596{
2597 struct ip_vs_service_user usvc;
2598 int ret;
2599
2600 ret = ip_vs_genl_parse_service(&usvc, nla, 0);
2601 if (ret)
2602 return ERR_PTR(ret);
2603
2604 if (usvc.fwmark)
2605 return __ip_vs_svc_fwm_get(usvc.fwmark);
2606 else
2607 return __ip_vs_service_get(usvc.protocol, usvc.addr,
2608 usvc.port);
2609}
2610
2611static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest)
2612{
2613 struct nlattr *nl_dest;
2614
2615 nl_dest = nla_nest_start(skb, IPVS_CMD_ATTR_DEST);
2616 if (!nl_dest)
2617 return -EMSGSIZE;
2618
2619 NLA_PUT(skb, IPVS_DEST_ATTR_ADDR, sizeof(dest->addr), &dest->addr);
2620 NLA_PUT_U16(skb, IPVS_DEST_ATTR_PORT, dest->port);
2621
2622 NLA_PUT_U32(skb, IPVS_DEST_ATTR_FWD_METHOD,
2623 atomic_read(&dest->conn_flags) & IP_VS_CONN_F_FWD_MASK);
2624 NLA_PUT_U32(skb, IPVS_DEST_ATTR_WEIGHT, atomic_read(&dest->weight));
2625 NLA_PUT_U32(skb, IPVS_DEST_ATTR_U_THRESH, dest->u_threshold);
2626 NLA_PUT_U32(skb, IPVS_DEST_ATTR_L_THRESH, dest->l_threshold);
2627 NLA_PUT_U32(skb, IPVS_DEST_ATTR_ACTIVE_CONNS,
2628 atomic_read(&dest->activeconns));
2629 NLA_PUT_U32(skb, IPVS_DEST_ATTR_INACT_CONNS,
2630 atomic_read(&dest->inactconns));
2631 NLA_PUT_U32(skb, IPVS_DEST_ATTR_PERSIST_CONNS,
2632 atomic_read(&dest->persistconns));
2633
2634 if (ip_vs_genl_fill_stats(skb, IPVS_DEST_ATTR_STATS, &dest->stats))
2635 goto nla_put_failure;
2636
2637 nla_nest_end(skb, nl_dest);
2638
2639 return 0;
2640
2641nla_put_failure:
2642 nla_nest_cancel(skb, nl_dest);
2643 return -EMSGSIZE;
2644}
2645
2646static int ip_vs_genl_dump_dest(struct sk_buff *skb, struct ip_vs_dest *dest,
2647 struct netlink_callback *cb)
2648{
2649 void *hdr;
2650
2651 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
2652 &ip_vs_genl_family, NLM_F_MULTI,
2653 IPVS_CMD_NEW_DEST);
2654 if (!hdr)
2655 return -EMSGSIZE;
2656
2657 if (ip_vs_genl_fill_dest(skb, dest) < 0)
2658 goto nla_put_failure;
2659
2660 return genlmsg_end(skb, hdr);
2661
2662nla_put_failure:
2663 genlmsg_cancel(skb, hdr);
2664 return -EMSGSIZE;
2665}
2666
2667static int ip_vs_genl_dump_dests(struct sk_buff *skb,
2668 struct netlink_callback *cb)
2669{
2670 int idx = 0;
2671 int start = cb->args[0];
2672 struct ip_vs_service *svc;
2673 struct ip_vs_dest *dest;
2674 struct nlattr *attrs[IPVS_CMD_ATTR_MAX + 1];
2675
2676 mutex_lock(&__ip_vs_mutex);
2677
2678 /* Try to find the service for which to dump destinations */
2679 if (nlmsg_parse(cb->nlh, GENL_HDRLEN, attrs,
2680 IPVS_CMD_ATTR_MAX, ip_vs_cmd_policy))
2681 goto out_err;
2682
2683 svc = ip_vs_genl_find_service(attrs[IPVS_CMD_ATTR_SERVICE]);
2684 if (IS_ERR(svc) || svc == NULL)
2685 goto out_err;
2686
2687 /* Dump the destinations */
2688 list_for_each_entry(dest, &svc->destinations, n_list) {
2689 if (++idx <= start)
2690 continue;
2691 if (ip_vs_genl_dump_dest(skb, dest, cb) < 0) {
2692 idx--;
2693 goto nla_put_failure;
2694 }
2695 }
2696
2697nla_put_failure:
2698 cb->args[0] = idx;
2699 ip_vs_service_put(svc);
2700
2701out_err:
2702 mutex_unlock(&__ip_vs_mutex);
2703
2704 return skb->len;
2705}
2706
2707static int ip_vs_genl_parse_dest(struct ip_vs_dest_user *udest,
2708 struct nlattr *nla, int full_entry)
2709{
2710 struct nlattr *attrs[IPVS_DEST_ATTR_MAX + 1];
2711 struct nlattr *nla_addr, *nla_port;
2712
2713 /* Parse mandatory identifying destination fields first */
2714 if (nla == NULL ||
2715 nla_parse_nested(attrs, IPVS_DEST_ATTR_MAX, nla, ip_vs_dest_policy))
2716 return -EINVAL;
2717
2718 nla_addr = attrs[IPVS_DEST_ATTR_ADDR];
2719 nla_port = attrs[IPVS_DEST_ATTR_PORT];
2720
2721 if (!(nla_addr && nla_port))
2722 return -EINVAL;
2723
2724 nla_memcpy(&udest->addr, nla_addr, sizeof(udest->addr));
2725 udest->port = nla_get_u16(nla_port);
2726
2727 /* If a full entry was requested, check for the additional fields */
2728 if (full_entry) {
2729 struct nlattr *nla_fwd, *nla_weight, *nla_u_thresh,
2730 *nla_l_thresh;
2731
2732 nla_fwd = attrs[IPVS_DEST_ATTR_FWD_METHOD];
2733 nla_weight = attrs[IPVS_DEST_ATTR_WEIGHT];
2734 nla_u_thresh = attrs[IPVS_DEST_ATTR_U_THRESH];
2735 nla_l_thresh = attrs[IPVS_DEST_ATTR_L_THRESH];
2736
2737 if (!(nla_fwd && nla_weight && nla_u_thresh && nla_l_thresh))
2738 return -EINVAL;
2739
2740 udest->conn_flags = nla_get_u32(nla_fwd)
2741 & IP_VS_CONN_F_FWD_MASK;
2742 udest->weight = nla_get_u32(nla_weight);
2743 udest->u_threshold = nla_get_u32(nla_u_thresh);
2744 udest->l_threshold = nla_get_u32(nla_l_thresh);
2745 }
2746
2747 return 0;
2748}
2749
2750static int ip_vs_genl_fill_daemon(struct sk_buff *skb, __be32 state,
2751 const char *mcast_ifn, __be32 syncid)
2752{
2753 struct nlattr *nl_daemon;
2754
2755 nl_daemon = nla_nest_start(skb, IPVS_CMD_ATTR_DAEMON);
2756 if (!nl_daemon)
2757 return -EMSGSIZE;
2758
2759 NLA_PUT_U32(skb, IPVS_DAEMON_ATTR_STATE, state);
2760 NLA_PUT_STRING(skb, IPVS_DAEMON_ATTR_MCAST_IFN, mcast_ifn);
2761 NLA_PUT_U32(skb, IPVS_DAEMON_ATTR_SYNC_ID, syncid);
2762
2763 nla_nest_end(skb, nl_daemon);
2764
2765 return 0;
2766
2767nla_put_failure:
2768 nla_nest_cancel(skb, nl_daemon);
2769 return -EMSGSIZE;
2770}
2771
2772static int ip_vs_genl_dump_daemon(struct sk_buff *skb, __be32 state,
2773 const char *mcast_ifn, __be32 syncid,
2774 struct netlink_callback *cb)
2775{
2776 void *hdr;
2777 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
2778 &ip_vs_genl_family, NLM_F_MULTI,
2779 IPVS_CMD_NEW_DAEMON);
2780 if (!hdr)
2781 return -EMSGSIZE;
2782
2783 if (ip_vs_genl_fill_daemon(skb, state, mcast_ifn, syncid))
2784 goto nla_put_failure;
2785
2786 return genlmsg_end(skb, hdr);
2787
2788nla_put_failure:
2789 genlmsg_cancel(skb, hdr);
2790 return -EMSGSIZE;
2791}
2792
2793static int ip_vs_genl_dump_daemons(struct sk_buff *skb,
2794 struct netlink_callback *cb)
2795{
2796 mutex_lock(&__ip_vs_mutex);
2797 if ((ip_vs_sync_state & IP_VS_STATE_MASTER) && !cb->args[0]) {
2798 if (ip_vs_genl_dump_daemon(skb, IP_VS_STATE_MASTER,
2799 ip_vs_master_mcast_ifn,
2800 ip_vs_master_syncid, cb) < 0)
2801 goto nla_put_failure;
2802
2803 cb->args[0] = 1;
2804 }
2805
2806 if ((ip_vs_sync_state & IP_VS_STATE_BACKUP) && !cb->args[1]) {
2807 if (ip_vs_genl_dump_daemon(skb, IP_VS_STATE_BACKUP,
2808 ip_vs_backup_mcast_ifn,
2809 ip_vs_backup_syncid, cb) < 0)
2810 goto nla_put_failure;
2811
2812 cb->args[1] = 1;
2813 }
2814
2815nla_put_failure:
2816 mutex_unlock(&__ip_vs_mutex);
2817
2818 return skb->len;
2819}
2820
2821static int ip_vs_genl_new_daemon(struct nlattr **attrs)
2822{
2823 if (!(attrs[IPVS_DAEMON_ATTR_STATE] &&
2824 attrs[IPVS_DAEMON_ATTR_MCAST_IFN] &&
2825 attrs[IPVS_DAEMON_ATTR_SYNC_ID]))
2826 return -EINVAL;
2827
2828 return start_sync_thread(nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]),
2829 nla_data(attrs[IPVS_DAEMON_ATTR_MCAST_IFN]),
2830 nla_get_u32(attrs[IPVS_DAEMON_ATTR_SYNC_ID]));
2831}
2832
2833static int ip_vs_genl_del_daemon(struct nlattr **attrs)
2834{
2835 if (!attrs[IPVS_DAEMON_ATTR_STATE])
2836 return -EINVAL;
2837
2838 return stop_sync_thread(nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]));
2839}
2840
2841static int ip_vs_genl_set_config(struct nlattr **attrs)
2842{
2843 struct ip_vs_timeout_user t;
2844
2845 __ip_vs_get_timeouts(&t);
2846
2847 if (attrs[IPVS_CMD_ATTR_TIMEOUT_TCP])
2848 t.tcp_timeout = nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_TCP]);
2849
2850 if (attrs[IPVS_CMD_ATTR_TIMEOUT_TCP_FIN])
2851 t.tcp_fin_timeout =
2852 nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_TCP_FIN]);
2853
2854 if (attrs[IPVS_CMD_ATTR_TIMEOUT_UDP])
2855 t.udp_timeout = nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_UDP]);
2856
2857 return ip_vs_set_timeout(&t);
2858}
2859
2860static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
2861{
2862 struct ip_vs_service *svc = NULL;
2863 struct ip_vs_service_user usvc;
2864 struct ip_vs_dest_user udest;
2865 int ret = 0, cmd;
2866 int need_full_svc = 0, need_full_dest = 0;
2867
2868 cmd = info->genlhdr->cmd;
2869
2870 mutex_lock(&__ip_vs_mutex);
2871
2872 if (cmd == IPVS_CMD_FLUSH) {
2873 ret = ip_vs_flush();
2874 goto out;
2875 } else if (cmd == IPVS_CMD_SET_CONFIG) {
2876 ret = ip_vs_genl_set_config(info->attrs);
2877 goto out;
2878 } else if (cmd == IPVS_CMD_NEW_DAEMON ||
2879 cmd == IPVS_CMD_DEL_DAEMON) {
2880
2881 struct nlattr *daemon_attrs[IPVS_DAEMON_ATTR_MAX + 1];
2882
2883 if (!info->attrs[IPVS_CMD_ATTR_DAEMON] ||
2884 nla_parse_nested(daemon_attrs, IPVS_DAEMON_ATTR_MAX,
2885 info->attrs[IPVS_CMD_ATTR_DAEMON],
2886 ip_vs_daemon_policy)) {
2887 ret = -EINVAL;
2888 goto out;
2889 }
2890
2891 if (cmd == IPVS_CMD_NEW_DAEMON)
2892 ret = ip_vs_genl_new_daemon(daemon_attrs);
2893 else
2894 ret = ip_vs_genl_del_daemon(daemon_attrs);
2895 goto out;
2896 } else if (cmd == IPVS_CMD_ZERO &&
2897 !info->attrs[IPVS_CMD_ATTR_SERVICE]) {
2898 ret = ip_vs_zero_all();
2899 goto out;
2900 }
2901
2902 /* All following commands require a service argument, so check if we
2903 * received a valid one. We need a full service specification when
2904 * adding / editing a service. Only identifying members otherwise. */
2905 if (cmd == IPVS_CMD_NEW_SERVICE || cmd == IPVS_CMD_SET_SERVICE)
2906 need_full_svc = 1;
2907
2908 ret = ip_vs_genl_parse_service(&usvc,
2909 info->attrs[IPVS_CMD_ATTR_SERVICE],
2910 need_full_svc);
2911 if (ret)
2912 goto out;
2913
2914 /* Lookup the exact service by <protocol, addr, port> or fwmark */
2915 if (usvc.fwmark == 0)
2916 svc = __ip_vs_service_get(usvc.protocol, usvc.addr, usvc.port);
2917 else
2918 svc = __ip_vs_svc_fwm_get(usvc.fwmark);
2919
2920 /* Unless we're adding a new service, the service must already exist */
2921 if ((cmd != IPVS_CMD_NEW_SERVICE) && (svc == NULL)) {
2922 ret = -ESRCH;
2923 goto out;
2924 }
2925
2926 /* Destination commands require a valid destination argument. For
2927 * adding / editing a destination, we need a full destination
2928 * specification. */
2929 if (cmd == IPVS_CMD_NEW_DEST || cmd == IPVS_CMD_SET_DEST ||
2930 cmd == IPVS_CMD_DEL_DEST) {
2931 if (cmd != IPVS_CMD_DEL_DEST)
2932 need_full_dest = 1;
2933
2934 ret = ip_vs_genl_parse_dest(&udest,
2935 info->attrs[IPVS_CMD_ATTR_DEST],
2936 need_full_dest);
2937 if (ret)
2938 goto out;
2939 }
2940
2941 switch (cmd) {
2942 case IPVS_CMD_NEW_SERVICE:
2943 if (svc == NULL)
2944 ret = ip_vs_add_service(&usvc, &svc);
2945 else
2946 ret = -EEXIST;
2947 break;
2948 case IPVS_CMD_SET_SERVICE:
2949 ret = ip_vs_edit_service(svc, &usvc);
2950 break;
2951 case IPVS_CMD_DEL_SERVICE:
2952 ret = ip_vs_del_service(svc);
2953 break;
2954 case IPVS_CMD_NEW_DEST:
2955 ret = ip_vs_add_dest(svc, &udest);
2956 break;
2957 case IPVS_CMD_SET_DEST:
2958 ret = ip_vs_edit_dest(svc, &udest);
2959 break;
2960 case IPVS_CMD_DEL_DEST:
2961 ret = ip_vs_del_dest(svc, &udest);
2962 break;
2963 case IPVS_CMD_ZERO:
2964 ret = ip_vs_zero_service(svc);
2965 break;
2966 default:
2967 ret = -EINVAL;
2968 }
2969
2970out:
2971 if (svc)
2972 ip_vs_service_put(svc);
2973 mutex_unlock(&__ip_vs_mutex);
2974
2975 return ret;
2976}
2977
2978static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info)
2979{
2980 struct sk_buff *msg;
2981 void *reply;
2982 int ret, cmd, reply_cmd;
2983
2984 cmd = info->genlhdr->cmd;
2985
2986 if (cmd == IPVS_CMD_GET_SERVICE)
2987 reply_cmd = IPVS_CMD_NEW_SERVICE;
2988 else if (cmd == IPVS_CMD_GET_INFO)
2989 reply_cmd = IPVS_CMD_SET_INFO;
2990 else if (cmd == IPVS_CMD_GET_CONFIG)
2991 reply_cmd = IPVS_CMD_SET_CONFIG;
2992 else {
2993 IP_VS_ERR("unknown Generic Netlink command\n");
2994 return -EINVAL;
2995 }
2996
2997 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2998 if (!msg)
2999 return -ENOMEM;
3000
3001 mutex_lock(&__ip_vs_mutex);
3002
3003 reply = genlmsg_put_reply(msg, info, &ip_vs_genl_family, 0, reply_cmd);
3004 if (reply == NULL)
3005 goto nla_put_failure;
3006
3007 switch (cmd) {
3008 case IPVS_CMD_GET_SERVICE:
3009 {
3010 struct ip_vs_service *svc;
3011
3012 svc = ip_vs_genl_find_service(info->attrs[IPVS_CMD_ATTR_SERVICE]);
3013 if (IS_ERR(svc)) {
3014 ret = PTR_ERR(svc);
3015 goto out_err;
3016 } else if (svc) {
3017 ret = ip_vs_genl_fill_service(msg, svc);
3018 ip_vs_service_put(svc);
3019 if (ret)
3020 goto nla_put_failure;
3021 } else {
3022 ret = -ESRCH;
3023 goto out_err;
3024 }
3025
3026 break;
3027 }
3028
3029 case IPVS_CMD_GET_CONFIG:
3030 {
3031 struct ip_vs_timeout_user t;
3032
3033 __ip_vs_get_timeouts(&t);
3034#ifdef CONFIG_IP_VS_PROTO_TCP
3035 NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP, t.tcp_timeout);
3036 NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP_FIN,
3037 t.tcp_fin_timeout);
3038#endif
3039#ifdef CONFIG_IP_VS_PROTO_UDP
3040 NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_UDP, t.udp_timeout);
3041#endif
3042
3043 break;
3044 }
3045
3046 case IPVS_CMD_GET_INFO:
3047 NLA_PUT_U32(msg, IPVS_INFO_ATTR_VERSION, IP_VS_VERSION_CODE);
3048 NLA_PUT_U32(msg, IPVS_INFO_ATTR_CONN_TAB_SIZE,
3049 IP_VS_CONN_TAB_SIZE);
3050 break;
3051 }
3052
3053 genlmsg_end(msg, reply);
3054 ret = genlmsg_unicast(msg, info->snd_pid);
3055 goto out;
3056
3057nla_put_failure:
3058 IP_VS_ERR("not enough space in Netlink message\n");
3059 ret = -EMSGSIZE;
3060
3061out_err:
3062 nlmsg_free(msg);
3063out:
3064 mutex_unlock(&__ip_vs_mutex);
3065
3066 return ret;
3067}
3068
3069
3070static struct genl_ops ip_vs_genl_ops[] __read_mostly = {
3071 {
3072 .cmd = IPVS_CMD_NEW_SERVICE,
3073 .flags = GENL_ADMIN_PERM,
3074 .policy = ip_vs_cmd_policy,
3075 .doit = ip_vs_genl_set_cmd,
3076 },
3077 {
3078 .cmd = IPVS_CMD_SET_SERVICE,
3079 .flags = GENL_ADMIN_PERM,
3080 .policy = ip_vs_cmd_policy,
3081 .doit = ip_vs_genl_set_cmd,
3082 },
3083 {
3084 .cmd = IPVS_CMD_DEL_SERVICE,
3085 .flags = GENL_ADMIN_PERM,
3086 .policy = ip_vs_cmd_policy,
3087 .doit = ip_vs_genl_set_cmd,
3088 },
3089 {
3090 .cmd = IPVS_CMD_GET_SERVICE,
3091 .flags = GENL_ADMIN_PERM,
3092 .doit = ip_vs_genl_get_cmd,
3093 .dumpit = ip_vs_genl_dump_services,
3094 .policy = ip_vs_cmd_policy,
3095 },
3096 {
3097 .cmd = IPVS_CMD_NEW_DEST,
3098 .flags = GENL_ADMIN_PERM,
3099 .policy = ip_vs_cmd_policy,
3100 .doit = ip_vs_genl_set_cmd,
3101 },
3102 {
3103 .cmd = IPVS_CMD_SET_DEST,
3104 .flags = GENL_ADMIN_PERM,
3105 .policy = ip_vs_cmd_policy,
3106 .doit = ip_vs_genl_set_cmd,
3107 },
3108 {
3109 .cmd = IPVS_CMD_DEL_DEST,
3110 .flags = GENL_ADMIN_PERM,
3111 .policy = ip_vs_cmd_policy,
3112 .doit = ip_vs_genl_set_cmd,
3113 },
3114 {
3115 .cmd = IPVS_CMD_GET_DEST,
3116 .flags = GENL_ADMIN_PERM,
3117 .policy = ip_vs_cmd_policy,
3118 .dumpit = ip_vs_genl_dump_dests,
3119 },
3120 {
3121 .cmd = IPVS_CMD_NEW_DAEMON,
3122 .flags = GENL_ADMIN_PERM,
3123 .policy = ip_vs_cmd_policy,
3124 .doit = ip_vs_genl_set_cmd,
3125 },
3126 {
3127 .cmd = IPVS_CMD_DEL_DAEMON,
3128 .flags = GENL_ADMIN_PERM,
3129 .policy = ip_vs_cmd_policy,
3130 .doit = ip_vs_genl_set_cmd,
3131 },
3132 {
3133 .cmd = IPVS_CMD_GET_DAEMON,
3134 .flags = GENL_ADMIN_PERM,
3135 .dumpit = ip_vs_genl_dump_daemons,
3136 },
3137 {
3138 .cmd = IPVS_CMD_SET_CONFIG,
3139 .flags = GENL_ADMIN_PERM,
3140 .policy = ip_vs_cmd_policy,
3141 .doit = ip_vs_genl_set_cmd,
3142 },
3143 {
3144 .cmd = IPVS_CMD_GET_CONFIG,
3145 .flags = GENL_ADMIN_PERM,
3146 .doit = ip_vs_genl_get_cmd,
3147 },
3148 {
3149 .cmd = IPVS_CMD_GET_INFO,
3150 .flags = GENL_ADMIN_PERM,
3151 .doit = ip_vs_genl_get_cmd,
3152 },
3153 {
3154 .cmd = IPVS_CMD_ZERO,
3155 .flags = GENL_ADMIN_PERM,
3156 .policy = ip_vs_cmd_policy,
3157 .doit = ip_vs_genl_set_cmd,
3158 },
3159 {
3160 .cmd = IPVS_CMD_FLUSH,
3161 .flags = GENL_ADMIN_PERM,
3162 .doit = ip_vs_genl_set_cmd,
3163 },
3164};
3165
3166static int __init ip_vs_genl_register(void)
3167{
3168 int ret, i;
3169
3170 ret = genl_register_family(&ip_vs_genl_family);
3171 if (ret)
3172 return ret;
3173
3174 for (i = 0; i < ARRAY_SIZE(ip_vs_genl_ops); i++) {
3175 ret = genl_register_ops(&ip_vs_genl_family, &ip_vs_genl_ops[i]);
3176 if (ret)
3177 goto err_out;
3178 }
3179 return 0;
3180
3181err_out:
3182 genl_unregister_family(&ip_vs_genl_family);
3183 return ret;
3184}
3185
3186static void ip_vs_genl_unregister(void)
3187{
3188 genl_unregister_family(&ip_vs_genl_family);
3189}
3190
3191/* End of Generic Netlink interface definitions */
3192
2323 3193
2324int __init ip_vs_control_init(void) 3194int __init ip_vs_control_init(void)
2325{ 3195{
@@ -2334,6 +3204,13 @@ int __init ip_vs_control_init(void)
2334 return ret; 3204 return ret;
2335 } 3205 }
2336 3206
3207 ret = ip_vs_genl_register();
3208 if (ret) {
3209 IP_VS_ERR("cannot register Generic Netlink interface.\n");
3210 nf_unregister_sockopt(&ip_vs_sockopts);
3211 return ret;
3212 }
3213
2337 proc_net_fops_create(&init_net, "ip_vs", 0, &ip_vs_info_fops); 3214 proc_net_fops_create(&init_net, "ip_vs", 0, &ip_vs_info_fops);
2338 proc_net_fops_create(&init_net, "ip_vs_stats",0, &ip_vs_stats_fops); 3215 proc_net_fops_create(&init_net, "ip_vs_stats",0, &ip_vs_stats_fops);
2339 3216
@@ -2368,6 +3245,7 @@ void ip_vs_control_cleanup(void)
2368 unregister_sysctl_table(sysctl_header); 3245 unregister_sysctl_table(sysctl_header);
2369 proc_net_remove(&init_net, "ip_vs_stats"); 3246 proc_net_remove(&init_net, "ip_vs_stats");
2370 proc_net_remove(&init_net, "ip_vs"); 3247 proc_net_remove(&init_net, "ip_vs");
3248 ip_vs_genl_unregister();
2371 nf_unregister_sockopt(&ip_vs_sockopts); 3249 nf_unregister_sockopt(&ip_vs_sockopts);
2372 LeaveFunction(2); 3250 LeaveFunction(2);
2373} 3251}