netfilter: nft_ct: add byte/packet counter support

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>
This commit is contained in:
Florian Westphal 2016-01-07 21:34:24 +01:00 committed by Pablo Neira Ayuso
parent ce1e7989d9
commit 48f66c905a
2 changed files with 40 additions and 0 deletions

View File

@ -757,6 +757,8 @@ enum nft_ct_keys {
NFT_CT_PROTO_SRC, NFT_CT_PROTO_SRC,
NFT_CT_PROTO_DST, NFT_CT_PROTO_DST,
NFT_CT_LABELS, NFT_CT_LABELS,
NFT_CT_PKTS,
NFT_CT_BYTES,
}; };
/** /**

View File

@ -16,6 +16,7 @@
#include <linux/netfilter/nf_tables.h> #include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables.h> #include <net/netfilter/nf_tables.h>
#include <net/netfilter/nf_conntrack.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_tuple.h>
#include <net/netfilter/nf_conntrack_helper.h> #include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_ecache.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, static void nft_ct_get_eval(const struct nft_expr *expr,
struct nft_regs *regs, struct nft_regs *regs,
const struct nft_pktinfo *pkt) 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); NF_CT_LABELS_MAX_SIZE - size);
return; 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 #endif
default: default:
break; break;
@ -291,6 +315,13 @@ static int nft_ct_get_init(const struct nft_ctx *ctx,
return -EINVAL; return -EINVAL;
len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u.all); len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u.all);
break; 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: default:
return -EOPNOTSUPP; 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: case NFT_CT_PROTO_DST:
if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir)) if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
goto nla_put_failure; 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: default:
break; break;
} }