#include <linux/netfilter/nf_tables.h>
#include <stdint.h>
+#include <stdbool.h>
#include <unistd.h>
enum {
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);
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);
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 {
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);
}
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)
{
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,
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,
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,
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,
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,
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;
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
nftnl_udata_next;
nftnl_udata_parse;
} LIBNFTNL_4;
+
+LIBNFTNL_4.2 {
+ nftnl_rule_cmp;
+ nftnl_expr_cmp;
+} LIBNFTNL_4.1;
}
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;
};