diff options
| author | Pablo Neira Ayuso <pablo@netfilter.org> | 2018-05-16 16:58:33 -0400 |
|---|---|---|
| committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2018-05-23 03:50:28 -0400 |
| commit | 3e0f64b7dd3149f75e8652ff1df56cffeedc8fc1 (patch) | |
| tree | f5ed936c6660e06ceda2ccace703f2b3993c0df3 | |
| parent | 97a0549b15a0b466c47f6a0143a490a082c64b4e (diff) | |
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: Pablo Neira Ayuso <pablo@netfilter.org>
| -rw-r--r-- | net/netfilter/nft_limit.c | 38 |
1 files changed, 24 insertions, 14 deletions
diff --git a/net/netfilter/nft_limit.c b/net/netfilter/nft_limit.c index a9fc298ef4c3..72f13a1144dd 100644 --- a/net/netfilter/nft_limit.c +++ b/net/netfilter/nft_limit.c | |||
| @@ -51,10 +51,13 @@ static inline bool nft_limit_eval(struct nft_limit *limit, u64 cost) | |||
| 51 | return !limit->invert; | 51 | return !limit->invert; |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | /* Use same default as in iptables. */ | ||
| 55 | #define NFT_LIMIT_PKT_BURST_DEFAULT 5 | ||
| 56 | |||
| 54 | static int nft_limit_init(struct nft_limit *limit, | 57 | static int nft_limit_init(struct nft_limit *limit, |
| 55 | const struct nlattr * const tb[]) | 58 | const struct nlattr * const tb[], bool pkts) |
| 56 | { | 59 | { |
| 57 | u64 unit; | 60 | u64 unit, tokens; |
| 58 | 61 | ||
| 59 | if (tb[NFTA_LIMIT_RATE] == NULL || | 62 | if (tb[NFTA_LIMIT_RATE] == NULL || |
| 60 | tb[NFTA_LIMIT_UNIT] == NULL) | 63 | tb[NFTA_LIMIT_UNIT] == NULL) |
| @@ -68,18 +71,25 @@ static int nft_limit_init(struct nft_limit *limit, | |||
| 68 | 71 | ||
| 69 | if (tb[NFTA_LIMIT_BURST]) | 72 | if (tb[NFTA_LIMIT_BURST]) |
| 70 | limit->burst = ntohl(nla_get_be32(tb[NFTA_LIMIT_BURST])); | 73 | limit->burst = ntohl(nla_get_be32(tb[NFTA_LIMIT_BURST])); |
| 71 | else | 74 | |
| 72 | limit->burst = 0; | 75 | if (pkts && limit->burst == 0) |
| 76 | limit->burst = NFT_LIMIT_PKT_BURST_DEFAULT; | ||
| 73 | 77 | ||
| 74 | if (limit->rate + limit->burst < limit->rate) | 78 | if (limit->rate + limit->burst < limit->rate) |
| 75 | return -EOVERFLOW; | 79 | return -EOVERFLOW; |
| 76 | 80 | ||
| 77 | /* The token bucket size limits the number of tokens can be | 81 | if (pkts) { |
| 78 | * accumulated. tokens_max specifies the bucket size. | 82 | tokens = div_u64(limit->nsecs, limit->rate) * limit->burst; |
| 79 | * tokens_max = unit * (rate + burst) / rate. | 83 | } else { |
| 80 | */ | 84 | /* The token bucket size limits the number of tokens can be |
| 81 | limit->tokens = div_u64(limit->nsecs * (limit->rate + limit->burst), | 85 | * accumulated. tokens_max specifies the bucket size. |
| 82 | limit->rate); | 86 | * tokens_max = unit * (rate + burst) / rate. |
| 87 | */ | ||
| 88 | tokens = div_u64(limit->nsecs * (limit->rate + limit->burst), | ||
| 89 | limit->rate); | ||
| 90 | } | ||
| 91 | |||
| 92 | limit->tokens = tokens; | ||
| 83 | limit->tokens_max = limit->tokens; | 93 | limit->tokens_max = limit->tokens; |
| 84 | 94 | ||
| 85 | if (tb[NFTA_LIMIT_FLAGS]) { | 95 | if (tb[NFTA_LIMIT_FLAGS]) { |
| @@ -144,7 +154,7 @@ static int nft_limit_pkts_init(const struct nft_ctx *ctx, | |||
| 144 | struct nft_limit_pkts *priv = nft_expr_priv(expr); | 154 | struct nft_limit_pkts *priv = nft_expr_priv(expr); |
| 145 | int err; | 155 | int err; |
| 146 | 156 | ||
| 147 | err = nft_limit_init(&priv->limit, tb); | 157 | err = nft_limit_init(&priv->limit, tb, true); |
| 148 | if (err < 0) | 158 | if (err < 0) |
| 149 | return err; | 159 | return err; |
| 150 | 160 | ||
| @@ -185,7 +195,7 @@ static int nft_limit_bytes_init(const struct nft_ctx *ctx, | |||
| 185 | { | 195 | { |
| 186 | struct nft_limit *priv = nft_expr_priv(expr); | 196 | struct nft_limit *priv = nft_expr_priv(expr); |
| 187 | 197 | ||
| 188 | return nft_limit_init(priv, tb); | 198 | return nft_limit_init(priv, tb, false); |
| 189 | } | 199 | } |
| 190 | 200 | ||
| 191 | static int nft_limit_bytes_dump(struct sk_buff *skb, | 201 | 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 | struct nft_limit_pkts *priv = nft_obj_data(obj); | 256 | struct nft_limit_pkts *priv = nft_obj_data(obj); |
| 247 | int err; | 257 | int err; |
| 248 | 258 | ||
| 249 | err = nft_limit_init(&priv->limit, tb); | 259 | err = nft_limit_init(&priv->limit, tb, true); |
| 250 | if (err < 0) | 260 | if (err < 0) |
| 251 | return err; | 261 | return err; |
| 252 | 262 | ||
| @@ -289,7 +299,7 @@ static int nft_limit_obj_bytes_init(const struct nft_ctx *ctx, | |||
| 289 | { | 299 | { |
| 290 | struct nft_limit *priv = nft_obj_data(obj); | 300 | struct nft_limit *priv = nft_obj_data(obj); |
| 291 | 301 | ||
| 292 | return nft_limit_init(priv, tb); | 302 | return nft_limit_init(priv, tb, false); |
| 293 | } | 303 | } |
| 294 | 304 | ||
| 295 | static int nft_limit_obj_bytes_dump(struct sk_buff *skb, | 305 | static int nft_limit_obj_bytes_dump(struct sk_buff *skb, |
