* [PATCH nft 1/3] src: add per-bytes limit
@ 2015-09-22 11:02 Pablo Neira Ayuso
2015-09-22 11:02 ` [PATCH nft 2/3] src: add burst parameter to limit Pablo Neira Ayuso
2015-09-22 11:02 ` [PATCH nft 3/3] tests: limit: extend them to validate new bytes/second and burst parameters Pablo Neira Ayuso
0 siblings, 2 replies; 3+ messages in thread
From: Pablo Neira Ayuso @ 2015-09-22 11:02 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber, fw
This example show how to accept packets below the ratelimit:
... limit rate 1024 mbytes/second counter accept
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/datatype.h | 4 +++
include/linux/netfilter/nf_tables.h | 9 ++++++
include/statement.h | 1 +
src/datatype.c | 55 +++++++++++++++++++++++++++++++++++
src/netlink_delinearize.c | 1 +
src/netlink_linearize.c | 1 +
src/parser_bison.y | 17 +++++++++++
src/statement.c | 43 +++++++++++++++++++++++++--
8 files changed, 129 insertions(+), 2 deletions(-)
diff --git a/include/datatype.h b/include/datatype.h
index 2a6a4fc..ebafa65 100644
--- a/include/datatype.h
+++ b/include/datatype.h
@@ -235,4 +235,8 @@ extern void time_print(uint64_t seconds);
extern struct error_record *time_parse(const struct location *loc,
const char *c, uint64_t *res);
+extern struct error_record *rate_parse(const struct location *loc,
+ const char *str, uint64_t *rate,
+ uint64_t *unit);
+
#endif /* NFTABLES_DATATYPE_H */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 33056dc..db0457d 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -747,16 +747,25 @@ enum nft_ct_attributes {
};
#define NFTA_CT_MAX (__NFTA_CT_MAX - 1)
+enum nft_limit_type {
+ NFT_LIMIT_PKTS,
+ NFT_LIMIT_PKT_BYTES
+};
+
/**
* enum nft_limit_attributes - nf_tables limit expression netlink attributes
*
* @NFTA_LIMIT_RATE: refill rate (NLA_U64)
* @NFTA_LIMIT_UNIT: refill unit (NLA_U64)
+ * @NFTA_LIMIT_BURST: burst (NLA_U32)
+ * @NFTA_LIMIT_TYPE: type of limit (NLA_U32: enum nft_limit_type)
*/
enum nft_limit_attributes {
NFTA_LIMIT_UNSPEC,
NFTA_LIMIT_RATE,
NFTA_LIMIT_UNIT,
+ NFTA_LIMIT_BURST,
+ NFTA_LIMIT_TYPE,
__NFTA_LIMIT_MAX
};
#define NFTA_LIMIT_MAX (__NFTA_LIMIT_MAX - 1)
diff --git a/include/statement.h b/include/statement.h
index 48e6130..d2d0852 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -51,6 +51,7 @@ extern struct stmt *log_stmt_alloc(const struct location *loc);
struct limit_stmt {
uint64_t rate;
uint64_t unit;
+ enum nft_limit_type type;
};
extern struct stmt *limit_stmt_alloc(const struct location *loc);
diff --git a/src/datatype.c b/src/datatype.c
index f79f5d2..e5a486f 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -976,3 +976,58 @@ void concat_type_destroy(const struct datatype *dtype)
xfree(dtype);
}
}
+
+static struct error_record *time_unit_parse(const struct location *loc,
+ const char *str, uint64_t *unit)
+{
+ if (strcmp(str, "second") == 0)
+ *unit = 1ULL;
+ else if (strcmp(str, "minute") == 0)
+ *unit = 1ULL * 60;
+ else if (strcmp(str, "hour") == 0)
+ *unit = 1ULL * 60 * 60;
+ else if (strcmp(str, "day") == 0)
+ *unit = 1ULL * 60 * 60 * 24;
+ else if (strcmp(str, "week") == 0)
+ *unit = 1ULL * 60 * 60 * 24 * 7;
+ else
+ return error(loc, "Wrong rate format");
+
+ return NULL;
+}
+
+static struct error_record *data_unit_parse(const struct location *loc,
+ const char *str, uint64_t *rate)
+{
+ if (strncmp(str, "bytes", strlen("bytes")) == 0)
+ *rate = 1ULL;
+ else if (strncmp(str, "kbytes", strlen("kbytes")) == 0)
+ *rate = 1024;
+ else if (strncmp(str, "mbytes", strlen("mbytes")) == 0)
+ *rate = 1024 * 1024;
+ else
+ return error(loc, "Wrong rate format");
+
+ return NULL;
+}
+
+struct error_record *rate_parse(const struct location *loc, const char *str,
+ uint64_t *rate, uint64_t *unit)
+{
+ struct error_record *erec;
+ const char *slash;
+
+ slash = strchr(str, '/');
+ if (!slash)
+ return error(loc, "wrong rate format");
+
+ erec = data_unit_parse(loc, str, rate);
+ if (erec != NULL)
+ return erec;
+
+ erec = time_unit_parse(loc, slash + 1, unit);
+ if (erec != NULL)
+ return erec;
+
+ return NULL;
+}
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 787eec7..569763b 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -583,6 +583,7 @@ static void netlink_parse_limit(struct netlink_parse_ctx *ctx,
stmt = limit_stmt_alloc(loc);
stmt->limit.rate = nftnl_expr_get_u64(nle, NFTNL_EXPR_LIMIT_RATE);
stmt->limit.unit = nftnl_expr_get_u64(nle, NFTNL_EXPR_LIMIT_UNIT);
+ stmt->limit.type = nftnl_expr_get_u32(nle, NFTNL_EXPR_LIMIT_TYPE);
list_add_tail(&stmt->list, &ctx->rule->stmts);
}
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 707df49..cebd2f1 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -656,6 +656,7 @@ static void netlink_gen_limit_stmt(struct netlink_linearize_ctx *ctx,
nle = alloc_nft_expr("limit");
nftnl_expr_set_u64(nle, NFTNL_EXPR_LIMIT_RATE, stmt->limit.rate);
nftnl_expr_set_u64(nle, NFTNL_EXPR_LIMIT_UNIT, stmt->limit.unit);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LIMIT_TYPE, stmt->limit.type);
nftnl_rule_add_expr(ctx->nlr, nle);
}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index cfb6b70..ec44a2c 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -1446,6 +1446,23 @@ limit_stmt : LIMIT RATE NUM SLASH time_unit
$$ = limit_stmt_alloc(&@$);
$$->limit.rate = $3;
$$->limit.unit = $5;
+ $$->limit.type = NFT_LIMIT_PKTS;
+ }
+ | LIMIT RATE NUM STRING
+ {
+ struct error_record *erec;
+ uint64_t rate, unit;
+
+ erec = rate_parse(&@$, $4, &rate, &unit);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+
+ $$ = limit_stmt_alloc(&@$);
+ $$->limit.rate = rate * $3;
+ $$->limit.unit = unit;
+ $$->limit.type = NFT_LIMIT_PKT_BYTES;
}
;
diff --git a/src/statement.c b/src/statement.c
index 9ebc593..ba7b8be 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -185,10 +185,49 @@ static const char *get_unit(uint64_t u)
return "error";
}
+static const char *data_unit[] = {
+ "bytes",
+ "kbytes",
+ "mbytes",
+ NULL
+};
+
+static const char *get_rate(uint64_t byte_rate, uint64_t *rate)
+{
+ uint64_t res, prev, rest;
+ int i;
+
+ res = prev = byte_rate;
+ for (i = 0;; i++) {
+ rest = res % 1024;
+ res /= 1024;
+ if (res <= 1 && rest != 0)
+ break;
+ if (data_unit[i + 1] == NULL)
+ break;
+ prev = res;
+ }
+ *rate = prev;
+ return data_unit[i];
+}
+
static void limit_stmt_print(const struct stmt *stmt)
{
- printf("limit rate %" PRIu64 "/%s",
- stmt->limit.rate, get_unit(stmt->limit.unit));
+ const char *data_unit;
+ uint64_t rate;
+
+ switch (stmt->limit.type) {
+ case NFT_LIMIT_PKTS:
+ printf("limit rate %" PRIu64 "/%s",
+ stmt->limit.rate, get_unit(stmt->limit.unit));
+ break;
+ case NFT_LIMIT_PKT_BYTES:
+ data_unit = get_rate(stmt->limit.rate, &rate);
+
+ printf("limit rate %" PRIu64 " %s/%s",
+ rate, data_unit, get_unit(stmt->limit.unit));
+ break;
+ }
}
static const struct stmt_ops limit_stmt_ops = {
--
1.7.10.4
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH nft 2/3] src: add burst parameter to limit
2015-09-22 11:02 [PATCH nft 1/3] src: add per-bytes limit Pablo Neira Ayuso
@ 2015-09-22 11:02 ` Pablo Neira Ayuso
2015-09-22 11:02 ` [PATCH nft 3/3] tests: limit: extend them to validate new bytes/second and burst parameters Pablo Neira Ayuso
1 sibling, 0 replies; 3+ messages in thread
From: Pablo Neira Ayuso @ 2015-09-22 11:02 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber, fw
... limit rate 1024 mbytes/second burst 10240 bytes
... limit rate 1/second burst 3 packets
This parameter is optional.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/datatype.h | 3 +++
include/statement.h | 1 +
src/datatype.c | 4 ++--
src/netlink_delinearize.c | 1 +
src/netlink_linearize.c | 4 ++++
src/parser_bison.y | 26 +++++++++++++++++++++++---
src/scanner.l | 1 +
src/statement.c | 8 ++++++++
8 files changed, 43 insertions(+), 5 deletions(-)
diff --git a/include/datatype.h b/include/datatype.h
index ebafa65..07fedce 100644
--- a/include/datatype.h
+++ b/include/datatype.h
@@ -239,4 +239,7 @@ extern struct error_record *rate_parse(const struct location *loc,
const char *str, uint64_t *rate,
uint64_t *unit);
+extern struct error_record *data_unit_parse(const struct location *loc,
+ const char *str, uint64_t *rate);
+
#endif /* NFTABLES_DATATYPE_H */
diff --git a/include/statement.h b/include/statement.h
index d2d0852..bead0a6 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -52,6 +52,7 @@ struct limit_stmt {
uint64_t rate;
uint64_t unit;
enum nft_limit_type type;
+ uint32_t burst;
};
extern struct stmt *limit_stmt_alloc(const struct location *loc);
diff --git a/src/datatype.c b/src/datatype.c
index e5a486f..f56763b 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -996,8 +996,8 @@ static struct error_record *time_unit_parse(const struct location *loc,
return NULL;
}
-static struct error_record *data_unit_parse(const struct location *loc,
- const char *str, uint64_t *rate)
+struct error_record *data_unit_parse(const struct location *loc,
+ const char *str, uint64_t *rate)
{
if (strncmp(str, "bytes", strlen("bytes")) == 0)
*rate = 1ULL;
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 569763b..ede9302 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -584,6 +584,7 @@ static void netlink_parse_limit(struct netlink_parse_ctx *ctx,
stmt->limit.rate = nftnl_expr_get_u64(nle, NFTNL_EXPR_LIMIT_RATE);
stmt->limit.unit = nftnl_expr_get_u64(nle, NFTNL_EXPR_LIMIT_UNIT);
stmt->limit.type = nftnl_expr_get_u32(nle, NFTNL_EXPR_LIMIT_TYPE);
+ stmt->limit.burst = nftnl_expr_get_u32(nle, NFTNL_EXPR_LIMIT_BURST);
list_add_tail(&stmt->list, &ctx->rule->stmts);
}
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index cebd2f1..447219f 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -657,6 +657,10 @@ static void netlink_gen_limit_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u64(nle, NFTNL_EXPR_LIMIT_RATE, stmt->limit.rate);
nftnl_expr_set_u64(nle, NFTNL_EXPR_LIMIT_UNIT, stmt->limit.unit);
nftnl_expr_set_u32(nle, NFTNL_EXPR_LIMIT_TYPE, stmt->limit.type);
+ if (stmt->limit.burst > 0)
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LIMIT_BURST,
+ stmt->limit.burst);
+
nftnl_rule_add_expr(ctx->nlr, nle);
}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index ec44a2c..385e214 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -364,6 +364,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token LIMIT "limit"
%token RATE "rate"
+%token BURST "burst"
%token NANOSECOND "nanosecond"
%token MICROSECOND "microsecond"
@@ -450,7 +451,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <val> level_type
%type <stmt> limit_stmt
%destructor { stmt_free($$); } limit_stmt
-%type <val> time_unit
+%type <val> limit_burst time_unit
%type <stmt> reject_stmt reject_stmt_alloc
%destructor { stmt_free($$); } reject_stmt reject_stmt_alloc
%type <stmt> nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc
@@ -1441,14 +1442,15 @@ level_type : LEVEL_EMERG { $$ = LOG_EMERG; }
| LEVEL_DEBUG { $$ = LOG_DEBUG; }
;
-limit_stmt : LIMIT RATE NUM SLASH time_unit
+limit_stmt : LIMIT RATE NUM SLASH time_unit limit_burst
{
$$ = limit_stmt_alloc(&@$);
$$->limit.rate = $3;
$$->limit.unit = $5;
+ $$->limit.burst = $6;
$$->limit.type = NFT_LIMIT_PKTS;
}
- | LIMIT RATE NUM STRING
+ | LIMIT RATE NUM STRING limit_burst
{
struct error_record *erec;
uint64_t rate, unit;
@@ -1462,10 +1464,28 @@ limit_stmt : LIMIT RATE NUM SLASH time_unit
$$ = limit_stmt_alloc(&@$);
$$->limit.rate = rate * $3;
$$->limit.unit = unit;
+ $$->limit.burst = $5;
$$->limit.type = NFT_LIMIT_PKT_BYTES;
}
;
+limit_burst : /* empty */ { $$ = 0; }
+ | BURST NUM PACKETS { $$ = $2; }
+ | BURST NUM BYTES { $$ = $2; }
+ | BURST NUM STRING
+ {
+ struct error_record *erec;
+ uint64_t rate;
+
+ erec = data_unit_parse(&@$, $3, &rate);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+ $$ = $2 * rate;
+ }
+ ;
+
time_unit : SECOND { $$ = 1ULL; }
| MINUTE { $$ = 1ULL * 60; }
| HOUR { $$ = 1ULL * 60 * 60; }
diff --git a/src/scanner.l b/src/scanner.l
index 2d9871d..bd8e572 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -309,6 +309,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"limit" { return LIMIT; }
"rate" { return RATE; }
+"burst" { return BURST; }
"nanosecond" { return NANOSECOND; }
"microsecond" { return MICROSECOND; }
diff --git a/src/statement.c b/src/statement.c
index ba7b8be..d620d1b 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -220,12 +220,20 @@ static void limit_stmt_print(const struct stmt *stmt)
case NFT_LIMIT_PKTS:
printf("limit rate %" PRIu64 "/%s",
stmt->limit.rate, get_unit(stmt->limit.unit));
+ if (stmt->limit.burst > 0)
+ printf(" burst %u packets", stmt->limit.burst);
break;
case NFT_LIMIT_PKT_BYTES:
data_unit = get_rate(stmt->limit.rate, &rate);
printf("limit rate %" PRIu64 " %s/%s",
rate, data_unit, get_unit(stmt->limit.unit));
+ if (stmt->limit.burst > 0) {
+ uint64_t burst;
+
+ data_unit = get_rate(stmt->limit.burst, &burst);
+ printf(" burst %"PRIu64" %s", burst, data_unit);
+ }
break;
}
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH nft 3/3] tests: limit: extend them to validate new bytes/second and burst parameters
2015-09-22 11:02 [PATCH nft 1/3] src: add per-bytes limit Pablo Neira Ayuso
2015-09-22 11:02 ` [PATCH nft 2/3] src: add burst parameter to limit Pablo Neira Ayuso
@ 2015-09-22 11:02 ` Pablo Neira Ayuso
1 sibling, 0 replies; 3+ messages in thread
From: Pablo Neira Ayuso @ 2015-09-22 11:02 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber, fw
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
tests/regression/any/limit.t | 15 +++++++++-
tests/regression/any/limit.t.payload | 54 ++++++++++++++++++++++++++++++----
2 files changed, 63 insertions(+), 6 deletions(-)
diff --git a/tests/regression/any/limit.t b/tests/regression/any/limit.t
index 9af1ea8..96ffe60 100644
--- a/tests/regression/any/limit.t
+++ b/tests/regression/any/limit.t
@@ -8,5 +8,18 @@
limit rate 400/minute;ok
limit rate 20/second;ok
limit rate 400/hour;ok
-limit rate 400/week;ok
limit rate 40/day;ok
+limit rate 400/week;ok
+limit rate 1023/second burst 10 packets;ok
+
+limit rate 1 kbytes/second;ok
+limit rate 2 kbytes/second;ok
+limit rate 1025 kbytes/second;ok
+limit rate 1023 mbytes/second;ok
+limit rate 10230 mbytes/second;ok
+limit rate 1023000 mbytes/second;ok
+
+limit rate 1025 bytes/second burst 512 bytes;ok
+limit rate 1025 kbytes/second burst 1023 kbytes;ok
+limit rate 1025 mbytes/second burst 1025 kbytes;ok
+limit rate 1025000 mbytes/second burst 1023 mbytes;ok
diff --git a/tests/regression/any/limit.t.payload b/tests/regression/any/limit.t.payload
index c196f12..a3c87d8 100644
--- a/tests/regression/any/limit.t.payload
+++ b/tests/regression/any/limit.t.payload
@@ -1,20 +1,64 @@
# limit rate 400/minute
ip test-ip4 output
- [ limit rate 400/minute ]
+ [ limit rate 400/minute burst 0 type packets ]
# limit rate 20/second
ip test-ip4 output
- [ limit rate 20/second ]
+ [ limit rate 20/second burst 0 type packets ]
# limit rate 400/hour
ip test-ip4 output
- [ limit rate 400/hour ]
+ [ limit rate 400/hour burst 0 type packets ]
# limit rate 400/week
ip test-ip4 output
- [ limit rate 400/week ]
+ [ limit rate 400/week burst 0 type packets ]
# limit rate 40/day
ip test-ip4 output
- [ limit rate 40/day ]
+ [ limit rate 40/day burst 0 type packets ]
+
+# limit rate 1023/second burst 10 packets
+ip test-ip4 output
+ [ limit rate 1023/second burst 10 type packets ]
+
+# limit rate 1 kbytes/second
+ip test-ip4 output
+ [ limit rate 1024/second burst 0 type bytes ]
+
+# limit rate 2 kbytes/second
+ip test-ip4 output
+ [ limit rate 2048/second burst 0 type bytes ]
+
+# limit rate 1025 kbytes/second
+ip test-ip4 output
+ [ limit rate 1049600/second burst 0 type bytes ]
+
+# limit rate 1023 mbytes/second
+ip test-ip4 output
+ [ limit rate 1072693248/second burst 0 type bytes ]
+
+# limit rate 10230 mbytes/second
+ip test-ip4 output
+ [ limit rate 10726932480/second burst 0 type bytes ]
+
+# limit rate 1023000 mbytes/second
+ip test-ip4 output
+ [ limit rate 1072693248000/second burst 0 type bytes ]
+
+# limit rate 1025 bytes/second burst 512 bytes
+ip test-ip4 output
+ [ limit rate 1025/second burst 512 type bytes ]
+
+# limit rate 1025 kbytes/second burst 1023 kbytes
+ip test-ip4 output
+ [ limit rate 1049600/second burst 1047552 type bytes ]
+
+# limit rate 1025 mbytes/second burst 1025 kbytes
+ip test-ip4 output
+ [ limit rate 1074790400/second burst 1049600 type bytes ]
+
+# limit rate 1025000 mbytes/second burst 1023 mbytes
+ip test-ip4 output
+ [ limit rate 1074790400000/second burst 1072693248 type bytes ]
--
1.7.10.4
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2015-09-22 10:55 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-09-22 11:02 [PATCH nft 1/3] src: add per-bytes limit Pablo Neira Ayuso
2015-09-22 11:02 ` [PATCH nft 2/3] src: add burst parameter to limit Pablo Neira Ayuso
2015-09-22 11:02 ` [PATCH nft 3/3] tests: limit: extend them to validate new bytes/second and burst parameters Pablo Neira Ayuso
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).