[libnftnl] expr: hash: Add offset to hash value
diff mbox

Message ID 20160905085500.GA21103@sonyv
State Accepted
Delegated to: Pablo Neira
Headers show

Commit Message

Laura Garcia Liebana Sept. 5, 2016, 8:55 a.m. UTC
Add support to pass through an offset to the hash value. With this
feature, the sysadmin is able to generate a hash with a given
started value.

Example:

	meta mark set jhash ip saddr mod 2 seed 0xabcd sum 100

This option generates marks according to the source address from 100 to
101.

Signed-off-by: Laura Garcia Liebana <nevola@gmail.com>
---
 include/libnftnl/expr.h             |  1 +
 include/linux/netfilter/nf_tables.h |  2 ++
 src/expr/hash.c                     | 39 +++++++++++++++++++++++++++++++------
 tests/nft-expr_hash-test.c          |  4 ++++
 4 files changed, 40 insertions(+), 6 deletions(-)

Patch
diff mbox

diff --git a/include/libnftnl/expr.h b/include/libnftnl/expr.h
index 3cf0db1..9188364 100644
--- a/include/libnftnl/expr.h
+++ b/include/libnftnl/expr.h
@@ -211,6 +211,7 @@  enum {
 	NFTNL_EXPR_HASH_LEN,
 	NFTNL_EXPR_HASH_MODULUS,
 	NFTNL_EXPR_HASH_SEED,
+	NFTNL_EXPR_HASH_SUM,
 };
 
 /*
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 2718832..65d9fe8 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -1139,6 +1139,7 @@  enum nft_trace_types {
  * @NFTA_HASH_LEN: data length (NLA_U32)
  * @NFTA_HASH_MODULUS: Modulus value (NLA_U32)
  * @NFTA_HASH_SEED: hash initial value (NLA_U32)
+ * @NFTA_HASH_SUM: offset value to be added (NLA_U32)
  */
 enum nft_hash_attributes {
 	NFTA_HASH_UNSPEC,
@@ -1147,6 +1148,7 @@  enum nft_hash_attributes {
 	NFTA_HASH_LEN,
 	NFTA_HASH_MODULUS,
 	NFTA_HASH_SEED,
+	NFTA_HASH_SUM,
 	__NFTA_HASH_MAX
 };
 #define NFTA_HASH_MAX		(__NFTA_HASH_MAX - 1)
diff --git a/src/expr/hash.c b/src/expr/hash.c
index 2d61508..54c6dbc 100644
--- a/src/expr/hash.c
+++ b/src/expr/hash.c
@@ -26,6 +26,7 @@  struct nftnl_expr_hash {
 	unsigned int		len;
 	unsigned int		modulus;
 	unsigned int		seed;
+	unsigned int		sum;
 };
 
 static int
@@ -50,6 +51,9 @@  nftnl_expr_hash_set(struct nftnl_expr *e, uint16_t type,
 	case NFTNL_EXPR_HASH_SEED:
 		hash->seed = *((uint32_t *)data);
 		break;
+	case NFTNL_EXPR_HASH_SUM:
+		hash->sum = *((uint32_t *)data);
+		break;
 	default:
 		return -1;
 	}
@@ -78,6 +82,9 @@  nftnl_expr_hash_get(const struct nftnl_expr *e, uint16_t type,
 	case NFTNL_EXPR_HASH_SEED:
 		*data_len = sizeof(hash->seed);
 		return &hash->seed;
+	case NFTNL_EXPR_HASH_SUM:
+		*data_len = sizeof(hash->sum);
+		return &hash->sum;
 	}
 	return NULL;
 }
@@ -96,6 +103,7 @@  static int nftnl_expr_hash_cb(const struct nlattr *attr, void *data)
 	case NFTA_HASH_LEN:
 	case NFTA_HASH_MODULUS:
 	case NFTA_HASH_SEED:
+	case NFTA_HASH_SUM:
 		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
 			abi_breakage();
 		break;
@@ -120,7 +128,8 @@  nftnl_expr_hash_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
 		mnl_attr_put_u32(nlh, NFTA_HASH_MODULUS, htonl(hash->modulus));
 	if (e->flags & (1 << NFTNL_EXPR_HASH_SEED))
 		mnl_attr_put_u32(nlh, NFTA_HASH_SEED, htonl(hash->seed));
-
+	if (e->flags & (1 << NFTNL_EXPR_HASH_SUM))
+		mnl_attr_put_u32(nlh, NFTA_HASH_SUM, htonl(hash->sum));
 }
 
 static int
@@ -153,6 +162,10 @@  nftnl_expr_hash_parse(struct nftnl_expr *e, struct nlattr *attr)
 		hash->seed = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_SEED]));
 		e->flags |= (1 << NFTNL_EXPR_HASH_SEED);
 	}
+	if (tb[NFTA_HASH_SUM]) {
+		hash->sum = ntohl(mnl_attr_get_u32(tb[NFTA_HASH_SUM]));
+		e->flags |= (1 << NFTNL_EXPR_HASH_SUM);
+	}
 
 	return ret;
 }
