Commit 3e0f64b7 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

netfilter: nft_limit: fix packet ratelimiting

Credit calculations for the packet ratelimiting are not correct, as per
the applied ratelimit of 25/second and burst 8, a total of 33 packets
should have been accepted.  This is true in iptables(33) but not in
nftables (~65). For packet ratelimiting, use:

	div_u64(limit->nsecs, limit->rate) * limit->burst;

to calculate credit, just like in iptables' xt_limit does.

Moreover, use default burst in iptables, users are expecting similar
behaviour.
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 97a0549b
...@@ -51,10 +51,13 @@ static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost) ...@@ -51,10 +51,13 @@ static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost)
return !limit->invert; return !limit->invert;
} }
/* Use same default as in iptables. */
#define NFT_LIMIT_PKT_BURST_DEFAULT 5
static int nft_limit_init(struct nft_limit *limit, static int nft_limit_init(struct nft_limit *limit,
const struct nlattr * const tb[]) const struct nlattr * const tb[], bool pkts)
{ {
u64 unit; u64 unit, tokens;
if (tb[NFTA_LIMIT_RATE] == NULL || if (tb[NFTA_LIMIT_RATE] == NULL ||
tb[NFTA_LIMIT_UNIT] == NULL) tb[NFTA_LIMIT_UNIT] == NULL)
...@@ -68,18 +71,25 @@ static int nft_limit_init(struct nft_limit *limit, ...@@ -68,18 +71,25 @@ static int nft_limit_init(struct nft_limit *limit,
if (tb[NFTA_LIMIT_BURST]) if (tb[NFTA_LIMIT_BURST])
limit->burst = ntohl(nla_get_be32(tb[NFTA_LIMIT_BURST])); limit->burst = ntohl(nla_get_be32(tb[NFTA_LIMIT_BURST]));
else
limit->burst = 0; if (pkts && limit->burst == 0)
limit->burst = NFT_LIMIT_PKT_BURST_DEFAULT;
if (limit->rate + limit->burst < limit->rate) if (limit->rate + limit->burst < limit->rate)
return -EOVERFLOW; return -EOVERFLOW;
if (pkts) {
tokens = div_u64(limit->nsecs, limit->rate) * limit->burst;
} else {
/* The token bucket size limits the number of tokens can be /* The token bucket size limits the number of tokens can be
* accumulated. tokens_max specifies the bucket size. * accumulated. tokens_max specifies the bucket size.
* tokens_max = unit * (rate + burst) / rate. * tokens_max = unit * (rate + burst) / rate.
*/ */
limit->tokens = div_u64(limit->nsecs * (limit->rate + limit->burst), tokens = div_u64(limit->nsecs * (limit->rate + limit->burst),
limit->rate); limit->rate);
}
limit->tokens = tokens;
limit->tokens_max = limit->tokens; limit->tokens_max = limit->tokens;
if (tb[NFTA_LIMIT_FLAGS]) { if (tb[NFTA_LIMIT_FLAGS]) {
...@@ -144,7 +154,7 @@ static int nft_limit_pkts_init(const struct nft_ctx *ctx, ...@@ -144,7 +154,7 @@ static int nft_limit_pkts_init(const struct nft_ctx *ctx,
struct nft_limit_pkts *priv = nft_expr_priv(expr); struct nft_limit_pkts *priv = nft_expr_priv(expr);
int err; int err;
err = nft_limit_init(&priv->limit, tb); err = nft_limit_init(&priv->limit, tb, true);
if (err < 0) if (err < 0)
return err; return err;
...@@ -185,7 +195,7 @@ static int nft_limit_bytes_init(const struct nft_ctx *ctx, ...@@ -185,7 +195,7 @@ static int nft_limit_bytes_init(const struct nft_ctx *ctx,
{ {
struct nft_limit *priv = nft_expr_priv(expr); struct nft_limit *priv = nft_expr_priv(expr);
return nft_limit_init(priv, tb); return nft_limit_init(priv, tb, false);
} }
static int nft_limit_bytes_dump(struct sk_buff *skb, static int nft_limit_bytes_dump(struct sk_buff *skb,
...@@ -246,7 +256,7 @@ static int nft_limit_obj_pkts_init(const struct nft_ctx *ctx, ...@@ -246,7 +256,7 @@ static int nft_limit_obj_pkts_init(const struct nft_ctx *ctx,
struct nft_limit_pkts *priv = nft_obj_data(obj); struct nft_limit_pkts *priv = nft_obj_data(obj);
int err; int err;
err = nft_limit_init(&priv->limit, tb); err = nft_limit_init(&priv->limit, tb, true);
if (err < 0) if (err < 0)
return err; return err;
...@@ -289,7 +299,7 @@ static int nft_limit_obj_bytes_init(const struct nft_ctx *ctx, ...@@ -289,7 +299,7 @@ static int nft_limit_obj_bytes_init(const struct nft_ctx *ctx,
{ {
struct nft_limit *priv = nft_obj_data(obj); struct nft_limit *priv = nft_obj_data(obj);
return nft_limit_init(priv, tb); return nft_limit_init(priv, tb, false);
} }
static int nft_limit_obj_bytes_dump(struct sk_buff *skb, static int nft_limit_obj_bytes_dump(struct sk_buff *skb,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment