]> git.ipfire.org Git - thirdparty/libnftnl.git/commitdiff
src: Implement rule comparison
authorCarlos Falgueras García <carlosfg@riseup.net>
Wed, 17 Aug 2016 14:07:09 +0000 (16:07 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 17 Aug 2016 14:08:06 +0000 (16:08 +0200)
This patch implements the function:

bool nftnl_rule_cmp(const struct nftnl_rule *r1,
    const struct nftnl_rule *r2)

for rule comparison.

Expressions within rules need to be compared, so also has been created the
function:

bool nftnl_expr_cmp(const struct nftnl_expr *e1,
    const struct nftnl_expr *e2);

Also includes all expression comparators.

Signed-off-by: Carlos Falgueras García <carlosfg@riseup.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
31 files changed:
include/data_reg.h
include/expr_ops.h
include/libnftnl/expr.h
include/libnftnl/rule.h
src/expr.c
src/expr/bitwise.c
src/expr/byteorder.c
src/expr/cmp.c
src/expr/counter.c
src/expr/ct.c
src/expr/data_reg.c
src/expr/dup.c
src/expr/dynset.c
src/expr/exthdr.c
src/expr/fwd.c
src/expr/hash.c
src/expr/immediate.c
src/expr/limit.c
src/expr/log.c
src/expr/lookup.c
src/expr/masq.c
src/expr/match.c
src/expr/meta.c
src/expr/nat.c
src/expr/payload.c
src/expr/queue.c
src/expr/redir.c
src/expr/reject.c
src/expr/target.c
src/libnftnl.map
src/rule.c

index e749b5ba91eabb62be6fccf50c96ef1c5866571d..3fec7cdaa3173f26e987ebfce186fd44fa22af54 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/netfilter/nf_tables.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include <unistd.h>
 
 enum {
@@ -27,6 +28,8 @@ int nftnl_data_reg_snprintf(char *buf, size_t size,
                            const union nftnl_data_reg *reg,
                            uint32_t output_format, uint32_t flags,
                            int reg_type);
+bool nftnl_data_reg_cmp(const union nftnl_data_reg *r1,
+                       const union nftnl_data_reg *r2, int reg_type);
 struct nlattr;
 
 int nftnl_parse_data(union nftnl_data_reg *data, struct nlattr *attr, int *type);
index 3c0cb186d94abf86e828fa2b4d12447dc17126b1..a334732dd26d0ec4834512fec86bfc5f6459c82d 100644 (file)
@@ -13,6 +13,7 @@ struct expr_ops {
        uint32_t alloc_len;
        int     max_attr;
        void    (*free)(const struct nftnl_expr *e);
+       bool    (*cmp)(const struct nftnl_expr *e1, const struct nftnl_expr *e2);
        int     (*set)(struct nftnl_expr *e, uint16_t type, const void *data, uint32_t data_len);
        const void *(*get)(const struct nftnl_expr *e, uint16_t type, uint32_t *data_len);
        int     (*parse)(struct nftnl_expr *e, struct nlattr *attr);
index 1efe31caf405f5046fa48983f74402e612bac401..5dd5e104b624668e72fced7dcbe646f49e17b1ce 100644 (file)
@@ -36,6 +36,8 @@ uint32_t nftnl_expr_get_u32(const struct nftnl_expr *expr, uint16_t type);
 uint64_t nftnl_expr_get_u64(const struct nftnl_expr *expr, uint16_t type);
 const char *nftnl_expr_get_str(const struct nftnl_expr *expr, uint16_t type);
 
+bool nftnl_expr_cmp(const struct nftnl_expr *e1, const struct nftnl_expr *e2);
+
 int nftnl_expr_snprintf(char *buf, size_t buflen, const struct nftnl_expr *expr, uint32_t type, uint32_t flags);
 
 enum {
index e3bd6b893765d102d2de722bf2b3bc90b978fe10..adeedf26c8f24e4dc073c635d44650aa9fbde20a 100644 (file)
@@ -50,6 +50,8 @@ uint64_t nftnl_rule_get_u64(const struct nftnl_rule *r, uint16_t attr);
 
 void nftnl_rule_add_expr(struct nftnl_rule *r, struct nftnl_expr *expr);
 
+bool nftnl_rule_cmp(const struct nftnl_rule *r1, const struct nftnl_rule *r2);
+
 struct nlmsghdr;
 
 void nftnl_rule_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_rule *t);
index e5c1dd321a2a5c4469e3dd9bc75122998774bedb..51413ab70397820f97f9d6036faad8cc48c61520 100644 (file)
@@ -203,6 +203,16 @@ const char *nftnl_expr_get_str(const struct nftnl_expr *expr, uint16_t type)
 }
 EXPORT_SYMBOL_ALIAS(nftnl_expr_get_str, nft_rule_expr_get_str);
 
+bool nftnl_expr_cmp(const struct nftnl_expr *e1, const struct nftnl_expr *e2)
+{
+       if (e1->flags != e2->flags ||
+           strcmp(e1->ops->name, e2->ops->name) != 0)
+               return false;
+
+       return e1->ops->cmp(e1, e2);
+}
+EXPORT_SYMBOL(nftnl_expr_cmp);
+
 void
 nftnl_expr_build_payload(struct nlmsghdr *nlh, struct nftnl_expr *expr)
 {
index 2fd4b7417c871d43f9f623b74818fe67ccd56fd5..9cc9347b5d3aaa9c01d8491ee1da74b8551b4db8 100644 (file)
@@ -310,10 +310,32 @@ nftnl_expr_bitwise_snprintf(char *buf, size_t size, uint32_t type,
        return -1;
 }
 
+static bool nftnl_expr_bitwise_cmp(const struct nftnl_expr *e1,
+                                  const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_bitwise *b1 = nftnl_expr_data(e1);
+       struct nftnl_expr_bitwise *b2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_BITWISE_SREG))
+               eq &= (b1->sreg == b2->sreg);
+       if (e1->flags & (1 << NFTNL_EXPR_BITWISE_DREG))
+               eq &= (b1->dreg == b2->dreg);
+       if (e1->flags & (1 << NFTNL_EXPR_BITWISE_LEN))
+               eq &= (b1->len == b2->len);
+       if (e1->flags & (1 << NFTNL_EXPR_BITWISE_MASK))
+               eq &= nftnl_data_reg_cmp(&b1->mask, &b2->mask, DATA_VALUE);
+       if (e1->flags & (1 << NFTNL_EXPR_BITWISE_XOR))
+               eq &= nftnl_data_reg_cmp(&b1->xor, &b2->xor, DATA_VALUE);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_bitwise = {
        .name           = "bitwise",
        .alloc_len      = sizeof(struct nftnl_expr_bitwise),
        .max_attr       = NFTA_BITWISE_MAX,
+       .cmp            = nftnl_expr_bitwise_cmp,
        .set            = nftnl_expr_bitwise_set,
        .get            = nftnl_expr_bitwise_get,
        .parse          = nftnl_expr_bitwise_parse,
index ca697cffe69f8ae6b3b406c4a38b11b1e96e3546..a7914efc0b7b9f1f3acc3d464dfce6e1e71498df 100644 (file)
@@ -326,10 +326,32 @@ nftnl_expr_byteorder_snprintf(char *buf, size_t size, uint32_t type,
        return -1;
 }
 
+static bool nftnl_expr_byteorder_cmp(const struct nftnl_expr *e1,
+                                    const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_byteorder *b1 = nftnl_expr_data(e1);
+       struct nftnl_expr_byteorder *b2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_BYTEORDER_SREG))
+               eq &= (b1->sreg == b2->sreg);
+       if (e1->flags & (1 << NFTNL_EXPR_BYTEORDER_DREG))
+               eq &= (b1->dreg == b2->dreg);
+       if (e1->flags & (1 << NFTNL_EXPR_BYTEORDER_OP))
+               eq &= (b1->op == b2->op);
+       if (e1->flags & (1 << NFTNL_EXPR_BYTEORDER_LEN))
+               eq &= (b1->len == b2->len);
+       if (e1->flags & (1 << NFTNL_EXPR_BYTEORDER_SIZE))
+               eq &= (b1->size == b2->size);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_byteorder = {
        .name           = "byteorder",
        .alloc_len      = sizeof(struct nftnl_expr_byteorder),
        .max_attr       = NFTA_BYTEORDER_MAX,
+       .cmp            = nftnl_expr_byteorder_cmp,
        .set            = nftnl_expr_byteorder_set,
        .get            = nftnl_expr_byteorder_get,
        .parse          = nftnl_expr_byteorder_parse,
index 5d51958cb3f181975f2ad8dd5497e75bab87331e..a46c15af99860181fdf124a3f336fe1067e62aca 100644 (file)
@@ -293,10 +293,28 @@ nftnl_expr_cmp_snprintf(char *buf, size_t size, uint32_t type,
        return -1;
 }
 
+static bool nftnl_expr_cmp_cmp(const struct nftnl_expr *e1,
+                              const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_cmp *c1 = nftnl_expr_data(e1);
+       struct nftnl_expr_cmp *c2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_CMP_DATA))
+               eq &= nftnl_data_reg_cmp(&c1->data, &c2->data, DATA_VALUE);
+       if (e1->flags & (1 << NFTNL_EXPR_CMP_SREG))
+               eq &= (c1->sreg == c2->sreg);
+       if (e1->flags & (1 << NFTNL_EXPR_CMP_OP))
+               eq &= (c1->op == c2->op);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_cmp = {
        .name           = "cmp",
        .alloc_len      = sizeof(struct nftnl_expr_cmp),
        .max_attr       = NFTA_CMP_MAX,
+       .cmp            = nftnl_expr_cmp_cmp,
        .set            = nftnl_expr_cmp_set,
        .get            = nftnl_expr_cmp_get,
        .parse          = nftnl_expr_cmp_parse,
index 1f818c422a0540bc5207b32e482c6957be717a23..4488afc4ee28e4a3f5a336550350ecd0a2226b62 100644 (file)
@@ -198,10 +198,26 @@ static int nftnl_expr_counter_snprintf(char *buf, size_t len, uint32_t type,
        return -1;
 }
 
+static bool nftnl_expr_counter_cmp(const struct nftnl_expr *e1,
+                                  const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_counter *c1 = nftnl_expr_data(e1);
+       struct nftnl_expr_counter *c2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_CTR_PACKETS))
+               eq &= (c1->pkts == c2->pkts);
+       if (e1->flags & (1 << NFTNL_EXPR_CTR_BYTES))
+               eq &= (c1->pkts == c2->pkts);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_counter = {
        .name           = "counter",
        .alloc_len      = sizeof(struct nftnl_expr_counter),
        .max_attr       = NFTA_COUNTER_MAX,
+       .cmp            = nftnl_expr_counter_cmp,
        .set            = nftnl_expr_counter_set,
        .get            = nftnl_expr_counter_get,
        .parse          = nftnl_expr_counter_parse,
index 1a53b49fde0ad97c8f588e7d4ac4f7d2c75e988c..013789163c1705ade41304e4b901486b96614a16 100644 (file)
@@ -373,10 +373,30 @@ nftnl_expr_ct_snprintf(char *buf, size_t len, uint32_t type,
        return -1;
 }
 
+static bool nftnl_expr_ct_cmp(const struct nftnl_expr *e1,
+                             const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_ct *c1 = nftnl_expr_data(e1);
+       struct nftnl_expr_ct *c2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_CT_KEY))
+               eq &= (c1->key == c2->key);
+       if (e1->flags & (1 << NFTNL_EXPR_CT_DREG))
+               eq &= (c1->dreg == c2->dreg);
+       if (e1->flags & (1 << NFTNL_EXPR_CT_SREG))
+               eq &= (c1->sreg == c2->sreg);
+       if (e1->flags & (1 << NFTNL_EXPR_CT_DIR))
+               eq &= (c1->dir == c2->dir);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_ct = {
        .name           = "ct",
        .alloc_len      = sizeof(struct nftnl_expr_ct),
        .max_attr       = NFTA_CT_MAX,
+       .cmp            = nftnl_expr_ct_cmp,
        .set            = nftnl_expr_ct_set,
        .get            = nftnl_expr_ct_get,
        .parse          = nftnl_expr_ct_parse,
index 688823bc85d8d41ce5fca6916591755a2d8f9669..a954e9539957fef47dab94505e1dad6c4648dbb2 100644 (file)
@@ -379,6 +379,22 @@ int nftnl_data_reg_snprintf(char *buf, size_t size,
        return -1;
 }
 
+bool nftnl_data_reg_cmp(const union nftnl_data_reg *r1,
+                       const union nftnl_data_reg *r2, int reg_type)
+{
+       switch (reg_type) {
+       case DATA_VALUE:
+               return  r1->len == r2->len &&
+                       !memcmp(r1->val, r2->val, r1->len);
+       case DATA_VERDICT:
+       case DATA_CHAIN:
+               return  r1->verdict == r2->verdict &&
+                       !strcmp(r1->chain, r2->chain);
+       default:
+               return false;
+       }
+}
+
 static int nftnl_data_parse_cb(const struct nlattr *attr, void *data)
 {
        const struct nlattr **tb = data;
index 694db32bb9cbeb20e5c8c1e06893e4231c3af7aa..ac1923c16e161b329abd35df4e9bc83fba9ea015 100644 (file)
@@ -202,10 +202,26 @@ static int nftnl_expr_dup_snprintf(char *buf, size_t len, uint32_t type,
        return -1;
 }
 
+static bool nftnl_expr_dup_cmp(const struct nftnl_expr *e1,
+                              const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_dup *d1 = nftnl_expr_data(e1);
+       struct nftnl_expr_dup *d2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_DUP_SREG_ADDR))
+               eq &= (d1->sreg_addr == d2->sreg_addr);
+       if (e1->flags & (1 << NFTNL_EXPR_DUP_SREG_DEV))
+               eq &= (d1->sreg_dev == d2->sreg_dev);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_dup = {
        .name           = "dup",
        .alloc_len      = sizeof(struct nftnl_expr_dup),
        .max_attr       = NFTA_DUP_MAX,
+       .cmp            = nftnl_expr_dup_cmp,
        .set            = nftnl_expr_dup_set,
        .get            = nftnl_expr_dup_get,
        .parse          = nftnl_expr_dup_parse,
index 0eaa409a9c80821b1e8d8ee83fbe05b5326daad4..ea59145ba43806c187714e013088661ed23e7dbf 100644 (file)
@@ -370,11 +370,37 @@ static void nftnl_expr_dynset_free(const struct nftnl_expr *e)
        xfree(dynset->set_name);
 }
 
+static bool nftnl_expr_dynset_cmp(const struct nftnl_expr *e1,
+                                 const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_dynset *d1 = nftnl_expr_data(e1);
+       struct nftnl_expr_dynset *d2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_DYNSET_SREG_KEY))
+               eq &= (d1->sreg_key == d2->sreg_key);
+       if (e1->flags & (1 << NFTNL_EXPR_DYNSET_SREG_DATA))
+               eq &= (d1->sreg_data == d2->sreg_data);
+       if (e1->flags & (1 << NFTNL_EXPR_DYNSET_OP))
+               eq &= (d1->op == d2->op);
+       if (e1->flags & (1 << NFTNL_EXPR_DYNSET_TIMEOUT))
+               eq &= (d1->timeout == d2->timeout);
+       if (e1->flags & (1 << NFTNL_EXPR_DYNSET_EXPR))
+               eq &= nftnl_expr_cmp(d1->expr, d2->expr);
+       if (e1->flags & (1 << NFTNL_EXPR_DYNSET_SET_NAME))
+               eq &= !strcmp(d1->set_name, d2->set_name);
+       if (e1->flags & (1 << NFTNL_EXPR_DYNSET_SET_ID))
+               eq &= (d1->set_id == d2->set_id);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_dynset = {
        .name           = "dynset",
        .alloc_len      = sizeof(struct nftnl_expr_dynset),
        .max_attr       = NFTA_DYNSET_MAX,
        .free           = nftnl_expr_dynset_free,
+       .cmp            = nftnl_expr_dynset_cmp,
        .set            = nftnl_expr_dynset_set,
        .get            = nftnl_expr_dynset_get,
        .parse          = nftnl_expr_dynset_parse,
index 6489a4810a94672a7304cf4c751773189f7bba34..deb0d7c0aa22f6584d9c0f97f1fa1fb831e7a4b4 100644 (file)
@@ -304,10 +304,30 @@ nftnl_expr_exthdr_snprintf(char *buf, size_t len, uint32_t type,
        return -1;
 }
 
+static bool nftnl_expr_exthdr_cmp(const struct nftnl_expr *e1,
+                                 const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_exthdr *h1 = nftnl_expr_data(e1);
+       struct nftnl_expr_exthdr *h2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_EXTHDR_DREG))
+               eq &= (h1->dreg == h2->dreg);
+       if (e1->flags & (1 << NFTNL_EXPR_EXTHDR_OFFSET))
+               eq &= (h1->offset == h2->offset);
+       if (e1->flags & (1 << NFTNL_EXPR_EXTHDR_LEN))
+               eq &= (h1->len == h2->len);
+       if (e1->flags & (1 << NFTNL_EXPR_EXTHDR_TYPE))
+               eq &= (h1->type == h2->type);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_exthdr = {
        .name           = "exthdr",
        .alloc_len      = sizeof(struct nftnl_expr_exthdr),
        .max_attr       = NFTA_EXTHDR_MAX,
+       .cmp            = nftnl_expr_exthdr_cmp,
        .set            = nftnl_expr_exthdr_set,
        .get            = nftnl_expr_exthdr_get,
        .parse          = nftnl_expr_exthdr_parse,
index 8fa6d66bfc5a79f1ce576b9b08e9b7468cfd6d8e..9c5520ca4e701fe24e3cd9b1e86f029b261ba72c 100644 (file)
@@ -175,10 +175,24 @@ static int nftnl_expr_fwd_snprintf(char *buf, size_t len, uint32_t type,
        return -1;
 }
 
+static bool nftnl_expr_fwd_cmp(const struct nftnl_expr *e1,
+                              const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_fwd *f1 = nftnl_expr_data(e1);
+       struct nftnl_expr_fwd *f2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_FWD_SREG_DEV))
+               eq &= (f1->sreg_dev == f2->sreg_dev);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_fwd = {
        .name           = "fwd",
        .alloc_len      = sizeof(struct nftnl_expr_fwd),
        .max_attr       = NFTA_FWD_MAX,
+       .cmp            = nftnl_expr_fwd_cmp,
        .set            = nftnl_expr_fwd_set,
        .get            = nftnl_expr_fwd_get,
        .parse          = nftnl_expr_fwd_parse,
index 730990749ee87ebfbc68e1da2ab085498edba3b3..a3439d8c0dd8b93131229a77e40e9ef8b4175df6 100644 (file)
@@ -280,10 +280,32 @@ nftnl_expr_hash_snprintf(char *buf, size_t len, uint32_t type,
        return -1;
 }
 
+static bool nftnl_expr_hash_cmp(const struct nftnl_expr *e1,
+                               const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_hash *h1 = nftnl_expr_data(e1);
+       struct nftnl_expr_hash *h2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_HASH_SREG))
+               eq &= (h1->sreg == h2->sreg);
+       if (e1->flags & (1 << NFTNL_EXPR_HASH_DREG))
+               eq &= (h1->dreg == h2->dreg);
+       if (e1->flags & (1 << NFTNL_EXPR_HASH_LEN))
+               eq &= (h1->len == h2->len);
+       if (e1->flags & (1 << NFTNL_EXPR_HASH_MODULUS))
+               eq &= (h1->modulus == h2->modulus);
+       if (e1->flags & (1 << NFTNL_EXPR_HASH_SEED))
+               eq &= (h1->seed == h2->seed);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_hash = {
        .name           = "hash",
        .alloc_len      = sizeof(struct nftnl_expr_hash),
        .max_attr       = NFTA_HASH_MAX,
+       .cmp            = nftnl_expr_hash_cmp,
        .set            = nftnl_expr_hash_set,
        .get            = nftnl_expr_hash_get,
        .parse          = nftnl_expr_hash_parse,
index 22ec864f69ecc8e7fe3b23be54e4543a968909b9..cb8a81b0b2166b145b04f915b4d2e557ca3b72db 100644 (file)
@@ -320,11 +320,29 @@ static void nftnl_expr_immediate_free(const struct nftnl_expr *e)
                nftnl_free_verdict(&imm->data);
 }
 
+static bool nftnl_expr_immediate_cmp(const struct nftnl_expr *e1,
+                                    const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_immediate *i1 = nftnl_expr_data(e1);
+       struct nftnl_expr_immediate *i2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_IMM_DREG))
+               eq &= (i1->dreg == i2->dreg);
+       if (e1->flags & (1 << NFTNL_EXPR_IMM_VERDICT))
+               eq &= nftnl_data_reg_cmp(&i1->data, &i2->data, DATA_VERDICT);
+       else if (e1->flags & (1 << NFTNL_EXPR_IMM_DATA))
+               eq &= nftnl_data_reg_cmp(&i1->data, &i2->data, DATA_VALUE);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_immediate = {
        .name           = "immediate",
        .alloc_len      = sizeof(struct nftnl_expr_immediate),
        .max_attr       = NFTA_IMMEDIATE_MAX,
        .free           = nftnl_expr_immediate_free,
+       .cmp            = nftnl_expr_immediate_cmp,
        .set            = nftnl_expr_immediate_set,
        .get            = nftnl_expr_immediate_get,
        .parse          = nftnl_expr_immediate_parse,
index cdff81d620caa25ed11e6f643f248338d07c1b20..9f19d5355085b0292a742a851ba535e6b5b8bace 100644 (file)
@@ -287,11 +287,33 @@ nftnl_expr_limit_snprintf(char *buf, size_t len, uint32_t type,
        return -1;
 }
 
+static bool nftnl_expr_limit_cmp(const struct nftnl_expr *e1,
+                                const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_limit *l1 = nftnl_expr_data(e1);
+       struct nftnl_expr_limit *l2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_LIMIT_RATE))
+               eq &= (l1->rate == l2->rate);
+       if (e1->flags & (1 << NFTNL_EXPR_LIMIT_UNIT))
+               eq &= (l1->unit == l2->unit);
+       if (e1->flags & (1 << NFTNL_EXPR_LIMIT_BURST))
+               eq &= (l1->burst == l2->burst);
+       if (e1->flags & (1 << NFTNL_EXPR_LIMIT_TYPE))
+               eq &= (l1->type == l2->type);
+       if (e1->flags & (1 << NFTNL_EXPR_LIMIT_FLAGS))
+               eq &= (l1->flags == l2->flags);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_limit = {
        .name           = "limit",
        .alloc_len      = sizeof(struct nftnl_expr_limit),
        .max_attr       = NFTA_LIMIT_MAX,
        .set            = nftnl_expr_limit_set,
+       .cmp            = nftnl_expr_limit_cmp,
        .get            = nftnl_expr_limit_get,
        .parse          = nftnl_expr_limit_parse,
        .build          = nftnl_expr_limit_build,
index b9b3951fc5a8584c823424ca5f866a71a7d79aa4..d1e7b8d3b824589485d92d1069c656562d8043c1 100644 (file)
@@ -336,11 +336,35 @@ static void nftnl_expr_log_free(const struct nftnl_expr *e)
        xfree(log->prefix);
 }
 
+static bool nftnl_expr_log_cmp(const struct nftnl_expr *e1,
+                                    const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_log *l1 = nftnl_expr_data(e1);
+       struct nftnl_expr_log *l2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_LOG_SNAPLEN))
+               eq &= (l1->snaplen == l2->snaplen);
+       if (e1->flags & (1 << NFTNL_EXPR_LOG_GROUP))
+               eq &= (l1->group == l2->group);
+       if (e1->flags & (1 << NFTNL_EXPR_LOG_QTHRESHOLD))
+               eq &= (l1->qthreshold == l2->qthreshold);
+       if (e1->flags & (1 << NFTNL_EXPR_LOG_LEVEL))
+               eq &= (l1->level == l2->level);
+       if (e1->flags & (1 << NFTNL_EXPR_LOG_FLAGS))
+               eq &= (l1->flags == l2->flags);
+       if (e1->flags & (1 << NFTNL_EXPR_LOG_PREFIX))
+               eq &= !strcmp(l1->prefix, l2->prefix);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_log = {
        .name           = "log",
        .alloc_len      = sizeof(struct nftnl_expr_log),
        .max_attr       = NFTA_LOG_MAX,
        .free           = nftnl_expr_log_free,
+       .cmp            = nftnl_expr_log_cmp,
        .set            = nftnl_expr_log_set,
        .get            = nftnl_expr_log_get,
        .parse          = nftnl_expr_log_parse,
index 639470dad1373dff386036c480d1ddc0efdfdd8b..1377c0c48d2fa6bd6f28ca786d4160137b915496 100644 (file)
@@ -295,11 +295,33 @@ static void nftnl_expr_lookup_free(const struct nftnl_expr *e)
        xfree(lookup->set_name);
 }
 
