summaryrefslogtreecommitdiffstats
path: root/src/expr
diff options
context:
space:
mode:
Diffstat (limited to 'src/expr')
-rw-r--r--src/expr/ct.c82
-rw-r--r--src/expr/exthdr.c44
-rw-r--r--src/expr/fib.c46
-rw-r--r--src/expr/last.c22
-rw-r--r--src/expr/meta.c44
-rw-r--r--src/expr/osf.c32
-rw-r--r--src/expr/payload.c36
-rw-r--r--src/expr/rt.c46
-rw-r--r--src/expr/socket.c47
-rw-r--r--src/expr/xfrm.c51
10 files changed, 446 insertions, 4 deletions
diff --git a/src/expr/ct.c b/src/expr/ct.c
index d5dfc81..f17491c 100644
--- a/src/expr/ct.c
+++ b/src/expr/ct.c
@@ -14,6 +14,7 @@
#include <stdint.h>
#include <arpa/inet.h>
#include <errno.h>
+#include <assert.h>
#include <linux/netfilter/nf_tables.h>
#include "internal.h"
@@ -148,6 +149,82 @@ nftnl_expr_ct_parse(struct nftnl_expr *e, struct nlattr *attr)
return 0;
}
+#ifndef XT_CONNLABEL_MAXBIT
+#define XT_CONNLABEL_MAXBIT 127
+#endif
+
+#ifndef NF_CT_LABELS_MAX_SIZE
+#define NF_CT_LABELS_MAX_SIZE ((XT_CONNLABEL_MAXBIT + 1) / 8)
+#endif
+
+#ifndef NF_CT_HELPER_NAME_LEN
+#define NF_CT_HELPER_NAME_LEN 16
+#endif
+
+static int
+nftnl_expr_ct_reg_len(const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_ct *ct = nftnl_expr_data(e);
+
+ switch (ct->key) {
+ case NFT_CT_DIRECTION:
+ case NFT_CT_PROTOCOL:
+ case NFT_CT_L3PROTOCOL:
+ return sizeof(uint8_t);
+ case NFT_CT_ZONE:
+ case NFT_CT_LABELS:
+ return NF_CT_LABELS_MAX_SIZE;
+ case NFT_CT_HELPER:
+ return NF_CT_HELPER_NAME_LEN;
+ case NFT_CT_PROTO_SRC:
+ case NFT_CT_PROTO_DST:
+ return sizeof(uint16_t);
+ case NFT_CT_ID:
+ case NFT_CT_STATE:
+ case NFT_CT_STATUS:
+ case NFT_CT_MARK:
+ case NFT_CT_SECMARK:
+ case NFT_CT_EXPIRATION:
+ case NFT_CT_EVENTMASK:
+ case NFT_CT_SRC_IP:
+ case NFT_CT_DST_IP:
+ return sizeof(uint32_t);
+ case NFT_CT_BYTES:
+ case NFT_CT_PKTS:
+ case NFT_CT_AVGPKT:
+ return sizeof(uint64_t);
+ case NFT_CT_SRC:
+ case NFT_CT_DST:
+ case NFT_CT_SRC_IP6:
+ case NFT_CT_DST_IP6:
+ return sizeof(uint32_t) * 4;
+ default:
+ assert(0);
+ }
+
+ return sizeof(uint32_t);
+}
+
+static bool
+nftnl_expr_ct_reg_cmp(const struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_ct *ct = nftnl_expr_data(e);
+
+ return reg->ct.key == ct->key &&
+ reg->ct.dir == ct->dir;
+}
+
+static void
+nftnl_expr_ct_reg_update(struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_ct *ct = nftnl_expr_data(e);
+
+ reg->ct.key = ct->key;
+ reg->ct.dir = ct->dir;
+}
+
static const char *ctkey2str_array[NFT_CT_MAX + 1] = {
[NFT_CT_STATE] = "state",
[NFT_CT_DIRECTION] = "direction",
@@ -259,4 +336,9 @@ struct expr_ops expr_ops_ct = {
.parse = nftnl_expr_ct_parse,
.build = nftnl_expr_ct_build,
.snprintf = nftnl_expr_ct_snprintf,
+ .reg = {
+ .len = nftnl_expr_ct_reg_len,
+ .cmp = nftnl_expr_ct_reg_cmp,
+ .update = nftnl_expr_ct_reg_update,
+ },
};
diff --git a/src/expr/exthdr.c b/src/expr/exthdr.c
index 1b813b1..53a2a80 100644
--- a/src/expr/exthdr.c
+++ b/src/expr/exthdr.c
@@ -194,6 +194,38 @@ nftnl_expr_exthdr_parse(struct nftnl_expr *e, struct nlattr *attr)
return 0;
}
+static int
+nftnl_expr_exthdr_reg_len(const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_exthdr *exthdr = nftnl_expr_data(e);
+
+ return exthdr->len;
+}
+
+static bool
+nftnl_expr_exthdr_reg_cmp(const struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_exthdr *exthdr = nftnl_expr_data(e);
+
+ return reg->exthdr.offset == exthdr->offset &&
+ reg->exthdr.type == exthdr->type &&
+ reg->exthdr.op == exthdr->op &&
+ reg->exthdr.flags == exthdr->flags;
+}
+
+static void
+nftnl_expr_exthdr_reg_update(struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_exthdr *exthdr = nftnl_expr_data(e);
+
+ reg->exthdr.offset = exthdr->offset;
+ reg->exthdr.type = exthdr->type;
+ reg->exthdr.op = exthdr->op;
+ reg->exthdr.flags = exthdr->flags;
+}
+
static const char *op2str(uint8_t op)
{
switch (op) {
@@ -247,10 +279,15 @@ nftnl_expr_exthdr_snprintf(char *buf, size_t len,
exthdr->offset,
exthdr->flags & NFT_EXTHDR_F_PRESENT ? " present" : "",
exthdr->dreg);
- else
+ else if (e->flags & (1 << NFTNL_EXPR_EXTHDR_SREG))
return snprintf(buf, len, "write%s reg %u => %ub @ %u + %u ",
op2str(exthdr->op), exthdr->sreg, exthdr->len, exthdr->type,
exthdr->offset);
+ else if (exthdr->op == NFT_EXTHDR_OP_TCPOPT && exthdr->len == 0)
+ return snprintf(buf, len, "reset tcpopt %u ", exthdr->type);
+ else
+ return snprintf(buf, len, "op %u len %u type %u offset %u ",
+ exthdr->op, exthdr->len, exthdr->type, exthdr->offset);
}
@@ -263,4 +300,9 @@ struct expr_ops expr_ops_exthdr = {
.parse = nftnl_expr_exthdr_parse,
.build = nftnl_expr_exthdr_build,
.snprintf = nftnl_expr_exthdr_snprintf,
+ .reg = {
+ .len = nftnl_expr_exthdr_reg_len,
+ .cmp = nftnl_expr_exthdr_reg_cmp,
+ .update = nftnl_expr_exthdr_reg_update,
+ },
};
diff --git a/src/expr/fib.c b/src/expr/fib.c
index aaff52a..7e6c0dc 100644
--- a/src/expr/fib.c
+++ b/src/expr/fib.c
@@ -14,6 +14,8 @@
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
+#include <net/if.h>
+#include <assert.h>
#include <linux/netfilter/nf_tables.h>
#include "internal.h"
@@ -128,6 +130,45 @@ nftnl_expr_fib_parse(struct nftnl_expr *e, struct nlattr *attr)
return ret;
}
+static int
+nftnl_expr_fib_reg_len(const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_fib *fib = nftnl_expr_data(e);
+
+ switch (fib->result) {
+ case NFT_FIB_RESULT_OIF:
+ return sizeof(int);
+ case NFT_FIB_RESULT_OIFNAME:
+ return IFNAMSIZ;
+ case NFT_FIB_RESULT_ADDRTYPE:
+ return sizeof(uint32_t);
+ default:
+ assert(0);
+ break;
+ }
+ return sizeof(uint32_t);
+}
+
+static bool
+nftnl_expr_fib_reg_cmp(const struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_fib *fib = nftnl_expr_data(e);
+
+ return reg->fib.result == fib->result &&
+ reg->fib.flags == fib->flags;
+}
+
+static void
+nftnl_expr_fib_reg_update(struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_fib *fib = nftnl_expr_data(e);
+
+ reg->fib.result = fib->result;
+ reg->fib.flags = fib->flags;
+}
+
static const char *fib_type[NFT_FIB_RESULT_MAX + 1] = {
[NFT_FIB_RESULT_OIF] = "oif",
[NFT_FIB_RESULT_OIFNAME] = "oifname",
@@ -199,4 +240,9 @@ struct expr_ops expr_ops_fib = {
.parse = nftnl_expr_fib_parse,
.build = nftnl_expr_fib_build,
.snprintf = nftnl_expr_fib_snprintf,
+ .reg = {
+ .len = nftnl_expr_fib_reg_len,
+ .cmp = nftnl_expr_fib_reg_cmp,
+ .update = nftnl_expr_fib_reg_update,
+ },
};
diff --git a/src/expr/last.c b/src/expr/last.c
index 0020fbc..e2a60c4 100644
--- a/src/expr/last.c
+++ b/src/expr/last.c
@@ -22,6 +22,7 @@
struct nftnl_expr_last {
uint64_t msecs;
+ uint32_t set;
};
static int nftnl_expr_last_set(struct nftnl_expr *e, uint16_t type,
@@ -33,6 +34,9 @@ static int nftnl_expr_last_set(struct nftnl_expr *e, uint16_t type,
case NFTNL_EXPR_LAST_MSECS:
memcpy(&last->msecs, data, sizeof(last->msecs));
break;
+ case NFTNL_EXPR_LAST_SET:
+ memcpy(&last->set, data, sizeof(last->set));
+ break;
default:
return -1;
}
@@ -48,6 +52,9 @@ static const void *nftnl_expr_last_get(const struct nftnl_expr *e,
case NFTNL_EXPR_LAST_MSECS:
*data_len = sizeof(last->msecs);
return &last->msecs;
+ case NFTNL_EXPR_LAST_SET:
+ *data_len = sizeof(last->set);
+ return &last->set;
}
return NULL;
}
@@ -65,6 +72,10 @@ static int nftnl_expr_last_cb(const struct nlattr *attr, void *data)
if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
abi_breakage();
break;
+ case NFTA_LAST_SET:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+ abi_breakage();
+ break;
}
tb[type] = attr;
@@ -78,6 +89,8 @@ nftnl_expr_last_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
if (e->flags & (1 << NFTNL_EXPR_LAST_MSECS))
mnl_attr_put_u64(nlh, NFTA_LAST_MSECS, htobe64(last->msecs));
+ if (e->flags & (1 << NFTNL_EXPR_LAST_SET))
+ mnl_attr_put_u32(nlh, NFTA_LAST_SET, htonl(last->set));
}
static int
@@ -93,6 +106,10 @@ nftnl_expr_last_parse(struct nftnl_expr *e, struct nlattr *attr)
last->msecs = be64toh(mnl_attr_get_u64(tb[NFTA_LAST_MSECS]));
e->flags |= (1 << NFTNL_EXPR_LAST_MSECS);
}
+ if (tb[NFTA_LAST_SET]) {
+ last->set = ntohl(mnl_attr_get_u32(tb[NFTA_LAST_SET]));
+ e->flags |= (1 << NFTNL_EXPR_LAST_SET);
+ }
return 0;
}
@@ -103,7 +120,10 @@ static int nftnl_expr_last_snprintf(char *buf, size_t len,
{
struct nftnl_expr_last *last = nftnl_expr_data(e);
- return snprintf(buf, len, "last %"PRIu64" ", last->msecs);
+ if (!last->set)
+ return snprintf(buf, len, "never ");
+
+ return snprintf(buf, len, "%"PRIu64" ", last->msecs);
}
struct expr_ops expr_ops_last = {
diff --git a/src/expr/meta.c b/src/expr/meta.c
index 34fbb9b..601248f 100644
--- a/src/expr/meta.c
+++ b/src/expr/meta.c
@@ -14,6 +14,7 @@
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
+#include <net/if.h>
#include <linux/netfilter/nf_tables.h>
#include "internal.h"
@@ -132,6 +133,44 @@ nftnl_expr_meta_parse(struct nftnl_expr *e, struct nlattr *attr)
return 0;
}
+static int nftnl_meta_reg_len(const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_meta *meta = nftnl_expr_data(e);
+
+ switch (meta->key) {
+ case NFT_META_IIFNAME:
+ case NFT_META_OIFNAME:
+ case NFT_META_IIFKIND:
+ case NFT_META_OIFKIND:
+ case NFT_META_SDIFNAME:
+ case NFT_META_BRI_IIFNAME:
+ case NFT_META_BRI_OIFNAME:
+ return IFNAMSIZ;
+ case NFT_META_TIME_NS:
+ return sizeof(uint64_t);
+ default:
+ break;
+ }
+
+ return sizeof(uint32_t);
+}
+
+static bool nftnl_meta_reg_cmp(const struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_meta *meta = nftnl_expr_data(e);
+
+ return reg->meta.key == meta->key;
+}
+
+static void nftnl_meta_reg_update(struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_meta *meta = nftnl_expr_data(e);
+
+ reg->meta.key = meta->key;
+}
+
static const char *meta_key2str_array[NFT_META_MAX] = {
[NFT_META_LEN] = "len",
[NFT_META_PROTOCOL] = "protocol",
@@ -217,4 +256,9 @@ struct expr_ops expr_ops_meta = {
.parse = nftnl_expr_meta_parse,
.build = nftnl_expr_meta_build,
.snprintf = nftnl_expr_meta_snprintf,
+ .reg = {
+ .len = nftnl_meta_reg_len,
+ .cmp = nftnl_meta_reg_cmp,
+ .update = nftnl_meta_reg_update,
+ },
};
diff --git a/src/expr/osf.c b/src/expr/osf.c
index 215a681..666b6b7 100644
--- a/src/expr/osf.c
+++ b/src/expr/osf.c
@@ -11,6 +11,7 @@
#include <libnftnl/rule.h>
#define OSF_GENRE_SIZE 32
+#define NFT_OSF_MAXGENRELEN 16
struct nftnl_expr_osf {
enum nft_registers dreg;
@@ -125,6 +126,32 @@ nftnl_expr_osf_parse(struct nftnl_expr *e, struct nlattr *attr)
}
static int
+nftnl_expr_osf_reg_len(const struct nftnl_expr *e)
+{
+ return NFT_OSF_MAXGENRELEN;
+}
+
+static bool
+nftnl_expr_osf_reg_cmp(const struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_osf *osf = nftnl_expr_data(e);
+
+ return reg->osf.ttl == osf->ttl &&
+ reg->osf.flags == osf->flags;
+}
+
+static void
+nftnl_expr_osf_reg_update(struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_osf *osf = nftnl_expr_data(e);
+
+ reg->osf.ttl = osf->ttl;
+ reg->osf.flags = osf->flags;
+}
+
+static int
nftnl_expr_osf_snprintf(char *buf, size_t len,
uint32_t flags, const struct nftnl_expr *e)
{
@@ -148,4 +175,9 @@ struct expr_ops expr_ops_osf = {
.parse = nftnl_expr_osf_parse,
.build = nftnl_expr_osf_build,
.snprintf = nftnl_expr_osf_snprintf,
+ .reg = {
+ .len = nftnl_expr_osf_reg_len,
+ .cmp = nftnl_expr_osf_reg_cmp,
+ .update = nftnl_expr_osf_reg_update,
+ },
};
diff --git a/src/expr/payload.c b/src/expr/payload.c
index 9ccb78e..8b41a9d 100644
--- a/src/expr/payload.c
+++ b/src/expr/payload.c
@@ -203,15 +203,42 @@ nftnl_expr_payload_parse(struct nftnl_expr *e, struct nlattr *attr)
return 0;
}
-static const char *base2str_array[NFT_PAYLOAD_TRANSPORT_HEADER+1] = {
+static int nftnl_payload_reg_len(const struct nftnl_expr *expr)
+{
+ const struct nftnl_expr_payload *payload = nftnl_expr_data(expr);
+
+ return payload->len;
+}
+
+static bool nftnl_payload_reg_cmp(const struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_payload *payload = nftnl_expr_data(e);
+
+ return reg->payload.base == payload->base &&
+ reg->payload.offset == payload->offset &&
+ reg->len >= payload->len;
+}
+
+static void nftnl_payload_reg_update(struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_payload *payload = nftnl_expr_data(e);
+
+ reg->payload.base = payload->base;
+ reg->payload.offset = payload->offset;
+}
+
+static const char *base2str_array[NFT_PAYLOAD_INNER_HEADER + 1] = {
[NFT_PAYLOAD_LL_HEADER] = "link",
[NFT_PAYLOAD_NETWORK_HEADER] = "network",
[NFT_PAYLOAD_TRANSPORT_HEADER] = "transport",
+ [NFT_PAYLOAD_INNER_HEADER] = "inner",
};
static const char *base2str(enum nft_payload_bases base)
{
- if (base > NFT_PAYLOAD_TRANSPORT_HEADER)
+ if (base > NFT_PAYLOAD_INNER_HEADER)
return "unknown";
return base2str_array[base];
@@ -259,4 +286,9 @@ struct expr_ops expr_ops_payload = {
.parse = nftnl_expr_payload_parse,
.build = nftnl_expr_payload_build,
.snprintf = nftnl_expr_payload_snprintf,
+ .reg = {
+ .len = nftnl_payload_reg_len,
+ .cmp = nftnl_payload_reg_cmp,
+ .update = nftnl_payload_reg_update,
+ },
};
diff --git a/src/expr/rt.c b/src/expr/rt.c
index 1ad9b2a..16a1aff 100644
--- a/src/expr/rt.c
+++ b/src/expr/rt.c
@@ -12,6 +12,7 @@
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
+#include <assert.h>
#include <linux/netfilter/nf_tables.h>
#include "internal.h"
@@ -112,6 +113,46 @@ nftnl_expr_rt_parse(struct nftnl_expr *e, struct nlattr *attr)
return 0;
}
+static int nftnl_expr_rt_reg_len(const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_rt *rt = nftnl_expr_data(e);
+
+ switch (rt->key) {
+ case NFT_RT_CLASSID:
+ case NFT_RT_NEXTHOP4:
+ return sizeof(uint32_t);
+ case NFT_RT_NEXTHOP6:
+ return sizeof(uint32_t) * 4;
+ case NFT_RT_TCPMSS:
+ return sizeof(uint16_t);
+ case NFT_RT_XFRM:
+ return sizeof(uint8_t);
+ default:
+ assert(0);
+ break;
+ }
+
+ return sizeof(uint32_t);
+}
+
+static bool
+nftnl_expr_rt_reg_cmp(const struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_rt *rt = nftnl_expr_data(e);
+
+ return reg->rt.key == rt->key;
+}
+
+static void
+nftnl_expr_rt_reg_update(struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_rt *rt = nftnl_expr_data(e);
+
+ reg->rt.key = rt->key;
+}
+
static const char *rt_key2str_array[NFT_RT_MAX + 1] = {
[NFT_RT_CLASSID] = "classid",
[NFT_RT_NEXTHOP4] = "nexthop4",
@@ -163,4 +204,9 @@ struct expr_ops expr_ops_rt = {
.parse = nftnl_expr_rt_parse,
.build = nftnl_expr_rt_build,
.snprintf = nftnl_expr_rt_snprintf,
+ .reg = {
+ .len = nftnl_expr_rt_reg_len,
+ .cmp = nftnl_expr_rt_reg_cmp,
+ .update = nftnl_expr_rt_reg_update,
+ },
};
diff --git a/src/expr/socket.c b/src/expr/socket.c
index 02d86f8..edd28ca 100644
--- a/src/expr/socket.c
+++ b/src/expr/socket.c
@@ -12,6 +12,7 @@
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
+#include <assert.h>
#include <linux/netfilter/nf_tables.h>
#include "internal.h"
@@ -126,6 +127,47 @@ nftnl_expr_socket_parse(struct nftnl_expr *e, struct nlattr *attr)
return 0;
}
+static int
+nftnl_expr_socket_reg_len(const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_socket *socket = nftnl_expr_data(e);
+
+ switch(socket->key) {
+ case NFT_SOCKET_TRANSPARENT:
+ case NFT_SOCKET_WILDCARD:
+ return sizeof(uint8_t);
+ case NFT_SOCKET_MARK:
+ return sizeof(uint32_t);
+ case NFT_SOCKET_CGROUPV2:
+ return sizeof(uint64_t);
+ default:
+ assert(0);
+ break;
+ }
+
+ return sizeof(uint32_t);
+}
+
+static bool
+nftnl_expr_socket_reg_cmp(const struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_socket *socket = nftnl_expr_data(e);
+
+ return reg->socket.key == socket->key &&
+ reg->socket.level == socket->level;
+}
+
+static void
+nftnl_expr_socket_reg_update(struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_socket *socket = nftnl_expr_data(e);
+
+ reg->socket.key = socket->key;
+ reg->socket.level = socket->level;
+}
+
static const char *socket_key2str_array[NFT_SOCKET_MAX + 1] = {
[NFT_SOCKET_TRANSPARENT] = "transparent",
[NFT_SOCKET_MARK] = "mark",
@@ -166,4 +208,9 @@ struct expr_ops expr_ops_socket = {
.parse = nftnl_expr_socket_parse,
.build = nftnl_expr_socket_build,
.snprintf = nftnl_expr_socket_snprintf,
+ .reg = {
+ .len = nftnl_expr_socket_reg_len,
+ .cmp = nftnl_expr_socket_reg_cmp,
+ .update = nftnl_expr_socket_reg_update,
+ },
};
diff --git a/src/expr/xfrm.c b/src/expr/xfrm.c
index c81d14d..7f6d7fe 100644
--- a/src/expr/xfrm.c
+++ b/src/expr/xfrm.c
@@ -10,6 +10,7 @@
#include <stdint.h>
#include <arpa/inet.h>
#include <errno.h>
+#include <assert.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/xfrm.h>
@@ -141,6 +142,51 @@ nftnl_expr_xfrm_parse(struct nftnl_expr *e, struct nlattr *attr)
return 0;
}
+static int
+nftnl_expr_xfrm_reg_len(const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_xfrm *xfrm = nftnl_expr_data(e);
+
+ switch (xfrm->key) {
+ case NFT_XFRM_KEY_REQID:
+ case NFT_XFRM_KEY_SPI:
+ return sizeof(uint32_t);
+ case NFT_XFRM_KEY_DADDR_IP4:
+ case NFT_XFRM_KEY_SADDR_IP4:
+ return sizeof(struct in_addr);
+ case NFT_XFRM_KEY_DADDR_IP6:
+ case NFT_XFRM_KEY_SADDR_IP6:
+ return sizeof(struct in6_addr);
+ default:
+ assert(0);
+ break;
+ }
+
+ return sizeof(struct in_addr);
+}
+
+static bool
+nftnl_expr_xfrm_reg_cmp(const struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_xfrm *xfrm = nftnl_expr_data(e);
+
+ return reg->xfrm.key == xfrm->key &&
+ reg->xfrm.spnum == xfrm->spnum &&
+ reg->xfrm.dir == xfrm->dir;
+}
+
+static void
+nftnl_expr_xfrm_reg_update(struct nftnl_reg *reg,
+ const struct nftnl_expr *e)
+{
+ const struct nftnl_expr_xfrm *xfrm = nftnl_expr_data(e);
+
+ reg->xfrm.key = xfrm->key;
+ reg->xfrm.spnum = xfrm->spnum;
+ reg->xfrm.dir = xfrm->dir;
+}
+
static const char *xfrmkey2str_array[] = {
[NFT_XFRM_KEY_DADDR_IP4] = "daddr4",
[NFT_XFRM_KEY_SADDR_IP4] = "saddr4",
@@ -197,4 +243,9 @@ struct expr_ops expr_ops_xfrm = {
.parse = nftnl_expr_xfrm_parse,
.build = nftnl_expr_xfrm_build,
.snprintf = nftnl_expr_xfrm_snprintf,
+ .reg = {
+ .len = nftnl_expr_xfrm_reg_len,
+ .cmp = nftnl_expr_xfrm_reg_cmp,
+ .update = nftnl_expr_xfrm_reg_update,
+ },
};