Re: [RESEND PATCH v2] netfilter: nfnetlink_acct: Adding quota support to accounting framework

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Two full weeks have passed since I sent this patch and still no answer
- I also looked in your next tree [1] and despite agreeing on the
changes prior to sending the patch it hasn't been queued.  Am I
looking at the right place?  Is there anything else you'd like to me
to modify?  Do you still intend to queue this for the 3.16 merge
window?

[1]. git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next.git

On 20 April 2014 18:57,  <mathieu.poirier@xxxxxxxxxx> wrote:
> From: Mathieu Poirier <mathieu.poirier@xxxxxxxxxx>
>
> Nf_acct objects already support accounting at the byte and packet
> level.  As such it is a natural extention to add the possiblity to
> define a ceiling limit for both metrics.
>
> All the support for quotas itself is added to nfnetlink acctounting
> framework to stay coherent with current accounting object management.
> Quota limit checks are implemented in xt nfacct filter where
> statistic collection is already done.
>
> Pablo Niera Ayuso has also contributed to this feature.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@xxxxxxxxxx>
> ---
> Changes for v2:
> - Moved 'smp_mb__before_clear_bit()' before 'if' condition.
> - Fixed erroneous variable declaration.
> - Optimzed return statement in 'nfacct_mt()'.
> ---
>  include/linux/netfilter/nfnetlink_acct.h      |  8 ++-
>  include/uapi/linux/netfilter/nfnetlink.h      |  2 +
>  include/uapi/linux/netfilter/nfnetlink_acct.h |  9 +++
>  net/netfilter/nfnetlink_acct.c                | 86 +++++++++++++++++++++++++++
>  net/netfilter/xt_nfacct.c                     |  5 +-
>  5 files changed, 108 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/netfilter/nfnetlink_acct.h b/include/linux/netfilter/nfnetlink_acct.h
> index b2e85e5..6ec9757 100644
> --- a/include/linux/netfilter/nfnetlink_acct.h
> +++ b/include/linux/netfilter/nfnetlink_acct.h
> @@ -3,11 +3,17 @@
>
>  #include <uapi/linux/netfilter/nfnetlink_acct.h>
>
> +enum {
> +       NFACCT_NO_QUOTA         = -1,
> +       NFACCT_UNDERQUOTA,
> +       NFACCT_OVERQUOTA,
> +};
>
>  struct nf_acct;
>
>  struct nf_acct *nfnl_acct_find_get(const char *filter_name);
>  void nfnl_acct_put(struct nf_acct *acct);
>  void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct);
> -
> +extern int nfnl_acct_overquota(const struct sk_buff *skb,
> +                             struct nf_acct *nfacct);
>  #endif /* _NFNL_ACCT_H */
> diff --git a/include/uapi/linux/netfilter/nfnetlink.h b/include/uapi/linux/netfilter/nfnetlink.h
> index 596ddd4..354a7e5 100644
> --- a/include/uapi/linux/netfilter/nfnetlink.h
> +++ b/include/uapi/linux/netfilter/nfnetlink.h
> @@ -20,6 +20,8 @@ enum nfnetlink_groups {
>  #define NFNLGRP_CONNTRACK_EXP_DESTROY  NFNLGRP_CONNTRACK_EXP_DESTROY
>         NFNLGRP_NFTABLES,
>  #define NFNLGRP_NFTABLES                NFNLGRP_NFTABLES
> +       NFNLGRP_ACCT_QUOTA,
> +#define NFNLGRP_ACCT_QUOTA             NFNLGRP_ACCT_QUOTA
>         __NFNLGRP_MAX,
>  };
>  #define NFNLGRP_MAX    (__NFNLGRP_MAX - 1)
> diff --git a/include/uapi/linux/netfilter/nfnetlink_acct.h b/include/uapi/linux/netfilter/nfnetlink_acct.h
> index c7b6269..51404ec 100644
> --- a/include/uapi/linux/netfilter/nfnetlink_acct.h
> +++ b/include/uapi/linux/netfilter/nfnetlink_acct.h
> @@ -10,15 +10,24 @@ enum nfnl_acct_msg_types {
>         NFNL_MSG_ACCT_GET,
>         NFNL_MSG_ACCT_GET_CTRZERO,
>         NFNL_MSG_ACCT_DEL,
> +       NFNL_MSG_ACCT_OVERQUOTA,
>         NFNL_MSG_ACCT_MAX
>  };
>
> +enum nfnl_acct_flags {
> +       NFACCT_F_QUOTA_PKTS     = (1 << 0),
> +       NFACCT_F_QUOTA_BYTES    = (1 << 1),
> +       NFACCT_F_OVERQUOTA      = (1 << 2), /* can't be set from userspace */
> +};
> +
>  enum nfnl_acct_type {
>         NFACCT_UNSPEC,
>         NFACCT_NAME,
>         NFACCT_PKTS,
>         NFACCT_BYTES,
>         NFACCT_USE,
> +       NFACCT_FLAGS,
> +       NFACCT_QUOTA,
>         __NFACCT_MAX
>  };
>  #define NFACCT_MAX (__NFACCT_MAX - 1)
> diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c
> index c7b6d46..ab583af 100644
> --- a/net/netfilter/nfnetlink_acct.c
> +++ b/net/netfilter/nfnetlink_acct.c
> @@ -32,18 +32,24 @@ static LIST_HEAD(nfnl_acct_list);
>  struct nf_acct {
>         atomic64_t              pkts;
>         atomic64_t              bytes;
> +       unsigned long           flags;
>         struct list_head        head;
>         atomic_t                refcnt;
>         char                    name[NFACCT_NAME_MAX];
>         struct rcu_head         rcu_head;
> +       char                    data[0];
>  };
>
> +#define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES)
> +
>  static int
>  nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb,
>              const struct nlmsghdr *nlh, const struct nlattr * const tb[])
>  {
>         struct nf_acct *nfacct, *matching = NULL;
>         char *acct_name;
> +       unsigned int size = 0;
> +       u32 flags = 0;
>
>         if (!tb[NFACCT_NAME])
>                 return -EINVAL;
> @@ -68,15 +74,39 @@ nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb,
>                         /* reset counters if you request a replacement. */
>                         atomic64_set(&matching->pkts, 0);
>                         atomic64_set(&matching->bytes, 0);
> +                       smp_mb__before_clear_bit();
> +                       /* reset overquota flag if quota is enabled. */
> +                       if ((matching->flags & NFACCT_F_QUOTA))
> +                               clear_bit(NFACCT_F_OVERQUOTA, &matching->flags);
>                         return 0;
>                 }
>                 return -EBUSY;
>         }
>
>         nfacct = kzalloc(sizeof(struct nf_acct), GFP_KERNEL);
> +       if (tb[NFACCT_FLAGS]) {
> +               flags = ntohl(nla_get_be32(tb[NFACCT_FLAGS]));
> +               if (flags & ~NFACCT_F_QUOTA)
> +                       return -EOPNOTSUPP;
> +               if ((flags & NFACCT_F_QUOTA) == NFACCT_F_QUOTA)
> +                       return -EINVAL;
> +               if (flags & NFACCT_F_OVERQUOTA)
> +                       return -EINVAL;
> +
> +               size += sizeof(u64);
> +       }
> +
> +       nfacct = kzalloc(sizeof(struct nf_acct) + size, GFP_KERNEL);
>         if (nfacct == NULL)
>                 return -ENOMEM;
>
> +       if (flags & NFACCT_F_QUOTA) {
> +               u64 *quota = (u64 *)nfacct->data;
> +
> +               *quota = be64_to_cpu(nla_get_be64(tb[NFACCT_QUOTA]));
> +               nfacct->flags = flags;
> +       }
> +
>         strncpy(nfacct->name, nla_data(tb[NFACCT_NAME]), NFACCT_NAME_MAX);
>
>         if (tb[NFACCT_BYTES]) {
> @@ -117,6 +147,10 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
>         if (type == NFNL_MSG_ACCT_GET_CTRZERO) {
>                 pkts = atomic64_xchg(&acct->pkts, 0);
>                 bytes = atomic64_xchg(&acct->bytes, 0);
> +               smp_mb__before_clear_bit();
> +               if (acct->flags & NFACCT_F_QUOTA) {
> +                       clear_bit(NFACCT_F_OVERQUOTA, &acct->flags);
> +               }
>         } else {
>                 pkts = atomic64_read(&acct->pkts);
>                 bytes = atomic64_read(&acct->bytes);
> @@ -125,7 +159,13 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
>             nla_put_be64(skb, NFACCT_BYTES, cpu_to_be64(bytes)) ||
>             nla_put_be32(skb, NFACCT_USE, htonl(atomic_read(&acct->refcnt))))
>                 goto nla_put_failure;
> +       if (acct->flags & NFACCT_F_QUOTA) {
> +               u64 *quota = (u64 *)acct->data;
>
> +               if (nla_put_be32(skb, NFACCT_FLAGS, htonl(acct->flags)) ||
> +                   nla_put_be64(skb, NFACCT_QUOTA, cpu_to_be64(*quota)))
> +                       goto nla_put_failure;
> +       }
>         nlmsg_end(skb, nlh);
>         return skb->len;
>
> @@ -270,6 +310,8 @@ static const struct nla_policy nfnl_acct_policy[NFACCT_MAX+1] = {
>         [NFACCT_NAME] = { .type = NLA_NUL_STRING, .len = NFACCT_NAME_MAX-1 },
>         [NFACCT_BYTES] = { .type = NLA_U64 },
>         [NFACCT_PKTS] = { .type = NLA_U64 },
> +       [NFACCT_FLAGS] = { .type = NLA_U32 },
> +       [NFACCT_QUOTA] = { .type = NLA_U64 },
>  };
>
>  static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = {
> @@ -336,6 +378,50 @@ void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct)
>  }
>  EXPORT_SYMBOL_GPL(nfnl_acct_update);
>
> +static void nfnl_overquota_report(struct nf_acct *nfacct)
> +{
> +       int ret;
> +       struct sk_buff *skb;
> +
> +       skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
> +       if (skb == NULL)
> +               return;
> +
> +       ret = nfnl_acct_fill_info(skb, 0, 0, NFNL_MSG_ACCT_OVERQUOTA, 0,
> +                                 nfacct);
> +       if (ret <= 0) {
> +               kfree_skb(skb);
> +               return;
> +       }
> +       netlink_broadcast(init_net.nfnl, skb, 0, NFNLGRP_ACCT_QUOTA,
> +                         GFP_ATOMIC);
> +}
> +
> +int nfnl_acct_overquota(const struct sk_buff *skb, struct nf_acct *nfacct)
> +{
> +       u64 now;
> +       u64 *quota;
> +       int ret = NFACCT_UNDERQUOTA;
> +
> +       /* no place here if we don't have a quota */
> +       if (!(nfacct->flags & NFACCT_F_QUOTA))
> +               return NFACCT_NO_QUOTA;
> +
> +       quota = (u64 *)nfacct->data;
> +       now = (nfacct->flags & NFACCT_F_QUOTA_PKTS) ?
> +              atomic64_read(&nfacct->pkts) : atomic64_read(&nfacct->bytes);
> +
> +       ret = now > *quota;
> +
> +       if (now >= *quota &&
> +           !test_and_set_bit(NFACCT_F_OVERQUOTA, &nfacct->flags)) {
> +               nfnl_overquota_report(nfacct);
> +       }
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(nfnl_acct_overquota);
> +
>  static int __init nfnl_acct_init(void)
>  {
>         int ret;
> diff --git a/net/netfilter/xt_nfacct.c b/net/netfilter/xt_nfacct.c
> index b3be0ef..8c646ed 100644
> --- a/net/netfilter/xt_nfacct.c
> +++ b/net/netfilter/xt_nfacct.c
> @@ -21,11 +21,14 @@ MODULE_ALIAS("ip6t_nfacct");
>
>  static bool nfacct_mt(const struct sk_buff *skb, struct xt_action_param *par)
>  {
> +       int overquota;
>         const struct xt_nfacct_match_info *info = par->targinfo;
>
>         nfnl_acct_update(skb, info->nfacct);
>
> -       return true;
> +       overquota = nfnl_acct_overquota(skb, info->nfacct);
> +
> +       return overquota == NFACCT_UNDERQUOTA ? false : true;
>  }
>
>  static int
> --
> 1.8.3.2
>
--
To unsubscribe from this list: send the line "unsubscribe netfilter" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Netfilter Development]     [Linux Kernel Networking Development]     [Netem]     [Berkeley Packet Filter]     [Linux Kernel Development]     [Advanced Routing & Traffice Control]     [Bugtraq]

  Powered by Linux