+static bool nftnl_expr_lookup_cmp(const struct nftnl_expr *e1,
+                                 const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_lookup *l1 = nftnl_expr_data(e1);
+       struct nftnl_expr_lookup *l2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_LOOKUP_SREG))
+               eq &= (l1->sreg == l2->sreg);
+       if (e1->flags & (1 << NFTNL_EXPR_LOOKUP_DREG))
+               eq &= (l1->dreg == l2->dreg);
+       if (e1->flags & (1 << NFTNL_EXPR_LOOKUP_SET))
+               eq &= !strcmp(l1->set_name, l2->set_name);
+       if (e1->flags & (1 << NFTNL_EXPR_LOOKUP_SET_ID))
+               eq &= (l1->set_id == l2->set_id);
+       if (e1->flags & (1 << NFTNL_EXPR_LOOKUP_FLAGS))
+               eq &= (l1->flags == l2->flags);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_lookup = {
        .name           = "lookup",
        .alloc_len      = sizeof(struct nftnl_expr_lookup),
        .max_attr       = NFTA_LOOKUP_MAX,
        .free           = nftnl_expr_lookup_free,
+       .cmp            = nftnl_expr_lookup_cmp,
        .set            = nftnl_expr_lookup_set,
        .get            = nftnl_expr_lookup_get,
        .parse          = nftnl_expr_lookup_parse,
index 7296590e07d681351cf1ed302b2dd982d01b7746..77506fe244b1e12aa81ffe4586fb6f4a6ef5cc3b 100644 (file)
@@ -228,10 +228,28 @@ static int nftnl_expr_masq_snprintf(char *buf, size_t len, uint32_t type,
        return -1;
 }
 
+static bool nftnl_expr_masq_cmp(const struct nftnl_expr *e1,
+                               const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_masq *m1 = nftnl_expr_data(e1);
+       struct nftnl_expr_masq *m2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_MASQ_FLAGS))
+               eq &= (m1->flags == m2->flags);
+       if (e1->flags & (1 << NFTNL_EXPR_MASQ_REG_PROTO_MIN))
+               eq &= (m1->sreg_proto_min == m2->sreg_proto_min);
+       if (e1->flags & (1 << NFTNL_EXPR_MASQ_REG_PROTO_MAX))
+               eq &= (m1->sreg_proto_max == m2->sreg_proto_max);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_masq = {
        .name           = "masq",
        .alloc_len      = sizeof(struct nftnl_expr_masq),
        .max_attr       = NFTA_MASQ_MAX,
+       .cmp            = nftnl_expr_masq_cmp,
        .set            = nftnl_expr_masq_set,
        .get            = nftnl_expr_masq_get,
        .parse          = nftnl_expr_masq_parse,
index 3342e2ccebbd0290f30c249dae288c0d287b67f8..c48518e1b7475218d03d741b3946e3c1987b77d1 100644 (file)
@@ -240,11 +240,31 @@ static void nftnl_expr_match_free(const struct nftnl_expr *e)
        xfree(match->data);
 }
 
