diff mbox

[nf-next,08/11] netfilter: nft_quota: add depleted flag for objects

Message ID 1480291270-3715-9-git-send-email-pablo@netfilter.org
State Changes Requested
Delegated to: Pablo Neira
Headers show

Commit Message

Pablo Neira Ayuso Nov. 28, 2016, 12:01 a.m. UTC
Notify on depleted quota objects. The NFT_QUOTA_F_DEPLETED flag
indicates we have reached overquota.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/uapi/linux/netfilter/nf_tables.h |  1 +
 net/netfilter/nft_quota.c                | 33 ++++++++++++++++++++++++--------
 2 files changed, 26 insertions(+), 8 deletions(-)

Comments

Florian Westphal Nov. 28, 2016, 10:27 a.m. UTC | #1
Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> Notify on depleted quota objects. The NFT_QUOTA_F_DEPLETED flag
> indicates we have reached overquota.
> 
> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
> -	nft_quota_do_eval(priv, regs, pkt);
> +	if (nft_overquota(priv, pkt) ^ nft_quota_invert(priv)) {
> +		if (test_and_set_bit(NFT_QUOTA_F_DEPLETED, &priv->flags)) {
> +			nft_obj_notify(nft_net(pkt), nft_chain(pkt)->table,
> +				       obj, 0, 0, NFT_MSG_NEWOBJ,
> +				       nft_pf(pkt), 0, GFP_ATOMIC);

I suspect this should be !test_and_set_bit()?

Or does this really want to call notify for every overquota hit?

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Pablo Neira Ayuso Nov. 28, 2016, 11:08 a.m. UTC | #2
On Mon, Nov 28, 2016 at 11:27:49AM +0100, Florian Westphal wrote:
> Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > Notify on depleted quota objects. The NFT_QUOTA_F_DEPLETED flag
> > indicates we have reached overquota.
> > 
> > Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
> > -	nft_quota_do_eval(priv, regs, pkt);
> > +	if (nft_overquota(priv, pkt) ^ nft_quota_invert(priv)) {
> > +		if (test_and_set_bit(NFT_QUOTA_F_DEPLETED, &priv->flags)) {
> > +			nft_obj_notify(nft_net(pkt), nft_chain(pkt)->table,
> > +				       obj, 0, 0, NFT_MSG_NEWOBJ,
> > +				       nft_pf(pkt), 0, GFP_ATOMIC);
> 
> I suspect this should be !test_and_set_bit()?
> 
> Or does this really want to call notify for every overquota hit?

That's right, my test here was just checking for the first event then
stop. Will fix up this, thanks for reviewing.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index bd80501c5633..cf2130457d00 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -1013,6 +1013,7 @@  enum nft_queue_attributes {
 
 enum nft_quota_flags {
 	NFT_QUOTA_F_INV		= (1 << 0),
+	NFT_QUOTA_F_DEPLETED	= (1 << 1),
 };
 
 /**
diff --git a/net/netfilter/nft_quota.c b/net/netfilter/nft_quota.c
index ef2f2ae885aa..bbc5aa93b3cc 100644
--- a/net/netfilter/nft_quota.c
+++ b/net/netfilter/nft_quota.c
@@ -17,8 +17,8 @@ 
 
 struct nft_quota {
 	u64		quota;
-	bool		invert;
 	atomic64_t	consumed;
+	unsigned long	flags;
 };
 
 static inline bool nft_overquota(struct nft_quota *priv,
@@ -27,11 +27,16 @@  static inline bool nft_overquota(struct nft_quota *priv,
 	return atomic64_add_return(pkt->skb->len, &priv->consumed) > priv->quota;
 }
 
+static inline bool nft_quota_invert(struct nft_quota *priv)
+{
+	return priv->flags & NFT_QUOTA_F_INV;
+}
+
 static inline void nft_quota_do_eval(struct nft_quota *priv,
 				     struct nft_regs *regs,
 				     const struct nft_pktinfo *pkt)
 {
-	if (nft_overquota(priv, pkt) ^ priv->invert)
+	if (nft_overquota(priv, pkt) ^ nft_quota_invert(priv))
 		regs->verdict.code = NFT_BREAK;
 }
 
@@ -46,13 +51,20 @@  static void nft_quota_obj_eval(void *obj,
 {
 	struct nft_quota *priv = obj;
 
-	nft_quota_do_eval(priv, regs, pkt);
+	if (nft_overquota(priv, pkt) ^ nft_quota_invert(priv)) {
+		if (test_and_set_bit(NFT_QUOTA_F_DEPLETED, &priv->flags)) {
+			nft_obj_notify(nft_net(pkt), nft_chain(pkt)->table,
+				       obj, 0, 0, NFT_MSG_NEWOBJ,
+				       nft_pf(pkt), 0, GFP_ATOMIC);
+		}
+		regs->verdict.code = NFT_BREAK;
+	}
 }
 
 static int nft_quota_obj_init(const struct nlattr * const tb[], void *obj)
 {
 	struct nft_quota *priv = obj;
-	u32 flags = 0;
+	unsigned long flags = 0;
 	u64 quota;
 
 	if (!tb[NFTA_QUOTA_BYTES])
@@ -66,10 +78,12 @@  static int nft_quota_obj_init(const struct nlattr * const tb[], void *obj)
 		flags = ntohl(nla_get_be32(tb[NFTA_QUOTA_FLAGS]));
 		if (flags & ~NFT_QUOTA_F_INV)
 			return -EINVAL;
+		if (flags & NFT_QUOTA_F_DEPLETED)
+			return -EOPNOTSUPP;
 	}
 
 	priv->quota = quota;
-	priv->invert = (flags & NFT_QUOTA_F_INV) ? true : false;
+	priv->flags = flags;
 	atomic64_set(&priv->consumed, 0);
 
 	return 0;
@@ -78,13 +92,16 @@  static int nft_quota_obj_init(const struct nlattr * const tb[], void *obj)
 static int nft_quota_obj_dump(struct sk_buff *skb, void *obj, bool reset)
 {
 	struct nft_quota *priv = obj;
-	u32 flags = priv->invert ? NFT_QUOTA_F_INV : 0;
+	unsigned long flags = priv->flags;
 	u64 consumed;
 
-	if (reset)
+	if (reset) {
 		consumed = atomic64_xchg(&priv->consumed, 0);
-	else
+		if (test_and_clear_bit(NFT_QUOTA_F_DEPLETED, &priv->flags))
+			flags |= NFT_QUOTA_F_DEPLETED;
+	} else {
 		consumed = atomic64_read(&priv->consumed);
+	}
 
 	if (nla_put_be64(skb, NFTA_QUOTA_BYTES, cpu_to_be64(priv->quota),
 			 NFTA_QUOTA_PAD) ||