summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/expression.h1
-rw-r--r--include/hash.h2
-rw-r--r--include/linux/netfilter/nf_tables.h13
-rw-r--r--src/evaluate.c3
-rw-r--r--src/hash.c28
-rw-r--r--src/netlink_delinearize.c35
-rw-r--r--src/netlink_linearize.c19
-rw-r--r--src/parser_bison.y16
-rw-r--r--src/scanner.l1
-rw-r--r--tests/py/ip/hash.t1
-rw-r--r--tests/py/ip/hash.t.payload4
11 files changed, 87 insertions, 36 deletions
diff --git a/include/expression.h b/include/expression.h
index 83ecf111..4f2948cc 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -309,6 +309,7 @@ struct expr {
uint32_t mod;
uint32_t seed;
uint32_t offset;
+ enum nft_hash_types type;
} hash;
struct {
/* EXPR_FIB */
diff --git a/include/hash.h b/include/hash.h
index 8bf53e2e..7f9c6f13 100644
--- a/include/hash.h
+++ b/include/hash.h
@@ -3,6 +3,6 @@
extern struct expr *hash_expr_alloc(const struct location *loc,
uint32_t modulus, uint32_t seed,
- uint32_t offset);
+ uint32_t offset, enum nft_hash_types type);
#endif /* NFTABLES_HASH_H */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 05215d30..4f7d7568 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -816,6 +816,17 @@ enum nft_rt_keys {
};
/**
+ * enum nft_hash_types - nf_tables hash expression types
+ *
+ * @NFT_HASH_JENKINS: Jenkins Hash
+ * @NFT_HASH_SYM: Symmetric Hash
+ */
+enum nft_hash_types {
+ NFT_HASH_JENKINS,
+ NFT_HASH_SYM,
+};
+
+/**
* enum nft_hash_attributes - nf_tables hash expression netlink attributes
*
* @NFTA_HASH_SREG: source register (NLA_U32)
@@ -824,6 +835,7 @@ enum nft_rt_keys {
* @NFTA_HASH_MODULUS: modulus value (NLA_U32)
* @NFTA_HASH_SEED: seed value (NLA_U32)
* @NFTA_HASH_OFFSET: add this offset value to hash result (NLA_U32)
+ * @NFTA_HASH_TYPE: hash operation (NLA_U32: nft_hash_types)
*/
enum nft_hash_attributes {
NFTA_HASH_UNSPEC,
@@ -833,6 +845,7 @@ enum nft_hash_attributes {
NFTA_HASH_MODULUS,
NFTA_HASH_SEED,
NFTA_HASH_OFFSET,
+ NFTA_HASH_TYPE,
__NFTA_HASH_MAX,
};
#define NFTA_HASH_MAX (__NFTA_HASH_MAX - 1)
diff --git a/src/evaluate.c b/src/evaluate.c
index 54985166..efcafc72 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1288,7 +1288,8 @@ static int expr_evaluate_hash(struct eval_ctx *ctx, struct expr **exprp)
expr_dtype_integer_compatible(ctx, expr);
expr_set_context(&ctx->ectx, NULL, 0);
- if (expr_evaluate(ctx, &expr->hash.expr) < 0)
+ if (expr->hash.expr &&
+ expr_evaluate(ctx, &expr->hash.expr) < 0)
return -1;
/* expr_evaluate_primary() sets the context to what to the input
diff --git a/src/hash.c b/src/hash.c
index d26b2eda..a7a96122 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -17,10 +17,18 @@
static void hash_expr_print(const struct expr *expr)
{
- printf("jhash ");
- expr_print(expr->hash.expr);
+ switch (expr->hash.type) {
+ case NFT_HASH_SYM:
+ printf("symhash");
+ break;
+ case NFT_HASH_JENKINS:
+ default:
+ printf("jhash ");
+ expr_print(expr->hash.expr);
+ }
+
printf(" mod %u", expr->hash.mod);
- if (expr->hash.seed)
+ if (expr->hash.type & NFT_HASH_JENKINS && expr->hash.seed)
printf(" seed 0x%x", expr->hash.seed);
if (expr->hash.offset)
printf(" offset %u", expr->hash.offset);
@@ -28,18 +36,22 @@ static void hash_expr_print(const struct expr *expr)
static bool hash_expr_cmp(const struct expr *e1, const struct expr *e2)
{
- return expr_cmp(e1->hash.expr, e2->hash.expr) &&
+ return (e1->hash.expr ||
+ expr_cmp(e1->hash.expr, e2->hash.expr)) &&
e1->hash.mod == e2->hash.mod &&
e1->hash.seed == e2->hash.seed &&
- e1->hash.offset == e2->hash.offset;
+ e1->hash.offset == e2->hash.offset &&
+ e1->hash.type == e2->hash.type;
}
static void hash_expr_clone(struct expr *new, const struct expr *expr)
{
- new->hash.expr = expr_clone(expr->hash.expr);
+ if (expr->hash.expr)
+ new->hash.expr = expr_clone(expr->hash.expr);
new->hash.mod = expr->hash.mod;
new->hash.seed = expr->hash.seed;
new->hash.offset = expr->hash.offset;
+ new->hash.type = expr->hash.type;
}
static const struct expr_ops hash_expr_ops = {
@@ -51,7 +63,8 @@ static const struct expr_ops hash_expr_ops = {
};
struct expr *hash_expr_alloc(const struct location *loc, uint32_t mod,
- uint32_t seed, uint32_t offset)
+ uint32_t seed, uint32_t offset,
+ enum nft_hash_types type)
{
struct expr *expr;
@@ -60,6 +73,7 @@ struct expr *hash_expr_alloc(const struct location *loc, uint32_t mod,
expr->hash.mod = mod;
expr->hash.seed = seed;
expr->hash.offset = offset;
+ expr->hash.type = type;
return expr;
}
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 39347e01..36e8fe3c 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -523,27 +523,33 @@ static void netlink_parse_hash(struct netlink_parse_ctx *ctx,
enum nft_registers sreg, dreg;
struct expr *expr, *hexpr;
uint32_t mod, seed, len, offset;
+ enum nft_hash_types type;
- sreg = netlink_parse_register(nle, NFTNL_EXPR_HASH_SREG);
- hexpr = netlink_get_register(ctx, loc, sreg);
- if (hexpr == NULL)
- return netlink_error(ctx, loc,
- "hash statement has no expression");
-
+ type = nftnl_expr_get_u32(nle, NFTNL_EXPR_HASH_TYPE);
offset = nftnl_expr_get_u32(nle, NFTNL_EXPR_HASH_OFFSET);
seed = nftnl_expr_get_u32(nle, NFTNL_EXPR_HASH_SEED);
mod = nftnl_expr_get_u32(nle, NFTNL_EXPR_HASH_MODULUS);
- len = nftnl_expr_get_u32(nle, NFTNL_EXPR_HASH_LEN) * BITS_PER_BYTE;
- if (hexpr->len < len) {
- hexpr = netlink_parse_concat_expr(ctx, loc, sreg, len);
+ expr = hash_expr_alloc(loc, mod, seed, offset, type);
+
+ if (type != NFT_HASH_SYM) {
+ sreg = netlink_parse_register(nle, NFTNL_EXPR_HASH_SREG);
+ hexpr = netlink_get_register(ctx, loc, sreg);
+
if (hexpr == NULL)
- return;
+ return
+ netlink_error(ctx, loc,
+ "hash statement has no expression");
+ len = nftnl_expr_get_u32(nle,
+ NFTNL_EXPR_HASH_LEN) * BITS_PER_BYTE;
+ if (hexpr->len < len) {
+ hexpr = netlink_parse_concat_expr(ctx, loc, sreg, len);
+ if (hexpr == NULL)
+ return;
+ }
+ expr->hash.expr = hexpr;
}
- expr = hash_expr_alloc(loc, mod, seed, offset);
- expr->hash.expr = hexpr;
-
dreg = netlink_parse_register(nle, NFTNL_EXPR_HASH_DREG);
netlink_set_register(ctx, dreg, expr);
}
@@ -1826,7 +1832,8 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
case EXPR_FIB:
break;
case EXPR_HASH:
- expr_postprocess(ctx, &expr->hash.expr);
+ if (expr->hash.expr)
+ expr_postprocess(ctx, &expr->hash.expr);
break;
case EXPR_CT:
ct_expr_update_type(&ctx->pctx, expr);
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 48f34c25..293150e2 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -125,18 +125,23 @@ static void netlink_gen_hash(struct netlink_linearize_ctx *ctx,
enum nft_registers sreg;
struct nftnl_expr *nle;
- sreg = get_register(ctx, expr->hash.expr);
- netlink_gen_expr(ctx, expr->hash.expr, sreg);
- release_register(ctx, expr->hash.expr);
-
nle = alloc_nft_expr("hash");
- netlink_put_register(nle, NFTNL_EXPR_HASH_SREG, sreg);
+
+ if (expr->hash.expr) {
+ sreg = get_register(ctx, expr->hash.expr);
+ netlink_gen_expr(ctx, expr->hash.expr, sreg);
+ release_register(ctx, expr->hash.expr);
+ netlink_put_register(nle, NFTNL_EXPR_HASH_SREG, sreg);
+
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_LEN,
+ div_round_up(expr->hash.expr->len,
+ BITS_PER_BYTE));
+ }
netlink_put_register(nle, NFTNL_EXPR_HASH_DREG, dreg);
- nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_LEN,
- div_round_up(expr->hash.expr->len, BITS_PER_BYTE));
nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_MODULUS, expr->hash.mod);
nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_SEED, expr->hash.seed);
nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_OFFSET, expr->hash.offset);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_TYPE, expr->hash.type);
nftnl_rule_add_expr(ctx->nlr, nle);
}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 15931e96..dff8a5ab 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -437,6 +437,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token OFFSET "offset"
%token JHASH "jhash"
+%token SYMHASH "symhash"
%token SEED "seed"
%token POSITION "position"
@@ -512,7 +513,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%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
%destructor { stmt_free($$); } nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc
-%type <val> nf_nat_flags nf_nat_flag offset_opt
+%type <val> nf_nat_flags nf_nat_flag offset_opt seed_opt
%type <stmt> queue_stmt queue_stmt_alloc
%destructor { stmt_free($$); } queue_stmt queue_stmt_alloc
%type <val> queue_stmt_flags queue_stmt_flag
@@ -2916,15 +2917,18 @@ numgen_expr : NUMGEN numgen_type MOD NUM offset_opt
}
;
-hash_expr : JHASH expr MOD NUM SEED NUM offset_opt
+seed_opt : /* empty */ { $$ = 0; }
+ | SEED NUM { $$ = $2; }
+ ;
+
+hash_expr : JHASH expr MOD NUM seed_opt offset_opt
{
- $$ = hash_expr_alloc(&@$, $4, $6, $7);
+ $$ = hash_expr_alloc(&@$, $4, $5, $6, NFT_HASH_JENKINS);
$$->hash.expr = $2;
}
- | JHASH expr MOD NUM offset_opt
+ | SYMHASH MOD NUM offset_opt
{
- $$ = hash_expr_alloc(&@$, $4, 0, $5);
- $$->hash.expr = $2;
+ $$ = hash_expr_alloc(&@$, $3, 0, $4, NFT_HASH_SYM);
}
;
diff --git a/src/scanner.l b/src/scanner.l
index b70e1a80..003f15eb 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -488,6 +488,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"offset" { return OFFSET; }
"jhash" { return JHASH; }
+"symhash" { return SYMHASH; }
"seed" { return SEED; }
"dup" { return DUP; }
diff --git a/tests/py/ip/hash.t b/tests/py/ip/hash.t
index 0d01a11d..2becef62 100644
--- a/tests/py/ip/hash.t
+++ b/tests/py/ip/hash.t
@@ -6,3 +6,4 @@ ct mark set jhash ip saddr . ip daddr mod 2;ok
ct mark set jhash ip saddr . ip daddr mod 2 seed 0xdeadbeef offset 100;ok
ct mark set jhash ip saddr . ip daddr mod 2 offset 100;ok
dnat to jhash ip saddr mod 2 seed 0xdeadbeef map { 0 : 192.168.20.100, 1 : 192.168.30.100 };ok
+ct mark set symhash mod 2 offset 100;ok
diff --git a/tests/py/ip/hash.t.payload b/tests/py/ip/hash.t.payload
index 8c28ad98..21227e91 100644
--- a/tests/py/ip/hash.t.payload
+++ b/tests/py/ip/hash.t.payload
@@ -36,3 +36,7 @@ ip test-ip4 pre
[ lookup reg 1 set __map%d dreg 1 ]
[ nat dnat ip addr_min reg 1 addr_max reg 0 ]
+# ct mark set symhash mod 2 offset 100
+ip test-ip4 pre
+ [ hash reg 1 = symhash() % mod 2 offset 100 ]
+ [ ct set mark with reg 1 ]