+static bool nftnl_expr_match_cmp(const struct nftnl_expr *e1,
+                                const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_match *m1 = nftnl_expr_data(e1);
+       struct nftnl_expr_match *m2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_MT_NAME))
+               eq &= !strcmp(m1->name, m2->name);
+       if (e1->flags & (1 << NFTNL_EXPR_MT_REV))
+               eq &= (m1->rev == m2->rev);
+       if (e1->flags & (1 << NFTNL_EXPR_MT_INFO)) {
+               eq &= (m1->data_len == m2->data_len);
+               eq &= !memcmp(m1->data, m2->data, m1->data_len);
+       }
+
+       return eq;
+}
+
 struct expr_ops expr_ops_match = {
        .name           = "match",
        .alloc_len      = sizeof(struct nftnl_expr_match),
        .max_attr       = NFTA_MATCH_MAX,
        .free           = nftnl_expr_match_free,
+       .cmp            = nftnl_expr_match_cmp,
        .set            = nftnl_expr_match_set,
        .get            = nftnl_expr_match_get,
        .parse          = nftnl_expr_match_parse,
index a478a89d3db3aae0e1e924a1c80277921ec6e996..6abf6c46262a33c358d9456dacc761b38d600d42 100644 (file)
@@ -296,10 +296,28 @@ nftnl_expr_meta_snprintf(char *buf, size_t len, uint32_t type,
        return -1;
 }
 
+static bool nftnl_expr_meta_cmp(const struct nftnl_expr *e1,
+                                    const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_meta *m1 = nftnl_expr_data(e1);
+       struct nftnl_expr_meta *m2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_META_KEY))
+               eq &= (m1->key == m2->key);
+       if (e1->flags & (1 << NFTNL_EXPR_META_DREG))
+               eq &= (m1->dreg == m2->dreg);
+       if (e1->flags & (1 << NFTNL_EXPR_META_SREG))
+               eq &= (m1->sreg == m2->sreg);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_meta = {
        .name           = "meta",
        .alloc_len      = sizeof(struct nftnl_expr_meta),
        .max_attr       = NFTA_META_MAX,
+       .cmp            = nftnl_expr_meta_cmp,
        .set            = nftnl_expr_meta_set,
        .get            = nftnl_expr_meta_get,
        .parse          = nftnl_expr_meta_parse,
index 1ae7f77f8d4897f25334876f55f7a600907a4df4..485a6234d66a4d41a155d2a83751445460e1ccb9 100644 (file)
@@ -404,10 +404,35 @@ nftnl_expr_nat_snprintf(char *buf, size_t size, uint32_t type,
        return -1;
 }
 
+static bool nftnl_expr_nat_cmp(const struct nftnl_expr *e1,
+                              const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_nat *n1 = nftnl_expr_data(e1);
+       struct nftnl_expr_nat *n2 = nftnl_expr_data(e2);
+       bool eq = true;
+       if (e1->flags & (1 << NFTNL_EXPR_NAT_REG_ADDR_MIN))
+               eq &= (n1->sreg_addr_min == n2->sreg_addr_min);
+       if (e1->flags & (1 << NFTNL_EXPR_NAT_REG_ADDR_MAX))
+               eq &= (n1->sreg_addr_max == n2->sreg_addr_max);
+       if (e1->flags & (1 << NFTNL_EXPR_NAT_REG_PROTO_MIN))
+               eq &= (n1->sreg_proto_min == n2->sreg_proto_min);
+       if (e1->flags & (1 << NFTNL_EXPR_NAT_REG_PROTO_MAX))
+               eq &= (n1->sreg_proto_max == n2->sreg_proto_max);
+       if (e1->flags & (1 << NFTNL_EXPR_NAT_FAMILY))
+               eq &= (n1->family == n2->family);
+       if (e1->flags & (1 << NFTNL_EXPR_NAT_TYPE))
+               eq &= (n1->type == n2->type);
+       if (e1->flags & (1 << NFTNL_EXPR_NAT_FLAGS))
+               eq &= (n1->flags == n2->flags);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_nat = {
        .name           = "nat",
        .alloc_len      = sizeof(struct nftnl_expr_nat),
        .max_attr       = NFTA_NAT_MAX,
+       .cmp            = nftnl_expr_nat_cmp,
        .set            = nftnl_expr_nat_set,
        .get            = nftnl_expr_nat_get,
        .parse          = nftnl_expr_nat_parse,
index d4f9ef96921dfb6211028eecd89a115dc2f27bf1..c9ab5d42c0377cb5715e3e1d43cae1f2718aad5e 100644 (file)
@@ -335,10 +335,36 @@ nftnl_expr_payload_snprintf(char *buf, size_t len, uint32_t type,
        return -1;
 }
 
+static bool nftnl_expr_payload_cmp(const struct nftnl_expr *e1,
+                                  const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_payload *p1 = nftnl_expr_data(e1);
+       struct nftnl_expr_payload *p2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_PAYLOAD_SREG))
+               eq &= (p1->sreg == p2->sreg);
+       if (e1->flags & (1 << NFTNL_EXPR_PAYLOAD_DREG))
+               eq &= (p1->dreg == p2->dreg);
+       if (e1->flags & (1 << NFTNL_EXPR_PAYLOAD_BASE))
+               eq &= (p1->base == p2->base);
+       if (e1->flags & (1 << NFTNL_EXPR_PAYLOAD_OFFSET))
+               eq &= (p1->offset == p2->offset);
+       if (e1->flags & (1 << NFTNL_EXPR_PAYLOAD_LEN))
+               eq &= (p1->len == p2->len);
+       if (e1->flags & (1 << NFTNL_EXPR_PAYLOAD_CSUM_TYPE))
+               eq &= (p1->csum_type == p2->csum_type);
+       if (e1->flags & (1 << NFTNL_EXPR_PAYLOAD_CSUM_OFFSET))
+               eq &= (p1->csum_offset == p2->csum_offset);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_payload = {
        .name           = "payload",
        .alloc_len      = sizeof(struct nftnl_expr_payload),
        .max_attr       = NFTA_PAYLOAD_MAX,
+       .cmp            = nftnl_expr_payload_cmp,
        .set            = nftnl_expr_payload_set,
        .get            = nftnl_expr_payload_get,
        .parse          = nftnl_expr_payload_parse,
index a2e6ed53005f240e0a7979a4344dba023a206a7c..522231b070340a84bd3b71fcfb26210e0d8031d6 100644 (file)
@@ -243,10 +243,28 @@ nftnl_expr_queue_snprintf(char *buf, size_t len, uint32_t type,
        return -1;
 }
 
+static bool nftnl_expr_queue_cmp(const struct nftnl_expr *e1,
+                           const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_queue *q1 = nftnl_expr_data(e1);
+       struct nftnl_expr_queue *q2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_QUEUE_NUM))
+               eq &= (q1->queuenum == q2->queuenum);
+       if (e1->flags & (1 << NFTNL_EXPR_QUEUE_TOTAL))
+               eq &= (q1->queues_total == q2->queues_total);
+       if (e1->flags & (1 << NFTNL_EXPR_QUEUE_FLAGS))
+               eq &= (q1->flags == q2->flags);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_queue = {
        .name           = "queue",
        .alloc_len      = sizeof(struct nftnl_expr_queue),
        .max_attr       = NFTA_QUEUE_MAX,
+       .cmp            = nftnl_expr_queue_cmp,
        .set            = nftnl_expr_queue_set,
        .get            = nftnl_expr_queue_get,
        .parse          = nftnl_expr_queue_parse,
index c6eedfb3fff53cbc4ee06fd3bed0986aee8e9efd..d9dba008be0641c87bd1b539ad98c54cccf2f0bc 100644 (file)
@@ -242,10 +242,28 @@ nftnl_expr_redir_snprintf(char *buf, size_t len, uint32_t type,
        return -1;
 }
 
+static bool nftnl_expr_redir_cmp(const struct nftnl_expr *e1,
+                                const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_redir *r1 = nftnl_expr_data(e1);
+       struct nftnl_expr_redir *r2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_REDIR_REG_PROTO_MIN))
+               eq &= (r1->sreg_proto_min== r2->sreg_proto_min);
+       if (e1->flags & (1 << NFTNL_EXPR_REDIR_REG_PROTO_MAX))
+               eq &= (r1->sreg_proto_max== r2->sreg_proto_max);
+       if (e1->flags & (1 << NFTNL_EXPR_REDIR_FLAGS))
+               eq &= (r1->flags== r2->flags);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_redir = {
        .name           = "redir",
        .alloc_len      = sizeof(struct nftnl_expr_redir),
        .max_attr       = NFTA_REDIR_MAX,
+       .cmp            = nftnl_expr_redir_cmp,
        .set            = nftnl_expr_redir_set,
        .get            = nftnl_expr_redir_get,
        .parse          = nftnl_expr_redir_parse,
index 19533281df6587bf7d8d4ebcc09373265061b4e6..29060820c490f789fbb53696053f46a4425a2871 100644 (file)
@@ -199,10 +199,26 @@ nftnl_expr_reject_snprintf(char *buf, size_t len, uint32_t type,
        return -1;
 }
 
+static bool nftnl_expr_reject_cmp(const struct nftnl_expr *e1,
+                                 const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_reject *r1 = nftnl_expr_data(e1);
+       struct nftnl_expr_reject *r2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_REJECT_TYPE))
+               eq &= (r1->type == r2->type);
+       if (e1->flags & (1 << NFTNL_EXPR_REJECT_CODE))
+               eq &= (r1->icmp_code == r2->icmp_code);
+
+       return eq;
+}
+
 struct expr_ops expr_ops_reject = {
        .name           = "reject",
        .alloc_len      = sizeof(struct nftnl_expr_reject),
        .max_attr       = NFTA_REJECT_MAX,
+       .cmp            = nftnl_expr_reject_cmp,
        .set            = nftnl_expr_reject_set,
        .get            = nftnl_expr_reject_get,
        .parse          = nftnl_expr_reject_parse,
index d4c0091fa9c1b2fea9c1ed1119eb0746711285ce..5a3301c872d82b516505400f00794f2a5dfe7b01 100644 (file)
@@ -241,11 +241,31 @@ static void nftnl_expr_target_free(const struct nftnl_expr *e)
        xfree(target->data);
 }
 
+static bool nftnl_expr_target_cmp(const struct nftnl_expr *e1,
+                                 const struct nftnl_expr *e2)
+{
+       struct nftnl_expr_target *t1 = nftnl_expr_data(e1);
+       struct nftnl_expr_target *t2 = nftnl_expr_data(e2);
+       bool eq = true;
+
+       if (e1->flags & (1 << NFTNL_EXPR_TG_NAME))
+               eq &= !strcmp(t1->name, t2->name);
+       if (e1->flags & (1 << NFTNL_EXPR_TG_REV))
+               eq &= (t1->rev == t2->rev);
+       if (e1->flags & (1 << NFTNL_EXPR_TG_INFO)) {
+               eq &= (t1->data_len == t2->data_len);
+               eq &= !memcmp(t1->data, t2->data, t1->data_len);
+       }
+
+       return eq;
+}
+
 struct expr_ops expr_ops_target = {
        .name           = "target",
        .alloc_len      = sizeof(struct nftnl_expr_target),
        .max_attr       = NFTA_TARGET_MAX,
        .free           = nftnl_expr_target_free,
+       .cmp            = nftnl_expr_target_cmp,
        .set            = nftnl_expr_target_set,
        .get            = nftnl_expr_target_get,
        .parse          = nftnl_expr_target_parse,
index c38e08163d6af80812baaf0a59a9b310f72ee28e..abed8b9e12956530c49b641f8c2b02223ef11131 100644 (file)
@@ -528,3 +528,8 @@ LIBNFTNL_4.1 {
        nftnl_udata_next;
        nftnl_udata_parse;
 } LIBNFTNL_4;
+
+LIBNFTNL_4.2 {
+       nftnl_rule_cmp;
+       nftnl_expr_cmp;
+} LIBNFTNL_4.1;
index 8aeefbe19a9eda1d9f41ea690f2ced1a22ca0fb6..ae7c478dda0967115f15e249885688e1347064f3 100644 (file)
@@ -1077,6 +1077,36 @@ void nftnl_expr_iter_destroy(struct nftnl_expr_iter *iter)
 }
 EXPORT_SYMBOL_ALIAS(nftnl_expr_iter_destroy, nft_rule_expr_iter_destroy);
 
+bool nftnl_rule_cmp(const struct nftnl_rule *r1, const struct nftnl_rule *r2)
+{
+       struct nftnl_expr_iter it1, it2;
+       struct nftnl_expr *e1, *e2;
+       unsigned int eq = 1;
+
+       if (r1->flags & r1->flags & (1 << NFTNL_RULE_TABLE))
+               eq &= !strcmp(r1->table, r2->table);
+       if (r1->flags & r1->flags & (1 << NFTNL_RULE_CHAIN))
+               eq &= !strcmp(r1->chain, r2->chain);
+       if (r1->flags & r1->flags & (1 << NFTNL_RULE_COMPAT_FLAGS))
+               eq &= (r1->compat.flags == r2->compat.flags);
+       if (r1->flags & r1->flags & (1 << NFTNL_RULE_COMPAT_PROTO))
+               eq &= (r1->compat.proto == r2->compat.proto);
+
+       nftnl_expr_iter_init(r1, &it1);
+       nftnl_expr_iter_init(r2, &it2);
+       e1 = nftnl_expr_iter_next(&it1);
+       e2 = nftnl_expr_iter_next(&it2);
+       while (eq && e1 && e2) {
+               eq = nftnl_expr_cmp(e1, e2);
+
+               e1 = nftnl_expr_iter_next(&it1);
+               e2 = nftnl_expr_iter_next(&it2);
+       }
+
+       return eq;
+}
+EXPORT_SYMBOL(nftnl_rule_cmp);
+
 struct nftnl_rule_list {
        struct list_head list;
 };