From e91ea14da66759c71d5c2a581b82c2508a02f60a Mon Sep 17 00:00:00 2001 From: Phil Oester Date: Tue, 22 Oct 2013 10:48:22 +0200 Subject: expr: limit: operational limit match The nft limit match currently does not work at all. Below patches to nftables, libnftables, and kernel address the issue. A few notes on the implementation: - Removed support for nano/micro/milli second limits. These seem pointless, given we are using jiffies in the limit match, not a hpet. And who really needs to limit items down to sub-second level?? - 'depth' member is removed as unnecessary. All we need in the kernel is the rate and the unit. - 'stamp' member becomes the time we need to next refresh the token bucket, instead of being updated on every packet which goes through the match. This closes netfilter bugzilla #827, reported by Eric Leblond. Signed-off-by: Phil Oester Signed-off-by: Pablo Neira Ayuso --- include/libnftables/expr.h | 2 +- include/linux/netfilter/nf_tables.h | 4 +-- src/expr/limit.c | 51 +++++++++++++++++++++---------------- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/include/libnftables/expr.h b/include/libnftables/expr.h index b8f1d1e..232a810 100644 --- a/include/libnftables/expr.h +++ b/include/libnftables/expr.h @@ -134,7 +134,7 @@ enum { enum { NFT_EXPR_LIMIT_RATE = NFT_RULE_EXPR_ATTR_BASE, - NFT_EXPR_LIMIT_DEPTH, + NFT_EXPR_LIMIT_UNIT, }; #ifdef __cplusplus diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h index b690282..4ec8187 100644 --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -537,12 +537,12 @@ enum nft_ct_attributes { * enum nft_limit_attributes - nf_tables limit expression netlink attributes * * @NFTA_LIMIT_RATE: refill rate (NLA_U64) - * @NFTA_LIMIT_DEPTH: bucket depth (NLA_U64) + * @NFTA_LIMIT_UNIT: refill unit (NLA_U64) */ enum nft_limit_attributes { NFTA_LIMIT_UNSPEC, NFTA_LIMIT_RATE, - NFTA_LIMIT_DEPTH, + NFTA_LIMIT_UNIT, __NFTA_LIMIT_MAX }; #define NFTA_LIMIT_MAX (__NFTA_LIMIT_MAX - 1) diff --git a/src/expr/limit.c b/src/expr/limit.c index bdb0414..9718171 100644 --- a/src/expr/limit.c +++ b/src/expr/limit.c @@ -25,7 +25,7 @@ struct nft_expr_limit { uint64_t rate; - uint64_t depth; + uint64_t unit; }; static int @@ -38,8 +38,8 @@ nft_rule_expr_limit_set(struct nft_rule_expr *e, uint16_t type, case NFT_EXPR_LIMIT_RATE: limit->rate = *((uint64_t *)data); break; - case NFT_EXPR_LIMIT_DEPTH: - limit->depth = *((uint64_t *)data); + case NFT_EXPR_LIMIT_UNIT: + limit->unit = *((uint64_t *)data); break; default: return -1; @@ -57,9 +57,9 @@ nft_rule_expr_limit_get(const struct nft_rule_expr *e, uint16_t type, case NFT_EXPR_LIMIT_RATE: *data_len = sizeof(uint64_t); return &limit->rate; - case NFT_EXPR_LIMIT_DEPTH: + case NFT_EXPR_LIMIT_UNIT: *data_len = sizeof(uint64_t); - return &limit->depth; + return &limit->unit; } return NULL; } @@ -74,7 +74,7 @@ static int nft_rule_expr_limit_cb(const struct nlattr *attr, void *data) switch(type) { case NFTA_LIMIT_RATE: - case NFTA_LIMIT_DEPTH: + case NFTA_LIMIT_UNIT: if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) { perror("mnl_attr_validate"); return MNL_CB_ERROR; @@ -93,8 +93,8 @@ nft_rule_expr_limit_build(struct nlmsghdr *nlh, struct nft_rule_expr *e) if (e->flags & (1 << NFT_EXPR_LIMIT_RATE)) mnl_attr_put_u64(nlh, NFTA_LIMIT_RATE, htobe64(limit->rate)); - if (e->flags & (1 << NFT_EXPR_LIMIT_DEPTH)) - mnl_attr_put_u64(nlh, NFTA_LIMIT_DEPTH, htobe64(limit->depth)); + if (e->flags & (1 << NFT_EXPR_LIMIT_UNIT)) + mnl_attr_put_u64(nlh, NFTA_LIMIT_UNIT, htobe64(limit->unit)); } static int @@ -110,9 +110,9 @@ nft_rule_expr_limit_parse(struct nft_rule_expr *e, struct nlattr *attr) limit->rate = be64toh(mnl_attr_get_u64(tb[NFTA_LIMIT_RATE])); e->flags |= (1 << NFT_EXPR_LIMIT_RATE); } - if (tb[NFTA_LIMIT_DEPTH]) { - limit->depth = be64toh(mnl_attr_get_u64(tb[NFTA_LIMIT_DEPTH])); - e->flags |= (1 << NFT_EXPR_LIMIT_DEPTH); + if (tb[NFTA_LIMIT_UNIT]) { + limit->unit = be64toh(mnl_attr_get_u64(tb[NFTA_LIMIT_UNIT])); + e->flags |= (1 << NFT_EXPR_LIMIT_UNIT); } return 0; @@ -128,10 +128,10 @@ static int nft_rule_expr_limit_json_parse(struct nft_rule_expr *e, json_t *root) nft_rule_expr_set_u64(e, NFT_EXPR_LIMIT_RATE, uval64); - if (nft_jansson_parse_val(root, "depth", NFT_TYPE_U64, &uval64) < 0) + if (nft_jansson_parse_val(root, "unit", NFT_TYPE_U64, &uval64) < 0) return -1; - nft_rule_expr_set_u64(e, NFT_EXPR_LIMIT_DEPTH, uval64); + nft_rule_expr_set_u64(e, NFT_EXPR_LIMIT_UNIT, uval64); return 0; #else @@ -151,11 +151,11 @@ static int nft_rule_expr_limit_xml_parse(struct nft_rule_expr *e, mxml_node_t *t e->flags |= (1 << NFT_EXPR_LIMIT_RATE); - if (nft_mxml_num_parse(tree, "depth", MXML_DESCEND_FIRST, BASE_DEC, - &limit->depth, NFT_TYPE_U64, NFT_XML_MAND) != 0) + if (nft_mxml_num_parse(tree, "unit", MXML_DESCEND_FIRST, BASE_DEC, + &limit->unit, NFT_TYPE_U64, NFT_XML_MAND) != 0) return -1; - e->flags |= (1 << NFT_EXPR_LIMIT_DEPTH); + e->flags |= (1 << NFT_EXPR_LIMIT_UNIT); return 0; #else @@ -169,19 +169,26 @@ nft_rule_expr_limit_snprintf(char *buf, size_t len, uint32_t type, uint32_t flags, struct nft_rule_expr *e) { struct nft_expr_limit *limit = nft_expr_data(e); + static const char *units[] = { + [1] = "second", + [1 * 60] = "minute", + [1 * 60 * 60] = "hour", + [1 * 60 * 60 * 24] = "day", + [1 * 60 * 60 * 24 * 7] = "week", + }; switch(type) { case NFT_RULE_O_DEFAULT: - return snprintf(buf, len, "rate %"PRIu64" depth %"PRIu64" ", - limit->rate, limit->depth); + return snprintf(buf, len, "rate %"PRIu64"/%s ", + limit->rate, units[limit->unit]); case NFT_RULE_O_XML: return snprintf(buf, len, "%"PRIu64"" - "%"PRIu64"", - limit->rate, limit->depth); + "%"PRIu64"", + limit->rate, limit->unit); case NFT_RULE_O_JSON: return snprintf(buf, len, "\"rate\":%"PRIu64"," - "\"depth\":%"PRIu64"", - limit->rate, limit->depth); + "\"unit\":%"PRIu64"", + limit->rate, limit->unit); default: break; } -- cgit v1.2.3