netfilter: nft_ct: add byte/packet counter support
authorFlorian Westphal <fw@strlen.de>
Thu, 7 Jan 2016 20:34:24 +0000 (21:34 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 8 Jan 2016 13:44:09 +0000 (14:44 +0100)
If the accounting extension isn't present, we'll return a counter
value of 0.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/uapi/linux/netfilter/nf_tables.h
net/netfilter/nft_ct.c

index 03c28a402c6320d04cfa0f14663c5d252b5365cb..be41ffc128b832d9ade6ca045736625e21b32e5e 100644 (file)
@@ -757,6 +757,8 @@ enum nft_ct_keys {
        NFT_CT_PROTO_SRC,
        NFT_CT_PROTO_DST,
        NFT_CT_LABELS,
+       NFT_CT_PKTS,
+       NFT_CT_BYTES,
 };
 
 /**
index 8cbca3432f90324f8a28df2bd67da88cdaf72b12..6f74109a7ed320c014af9a0f70a7830a692d8e3c 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/netfilter/nf_tables.h>
 #include <net/netfilter/nf_tables.h>
 #include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_acct.h>
 #include <net/netfilter/nf_conntrack_tuple.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_ecache.h>
@@ -30,6 +31,18 @@ struct nft_ct {
        };
 };
 
+static u64 nft_ct_get_eval_counter(const struct nf_conn_counter *c,
+                                  enum nft_ct_keys k,
+                                  enum ip_conntrack_dir d)
+{
+       if (d < IP_CT_DIR_MAX)
+               return k == NFT_CT_BYTES ? atomic64_read(&c[d].bytes) :
+                                          atomic64_read(&c[d].packets);
+
+       return nft_ct_get_eval_counter(c, k, IP_CT_DIR_ORIGINAL) +
+              nft_ct_get_eval_counter(c, k, IP_CT_DIR_REPLY);
+}
+
 static void nft_ct_get_eval(const struct nft_expr *expr,
                            struct nft_regs *regs,
                            const struct nft_pktinfo *pkt)
@@ -114,6 +127,17 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
                               NF_CT_LABELS_MAX_SIZE - size);
                return;
        }
+       case NFT_CT_BYTES: /* fallthrough */
+       case NFT_CT_PKTS: {
+               const struct nf_conn_acct *acct = nf_conn_acct_find(ct);
+               u64 count = 0;
+
+               if (acct)
+                       count = nft_ct_get_eval_counter(acct->counter,
+                                                       priv->key, priv->dir);
+               memcpy(dest, &count, sizeof(count));
+               return;
+       }
 #endif
        default:
                break;
@@ -291,6 +315,13 @@ static int nft_ct_get_init(const struct nft_ctx *ctx,
                        return -EINVAL;
                len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u.all);
                break;
+       case NFT_CT_BYTES:
+       case NFT_CT_PKTS:
+               /* no direction? return sum of original + reply */
+               if (tb[NFTA_CT_DIRECTION] == NULL)
+                       priv->dir = IP_CT_DIR_MAX;
+               len = sizeof(u64);
+               break;
        default:
                return -EOPNOTSUPP;
        }
@@ -373,6 +404,13 @@ static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
        case NFT_CT_PROTO_DST:
                if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
                        goto nla_put_failure;
+               break;
+       case NFT_CT_BYTES:
+       case NFT_CT_PKTS:
+               if (priv->dir < IP_CT_DIR_MAX &&
+                   nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
+                       goto nla_put_failure;
+               break;
        default:
                break;
        }