diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-06-26 14:27:09 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-06-27 11:28:03 -0400 |
commit | 392025f87a5105c640cf1b4b317c21c14c05a6f9 (patch) | |
tree | 2d3a1dd345060bb9e8bf89bdde18fc215cbee2c3 /net | |
parent | 93040ae5cc8dcc893eca4a4366dc8415af278edf (diff) |
netfilter: ctnetlink: add new messages to obtain statistics
This patch adds the following messages to ctnetlink:
IPCTNL_MSG_CT_GET_STATS_CPU
IPCTNL_MSG_CT_GET_STATS
IPCTNL_MSG_EXP_GET_STATS_CPU
To display connection tracking system per-cpu and global statistics.
This provides a replacement for the following /proc interfaces:
/proc/net/stat/nf_conntrack
/proc/sys/net/netfilter/nf_conntrack_count
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 227 |
1 files changed, 226 insertions, 1 deletions
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index b9b8f4ac7a36..14f67a2cbcb5 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * (C) 2001 by Jay Schulist <jschlst@samba.org> | 4 | * (C) 2001 by Jay Schulist <jschlst@samba.org> |
5 | * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org> | 5 | * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org> |
6 | * (C) 2003 by Patrick Mchardy <kaber@trash.net> | 6 | * (C) 2003 by Patrick Mchardy <kaber@trash.net> |
7 | * (C) 2005-2011 by Pablo Neira Ayuso <pablo@netfilter.org> | 7 | * (C) 2005-2012 by Pablo Neira Ayuso <pablo@netfilter.org> |
8 | * | 8 | * |
9 | * Initial connection tracking via netlink development funded and | 9 | * Initial connection tracking via netlink development funded and |
10 | * generally made possible by Network Robots, Inc. (www.networkrobots.com) | 10 | * generally made possible by Network Robots, Inc. (www.networkrobots.com) |
@@ -1627,6 +1627,155 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, | |||
1627 | return err; | 1627 | return err; |
1628 | } | 1628 | } |
1629 | 1629 | ||
1630 | static int | ||
1631 | ctnetlink_ct_stat_cpu_fill_info(struct sk_buff *skb, u32 pid, u32 seq, | ||
1632 | __u16 cpu, const struct ip_conntrack_stat *st) | ||
1633 | { | ||
1634 | struct nlmsghdr *nlh; | ||
1635 | struct nfgenmsg *nfmsg; | ||
1636 | unsigned int flags = pid ? NLM_F_MULTI : 0, event; | ||
1637 | |||
1638 | event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_CT_GET_STATS_CPU); | ||
1639 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags); | ||
1640 | if (nlh == NULL) | ||
1641 | goto nlmsg_failure; | ||
1642 | |||
1643 | nfmsg = nlmsg_data(nlh); | ||
1644 | nfmsg->nfgen_family = AF_UNSPEC; | ||
1645 | nfmsg->version = NFNETLINK_V0; | ||
1646 | nfmsg->res_id = htons(cpu); | ||
1647 | |||
1648 | if (nla_put_be32(skb, CTA_STATS_SEARCHED, htonl(st->searched)) || | ||
1649 | nla_put_be32(skb, CTA_STATS_FOUND, htonl(st->found)) || | ||
1650 | nla_put_be32(skb, CTA_STATS_NEW, htonl(st->new)) || | ||
1651 | nla_put_be32(skb, CTA_STATS_INVALID, htonl(st->invalid)) || | ||
1652 | nla_put_be32(skb, CTA_STATS_IGNORE, htonl(st->ignore)) || | ||
1653 | nla_put_be32(skb, CTA_STATS_DELETE, htonl(st->delete)) || | ||
1654 | nla_put_be32(skb, CTA_STATS_DELETE_LIST, htonl(st->delete_list)) || | ||
1655 | nla_put_be32(skb, CTA_STATS_INSERT, htonl(st->insert)) || | ||
1656 | nla_put_be32(skb, CTA_STATS_INSERT_FAILED, | ||
1657 | htonl(st->insert_failed)) || | ||
1658 | nla_put_be32(skb, CTA_STATS_DROP, htonl(st->drop)) || | ||
1659 | nla_put_be32(skb, CTA_STATS_EARLY_DROP, htonl(st->early_drop)) || | ||
1660 | nla_put_be32(skb, CTA_STATS_ERROR, htonl(st->error)) || | ||
1661 | nla_put_be32(skb, CTA_STATS_SEARCH_RESTART, | ||
1662 | htonl(st->search_restart))) | ||
1663 | goto nla_put_failure; | ||
1664 | |||
1665 | nlmsg_end(skb, nlh); | ||
1666 | return skb->len; | ||
1667 | |||
1668 | nla_put_failure: | ||
1669 | nlmsg_failure: | ||
1670 | nlmsg_cancel(skb, nlh); | ||
1671 | return -1; | ||
1672 | } | ||
1673 | |||
1674 | static int | ||
1675 | ctnetlink_ct_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
1676 | { | ||
1677 | int cpu; | ||
1678 | struct net *net = sock_net(skb->sk); | ||
1679 | |||
1680 | if (cb->args[0] == nr_cpu_ids) | ||
1681 | return 0; | ||
1682 | |||
1683 | for (cpu = cb->args[0]; cpu < nr_cpu_ids; cpu++) { | ||
1684 | const struct ip_conntrack_stat *st; | ||
1685 | |||
1686 | if (!cpu_possible(cpu)) | ||
1687 | continue; | ||
1688 | |||
1689 | st = per_cpu_ptr(net->ct.stat, cpu); | ||
1690 | if (ctnetlink_ct_stat_cpu_fill_info(skb, | ||
1691 | NETLINK_CB(cb->skb).pid, | ||
1692 | cb->nlh->nlmsg_seq, | ||
1693 | cpu, st) < 0) | ||
1694 | break; | ||
1695 | } | ||
1696 | cb->args[0] = cpu; | ||
1697 | |||
1698 | return skb->len; | ||
1699 | } | ||
1700 | |||
1701 | static int | ||
1702 | ctnetlink_stat_ct_cpu(struct sock *ctnl, struct sk_buff *skb, | ||
1703 | const struct nlmsghdr *nlh, | ||
1704 | const struct nlattr * const cda[]) | ||
1705 | { | ||
1706 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | ||
1707 | struct netlink_dump_control c = { | ||
1708 | .dump = ctnetlink_ct_stat_cpu_dump, | ||
1709 | }; | ||
1710 | return netlink_dump_start(ctnl, skb, nlh, &c); | ||
1711 | } | ||
1712 | |||
1713 | return 0; | ||
1714 | } | ||
1715 | |||
1716 | static int | ||
1717 | ctnetlink_stat_ct_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, | ||
1718 | struct net *net) | ||
1719 | { | ||
1720 | struct nlmsghdr *nlh; | ||
1721 | struct nfgenmsg *nfmsg; | ||
1722 | unsigned int flags = pid ? NLM_F_MULTI : 0, event; | ||
1723 | unsigned int nr_conntracks = atomic_read(&net->ct.count); | ||
1724 | |||
1725 | event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_CT_GET_STATS); | ||
1726 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags); | ||
1727 | if (nlh == NULL) | ||
1728 | goto nlmsg_failure; | ||
1729 | |||
1730 | nfmsg = nlmsg_data(nlh); | ||
1731 | nfmsg->nfgen_family = AF_UNSPEC; | ||
1732 | nfmsg->version = NFNETLINK_V0; | ||
1733 | nfmsg->res_id = 0; | ||
1734 | |||
1735 | if (nla_put_be32(skb, CTA_STATS_GLOBAL_ENTRIES, htonl(nr_conntracks))) | ||
1736 | goto nla_put_failure; | ||
1737 | |||
1738 | nlmsg_end(skb, nlh); | ||
1739 | return skb->len; | ||
1740 | |||
1741 | nla_put_failure: | ||
1742 | nlmsg_failure: | ||
1743 | nlmsg_cancel(skb, nlh); | ||
1744 | return -1; | ||
1745 | } | ||
1746 | |||
1747 | static int | ||
1748 | ctnetlink_stat_ct(struct sock *ctnl, struct sk_buff *skb, | ||
1749 | const struct nlmsghdr *nlh, | ||
1750 | const struct nlattr * const cda[]) | ||
1751 | { | ||
1752 | struct sk_buff *skb2; | ||
1753 | int err; | ||
1754 | |||
1755 | skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
1756 | if (skb2 == NULL) | ||
1757 | return -ENOMEM; | ||
1758 | |||
1759 | err = ctnetlink_stat_ct_fill_info(skb2, NETLINK_CB(skb).pid, | ||
1760 | nlh->nlmsg_seq, | ||
1761 | NFNL_MSG_TYPE(nlh->nlmsg_type), | ||
1762 | sock_net(skb->sk)); | ||
1763 | if (err <= 0) | ||
1764 | goto free; | ||
1765 | |||
1766 | err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); | ||
1767 | if (err < 0) | ||
1768 | goto out; | ||
1769 | |||
1770 | return 0; | ||
1771 | |||
1772 | free: | ||
1773 | kfree_skb(skb2); | ||
1774 | out: | ||
1775 | /* this avoids a loop in nfnetlink. */ | ||
1776 | return err == -EAGAIN ? -ENOBUFS : err; | ||
1777 | } | ||
1778 | |||
1630 | #ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT | 1779 | #ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT |
1631 | static size_t | 1780 | static size_t |
1632 | ctnetlink_nfqueue_build_size(const struct nf_conn *ct) | 1781 | ctnetlink_nfqueue_build_size(const struct nf_conn *ct) |
@@ -2440,6 +2589,79 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, | |||
2440 | return err; | 2589 | return err; |
2441 | } | 2590 | } |
2442 | 2591 | ||
2592 | static int | ||
2593 | ctnetlink_exp_stat_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int cpu, | ||
2594 | const struct ip_conntrack_stat *st) | ||
2595 | { | ||
2596 | struct nlmsghdr *nlh; | ||
2597 | struct nfgenmsg *nfmsg; | ||
2598 | unsigned int flags = pid ? NLM_F_MULTI : 0, event; | ||
2599 | |||
2600 | event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_EXP_GET_STATS_CPU); | ||
2601 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags); | ||
2602 | if (nlh == NULL) | ||
2603 | goto nlmsg_failure; | ||
2604 | |||
2605 | nfmsg = nlmsg_data(nlh); | ||
2606 | nfmsg->nfgen_family = AF_UNSPEC; | ||
2607 | nfmsg->version = NFNETLINK_V0; | ||
2608 | nfmsg->res_id = htons(cpu); | ||
2609 | |||
2610 | if (nla_put_be32(skb, CTA_STATS_EXP_NEW, htonl(st->expect_new)) || | ||
2611 | nla_put_be32(skb, CTA_STATS_EXP_CREATE, htonl(st->expect_create)) || | ||
2612 | nla_put_be32(skb, CTA_STATS_EXP_DELETE, htonl(st->expect_delete))) | ||
2613 | goto nla_put_failure; | ||
2614 | |||
2615 | nlmsg_end(skb, nlh); | ||
2616 | return skb->len; | ||
2617 | |||
2618 | nla_put_failure: | ||
2619 | nlmsg_failure: | ||
2620 | nlmsg_cancel(skb, nlh); | ||
2621 | return -1; | ||
2622 | } | ||
2623 | |||
2624 | static int | ||
2625 | ctnetlink_exp_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
2626 | { | ||
2627 | int cpu; | ||
2628 | struct net *net = sock_net(skb->sk); | ||
2629 | |||
2630 | if (cb->args[0] == nr_cpu_ids) | ||
2631 | return 0; | ||
2632 | |||
2633 | for (cpu = cb->args[0]; cpu < nr_cpu_ids; cpu++) { | ||
2634 | const struct ip_conntrack_stat *st; | ||
2635 | |||
2636 | if (!cpu_possible(cpu)) | ||
2637 | continue; | ||
2638 | |||
2639 | st = per_cpu_ptr(net->ct.stat, cpu); | ||
2640 | if (ctnetlink_exp_stat_fill_info(skb, NETLINK_CB(cb->skb).pid, | ||
2641 | cb->nlh->nlmsg_seq, | ||
2642 | cpu, st) < 0) | ||
2643 | break; | ||
2644 | } | ||
2645 | cb->args[0] = cpu; | ||
2646 | |||
2647 | return skb->len; | ||
2648 | } | ||
2649 | |||
2650 | static int | ||
2651 | ctnetlink_stat_exp_cpu(struct sock *ctnl, struct sk_buff *skb, | ||
2652 | const struct nlmsghdr *nlh, | ||
2653 | const struct nlattr * const cda[]) | ||
2654 | { | ||
2655 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | ||
2656 | struct netlink_dump_control c = { | ||
2657 | .dump = ctnetlink_exp_stat_cpu_dump, | ||
2658 | }; | ||
2659 | return netlink_dump_start(ctnl, skb, nlh, &c); | ||
2660 | } | ||
2661 | |||
2662 | return 0; | ||
2663 | } | ||
2664 | |||
2443 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | 2665 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
2444 | static struct nf_ct_event_notifier ctnl_notifier = { | 2666 | static struct nf_ct_event_notifier ctnl_notifier = { |
2445 | .fcn = ctnetlink_conntrack_event, | 2667 | .fcn = ctnetlink_conntrack_event, |
@@ -2463,6 +2685,8 @@ static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { | |||
2463 | [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack, | 2685 | [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack, |
2464 | .attr_count = CTA_MAX, | 2686 | .attr_count = CTA_MAX, |
2465 | .policy = ct_nla_policy }, | 2687 | .policy = ct_nla_policy }, |
2688 | [IPCTNL_MSG_CT_GET_STATS_CPU] = { .call = ctnetlink_stat_ct_cpu }, | ||
2689 | [IPCTNL_MSG_CT_GET_STATS] = { .call = ctnetlink_stat_ct }, | ||
2466 | }; | 2690 | }; |
2467 | 2691 | ||
2468 | static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { | 2692 | static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { |
@@ -2475,6 +2699,7 @@ static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { | |||
2475 | [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect, | 2699 | [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect, |
2476 | .attr_count = CTA_EXPECT_MAX, | 2700 | .attr_count = CTA_EXPECT_MAX, |
2477 | .policy = exp_nla_policy }, | 2701 | .policy = exp_nla_policy }, |
2702 | [IPCTNL_MSG_EXP_GET_STATS_CPU] = { .call = ctnetlink_stat_exp_cpu }, | ||
2478 | }; | 2703 | }; |
2479 | 2704 | ||
2480 | static const struct nfnetlink_subsystem ctnl_subsys = { | 2705 | static const struct nfnetlink_subsystem ctnl_subsys = { |