@@ -161,7 +174,7 @@  static int nftnl_expr_hash_json_parse(struct nftnl_expr *e, json_t *root,
 				      struct nftnl_parse_err *err)
 {
 #ifdef JSON_PARSING
-	uint32_t sreg, dreg, len, modulus, seed;
+	uint32_t sreg, dreg, len, modulus, seed, sum;
 
 	if (nftnl_jansson_parse_reg(root, "sreg", NFTNL_TYPE_U32,
 				    &sreg, err) == 0)
@@ -183,6 +196,10 @@  static int nftnl_expr_hash_json_parse(struct nftnl_expr *e, json_t *root,
 				    &seed, err) == 0)
 		nftnl_expr_set_u32(e, NFTNL_EXPR_HASH_SEED, seed);
 
+	if (nftnl_jansson_parse_val(root, "sum", NFTNL_TYPE_U32,
+				    &sum, err) == 0)
+		nftnl_expr_set_u32(e, NFTNL_EXPR_HASH_SUM, sum);
+
 	return 0;
 #else
 	errno = EOPNOTSUPP;
@@ -196,7 +213,7 @@  static int nftnl_expr_hash_xml_parse(struct nftnl_expr *e,
 				     struct nftnl_parse_err *err)
 {
 #ifdef XML_PARSING
-	uint32_t sreg, dreg, len, modulus, seed;
+	uint32_t sreg, dreg, len, modulus, seed, sum;
 
 	if (nftnl_mxml_reg_parse(tree, "sreg", &sreg, MXML_DESCEND_FIRST,
 				 NFTNL_XML_MAND, err) == 0)
@@ -221,6 +238,11 @@  static int nftnl_expr_hash_xml_parse(struct nftnl_expr *e,
 				 err) == 0)
 		nftnl_expr_set_u32(e, NFTNL_EXPR_HASH_SEED, seed);
 
+	if (nftnl_mxml_num_parse(tree, "sum", MXML_DESCEND_FIRST, BASE_DEC,
+				 &sum, NFTNL_TYPE_U32, NFTNL_XML_MAND,
+				 err) == 0)
+		nftnl_expr_set_u32(e, NFTNL_EXPR_HASH_SUM, sum);
+
 	return 0;
 #else
 	errno = EOPNOTSUPP;
@@ -235,9 +257,10 @@  nftnl_expr_hash_snprintf_default(char *buf, size_t size,
 	struct nftnl_expr_hash *hash = nftnl_expr_data(e);
 	int len = size, offset = 0, ret;
 
-	ret = snprintf(buf, len, "reg %u = jhash(reg %u, %u, 0x%x) %% mod %u ",
-		       hash->dreg, hash->sreg, hash->len, hash->seed,
-		       hash->modulus);
+	ret = snprintf(buf, len,
+		       "reg %u = %u + jhash(reg %u, %u, 0x%x) %% mod %u ",
+		       hash->sum, hash->dreg, hash->sreg, hash->len,
+		       hash->seed, hash->modulus);
 	SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
 	return offset;
@@ -260,6 +283,8 @@  static int nftnl_expr_hash_export(char *buf, size_t size,
 		nftnl_buf_u32(&b, type, hash->modulus, MODULUS);
 	if (e->flags & (1 << NFTNL_EXPR_HASH_SEED))
 		nftnl_buf_u32(&b, type, hash->seed, SEED);
+	if (e->flags & (1 << NFTNL_EXPR_HASH_SUM))
+		nftnl_buf_u32(&b, type, hash->sum, SUM);
 
 	return nftnl_buf_done(&b);
 }
@@ -297,6 +322,8 @@  static bool nftnl_expr_hash_cmp(const struct nftnl_expr *e1,
                eq &= (h1->modulus == h2->modulus);
        if (e1->flags & (1 << NFTNL_EXPR_HASH_SEED))
                eq &= (h1->seed == h2->seed);
+	if (e1->flags & (1 << NFTNL_EXPR_HASH_SUM))
+		eq &= (h1->sum == h2->sum);
 
        return eq;
 }
diff --git a/tests/nft-expr_hash-test.c b/tests/nft-expr_hash-test.c
index 699197c..52c494e 100644
--- a/tests/nft-expr_hash-test.c
+++ b/tests/nft-expr_hash-test.c
@@ -42,6 +42,9 @@  static void cmp_nftnl_expr(struct nftnl_expr *rule_a,
 	if (nftnl_expr_get_u32(rule_a, NFTNL_EXPR_HASH_SEED) !=
 	    nftnl_expr_get_u32(rule_b, NFTNL_EXPR_HASH_SEED))
 		print_err("Expr NFTNL_EXPR_HASH_SEED mismatches");
+	if (nftnl_expr_get_u32(rule_a, NFTNL_EXPR_HASH_SUM) !=
+	    nftnl_expr_get_u32(rule_b, NFTNL_EXPR_HASH_SUM))
+		print_err("Expr NFTNL_EXPR_HASH_SUM mismatches");
 }
 
 int main(int argc, char *argv[])
@@ -65,6 +68,7 @@  int main(int argc, char *argv[])
 	nftnl_expr_set_u32(ex, NFTNL_EXPR_HASH_DREG, 0x78123456);
 	nftnl_expr_set_u32(ex, NFTNL_EXPR_HASH_MODULUS, 0x78123456);
 	nftnl_expr_set_u32(ex, NFTNL_EXPR_HASH_SEED, 0x78123456);
+	nftnl_expr_set_u32(ex, NFTNL_EXPR_HASH_SUM, 0x1234568);
 
 	nftnl_rule_add_expr(a, ex);