@@ -28,9 +28,17 @@ enum nfnl_acct_type {
NFACCT_USE,
NFACCT_FLAGS,
NFACCT_QUOTA,
+ NFACCT_FILTER,
__NFACCT_MAX
};
#define NFACCT_MAX (__NFACCT_MAX - 1)
+enum nfnl_attr_filter_type {
+ NFACCT_FILTER_UNSPEC,
+ NFACCT_FILTER_MASK,
+ NFACCT_FILTER_VALUE,
+ __NFACCT_FILTER_MAX
+};
+#define NFACCT_FILTER_MAX (__NFACCT_FILTER_MAX - 1)
#endif /* _UAPI_NFNL_ACCT_H_ */
@@ -40,6 +40,11 @@ struct nf_acct {
char data[0];
};
+struct nfacct_filter {
+ u32 value;
+ u32 mask;
+};
+
#define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES)
#define NFACCT_OVERQUOTA_BIT 2 /* NFACCT_F_OVERQUOTA */
@@ -181,6 +186,7 @@ static int
nfnl_acct_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
struct nf_acct *cur, *last;
+ const struct nfacct_filter *filter = cb->data;
if (cb->args[2])
return 0;
@@ -197,6 +203,10 @@ nfnl_acct_dump(struct sk_buff *skb, struct netlink_callback *cb)
last = NULL;
}
+
+ if (filter && (cur->flags & filter->mask) != filter->value)
+ continue;
+
if (nfnl_acct_fill_info(skb, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
@@ -212,6 +222,32 @@ nfnl_acct_dump(struct sk_buff *skb, struct netlink_callback *cb)
}
static int
+nfnl_acct_done(struct netlink_callback *cb)
+{
+ kfree(cb->data);
+ return 0;
+}
+
+static const struct nla_policy filter_policy[NFACCT_FILTER_MAX + 1] = {
+ [NFACCT_FILTER_MASK] = { .type = NLA_U32 },
+ [NFACCT_FILTER_VALUE] = { .type = NLA_U32 },
+};
+
+static struct nfacct_filter *
+nfacct_filter_alloc(struct nlattr *attrs[NFACCT_FILTER_MAX + 1])
+{
+ struct nfacct_filter *filter = kzalloc(sizeof(struct nfacct_filter),
+ GFP_KERNEL);
+ if (!filter)
+ return ERR_PTR(-ENOMEM);
+
+ filter->mask = nla_get_be32(attrs[NFACCT_FILTER_MASK]);
+ filter->value = nla_get_be32(attrs[NFACCT_FILTER_VALUE]);
+
+ return filter;
+}
+
+static int
nfnl_acct_get(struct sock *nfnl, struct sk_buff *skb,
const struct nlmsghdr *nlh, const struct nlattr * const tb[])
{
@@ -222,7 +258,21 @@ nfnl_acct_get(struct sock *nfnl, struct sk_buff *skb,
if (nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.dump = nfnl_acct_dump,
+ .done = nfnl_acct_done,
};
+ if (tb[NFACCT_FILTER]) {
+ struct nlattr *attrs[NFACCT_FILTER_MAX + 1];
+ ret = nla_parse_nested(attrs, NFACCT_FILTER_MAX,
+ tb[NFACCT_FILTER],
+ filter_policy);
+ if (ret < 0)
+ return ret;
+
+ c.data = nfacct_filter_alloc(attrs);
+ if (IS_ERR(c.data))
+ return PTR_ERR(c.data);
+ }
+
return netlink_dump_start(nfnl, skb, nlh, &c);
}
@@ -314,6 +364,7 @@ static const struct nla_policy nfnl_acct_policy[NFACCT_MAX+1] = {
[NFACCT_PKTS] = { .type = NLA_U64 },
[NFACCT_FLAGS] = { .type = NLA_U32 },
[NFACCT_QUOTA] = { .type = NLA_U64 },
+ [NFACCT_FILTER] = {.type = NLA_NESTED },
};
static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = {
Filtering covers following cases: 1. no filter specified. In this case client will get old behaviour 2. filter specified for getting only counters: in this case marks should be NFACCT_F_QUOTAS and value 0 3. filter specified for getting quotas: for packet based quota mask should be NFACCT_F_QUOTA_PKTS and value - the same, for byte based quota mask should be NFACCT_F_QUOTA_BYTES and value - the same. Bit set for quota is't supported in this patch. NFACCT_F_QUOTA didn't expose for user space program in public header as well. In case of NFACCT_F_QUOTA two request is necessary, one for NFACCT_F_QUOTA_PKTS and another one for NFACCT_F_QUOTA_BYTES. Signed-off-by: Alexey Perevalov <a.perevalov@samsung.com> --- include/uapi/linux/netfilter/nfnetlink_acct.h | 8 ++++ net/netfilter/nfnetlink_acct.c | 51 +++++++++++++++++++++++++ 2 files changed, 59 insertions(+)