Iptables counters restore, when using quotas, not working as expected

The problem is a kernel bug.

In EL6 the quota code that does the matching shows this:

quota_mt(const struct sk_buff *skb, const struct xt_match_param *par)
{
        struct xt_quota_info *q = (void *)par->matchinfo;
        struct xt_quota_priv *priv = q->master;
        bool ret = q->flags & XT_QUOTA_INVERT;

        spin_lock_bh(&quota_lock);
        if (priv->quota >= skb->len) {
                priv->quota -= skb->len;
                ret = !ret;
        } else {
                /* we do not allow even small packets from now on */
                priv->quota = 0;
        }
        /* Copy quota back to matchinfo so that iptables can display it */
        q->quota = priv->quota;
        spin_unlock_bh(&quota_lock);

        return ret;

In F20 it shows this:

static bool
quota_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
  struct xt_quota_info *q = (void *)par->matchinfo;
  struct xt_quota_priv *priv = q->master;
  bool ret = q->flags & XT_QUOTA_INVERT;

  spin_lock_bh(&priv->lock);
  if (priv->quota >= skb->len) {
    priv->quota -= skb->len;
    ret = !ret;
  } else {
    /* we do not allow even small packets from now on */
    priv->quota = 0;
  }
  spin_unlock_bh(&priv->lock);

  return ret;
}

Its basically the same (minus spacing changes) apart from one line;

        /* Copy quota back to matchinfo so that iptables can display it */
        q->quota = priv->quota;

This is meant as a display parameter.

So in EL6 if you setup a quota, pass some packets through, then do iptables -vnL SOMECHAIN you'll notice the quota value decrements.

In F20 doing the same thing the value doesn't decrement. I guess the designers believe its probably a better thing to make sure people know what quota was set rather than what the quota really is (seeing as packet counts make it clear what is left).

However, this has an unintended effect. When you run iptables-save you save the quota value as read via iptables. In EL6, if this value reaches 0 it displays 0 to iptables. Thus, when you restore, you restore the 0 back into the iptables chain.

With them removing it, this value never decrements and thus you never actually save the quota.

What really needs to happen is the module needs redesigning. There should be a quota entry and a remaining entry. Remaining should decrement like in EL6 and be what is used to enforce the quota, whereas "quota" should be the actual set value like in F20. This way you get the best of both worlds. A saved state of the quota and a actual description of what quota is set.

You should probably report this to the netfilter team.