aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2012-06-26 14:27:09 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2012-06-27 11:28:03 -0400
commit392025f87a5105c640cf1b4b317c21c14c05a6f9 (patch)
tree2d3a1dd345060bb9e8bf89bdde18fc215cbee2c3 /net
parent93040ae5cc8dcc893eca4a4366dc8415af278edf (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.c227
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
1630static int
1631ctnetlink_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
1668nla_put_failure:
1669nlmsg_failure:
1670 nlmsg_cancel(skb, nlh);
1671 return -1;
1672}
1673
1674static int
1675ctnetlink_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
1701static int
1702ctnetlink_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
1716static int
1717ctnetlink_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
1741nla_put_failure:
1742nlmsg_failure:
1743 nlmsg_cancel(skb, nlh);
1744 return -1;
1745}
1746
1747static int
1748ctnetlink_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
1772free:
1773 kfree_skb(skb2);
1774out:
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
1631static size_t 1780static size_t
1632ctnetlink_nfqueue_build_size(const struct nf_conn *ct) 1781ctnetlink_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
2592static int
2593ctnetlink_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
2618nla_put_failure:
2619nlmsg_failure:
2620 nlmsg_cancel(skb, nlh);
2621 return -1;
2622}
2623
2624static int
2625ctnetlink_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
2650static int
2651ctnetlink_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
2444static struct nf_ct_event_notifier ctnl_notifier = { 2666static 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
2468static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { 2692static 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
2480static const struct nfnetlink_subsystem ctnl_subsys = { 2705static const struct nfnetlink_subsystem ctnl_subsys = {