From: Fernando Fernandez Mancera <ffmanc...@riseup.net>

Signed-off-by: Fernando Fernandez Mancera <ffmanc...@riseup.net>
Signed-off-by: Pablo Neira Ayuso <pa...@netfilter.org>
---
 net/netfilter/nft_quota.c | 29 ++++++++++++++++++++++-------
 1 file changed, 22 insertions(+), 7 deletions(-)

diff --git a/net/netfilter/nft_quota.c b/net/netfilter/nft_quota.c
index c8745d454bf8..4413690591f2 100644
--- a/net/netfilter/nft_quota.c
+++ b/net/netfilter/nft_quota.c
@@ -13,7 +13,7 @@
 #include <net/netfilter/nf_tables.h>
 
 struct nft_quota {
-       u64             quota;
+       atomic64_t      quota;
        unsigned long   flags;
        atomic64_t      consumed;
 };
@@ -21,7 +21,8 @@ struct nft_quota {
 static inline bool nft_overquota(struct nft_quota *priv,
                                 const struct sk_buff *skb)
 {
-       return atomic64_add_return(skb->len, &priv->consumed) >= priv->quota;
+       return atomic64_add_return(skb->len, &priv->consumed) >=
+              atomic64_read(&priv->quota);
 }
 
 static inline bool nft_quota_invert(struct nft_quota *priv)
@@ -89,7 +90,7 @@ static int nft_quota_do_init(const struct nlattr * const tb[],
                        return -EOPNOTSUPP;
        }
 
-       priv->quota = quota;
+       atomic64_set(&priv->quota, quota);
        priv->flags = flags;
        atomic64_set(&priv->consumed, consumed);
 
@@ -105,10 +106,22 @@ static int nft_quota_obj_init(const struct nft_ctx *ctx,
        return nft_quota_do_init(tb, priv);
 }
 
+static void nft_quota_obj_update(struct nft_object *obj,
+                                struct nft_object *newobj)
+{
+       struct nft_quota *newpriv = nft_obj_data(newobj);
+       struct nft_quota *priv = nft_obj_data(obj);
+       u64 newquota;
+
+       newquota = atomic64_read(&newpriv->quota);
+       atomic64_set(&priv->quota, newquota);
+       priv->flags = newpriv->flags;
+}
+
 static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv,
                             bool reset)
 {
-       u64 consumed, consumed_cap;
+       u64 consumed, consumed_cap, quota;
        u32 flags = priv->flags;
 
        /* Since we inconditionally increment consumed quota for each packet
@@ -116,14 +129,15 @@ static int nft_quota_do_dump(struct sk_buff *skb, struct 
nft_quota *priv,
         * userspace.
         */
        consumed = atomic64_read(&priv->consumed);
-       if (consumed >= priv->quota) {
-               consumed_cap = priv->quota;
+       quota = atomic64_read(&priv->quota);
+       if (consumed >= quota) {
+               consumed_cap = quota;
                flags |= NFT_QUOTA_F_DEPLETED;
        } else {
                consumed_cap = consumed;
        }
 
-       if (nla_put_be64(skb, NFTA_QUOTA_BYTES, cpu_to_be64(priv->quota),
+       if (nla_put_be64(skb, NFTA_QUOTA_BYTES, cpu_to_be64(quota),
                         NFTA_QUOTA_PAD) ||
            nla_put_be64(skb, NFTA_QUOTA_CONSUMED, cpu_to_be64(consumed_cap),
                         NFTA_QUOTA_PAD) ||
@@ -155,6 +169,7 @@ static const struct nft_object_ops nft_quota_obj_ops = {
        .init           = nft_quota_obj_init,
        .eval           = nft_quota_obj_eval,
        .dump           = nft_quota_obj_dump,
+       .update         = nft_quota_obj_update,
 };
 
 static struct nft_object_type nft_quota_obj_type __read_mostly = {
-- 
2.11.0

Reply via email to