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