|
@@ -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),
|
|
@@ -211,6 +221,38 @@ nfnl_acct_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
return skb->len;
|
|
|
}
|
|
|
|
|
|
+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(const struct nlattr * const attr)
|
|
|
+{
|
|
|
+ struct nfacct_filter *filter;
|
|
|
+ struct nlattr *tb[NFACCT_FILTER_MAX + 1];
|
|
|
+ int err;
|
|
|
+
|
|
|
+ err = nla_parse_nested(tb, NFACCT_FILTER_MAX, attr, filter_policy);
|
|
|
+ if (err < 0)
|
|
|
+ return ERR_PTR(err);
|
|
|
+
|
|
|
+ filter = kzalloc(sizeof(struct nfacct_filter), GFP_KERNEL);
|
|
|
+ if (!filter)
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
+
|
|
|
+ filter->mask = ntohl(nla_get_be32(tb[NFACCT_FILTER_MASK]));
|
|
|
+ filter->value = ntohl(nla_get_be32(tb[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 +264,18 @@ 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 nfacct_filter *filter;
|
|
|
+
|
|
|
+ filter = nfacct_filter_alloc(tb[NFACCT_FILTER]);
|
|
|
+ if (IS_ERR(filter))
|
|
|
+ return PTR_ERR(filter);
|
|
|
+
|
|
|
+ c.data = filter;
|
|
|
+ }
|
|
|
return netlink_dump_start(nfnl, skb, nlh, &c);
|
|
|
}
|
|
|
|
|
@@ -314,6 +367,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] = {
|