To support forwarding through neighbour layer from ingress. Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> --- include/libnftnl/expr.h | 2 ++ include/linux/netfilter/nf_tables.h | 4 +++ src/expr/fwd.c | 60 ++++++++++++++++++++++++++++++++++--- 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/include/libnftnl/expr.h b/include/libnftnl/expr.h index 7d222af0784f..219104eb3c37 100644 --- a/include/libnftnl/expr.h +++ b/include/libnftnl/expr.h @@ -238,6 +238,8 @@ enum { enum { NFTNL_EXPR_FWD_SREG_DEV = NFTNL_EXPR_BASE, + NFTNL_EXPR_FWD_SREG_ADDR, + NFTNL_EXPR_FWD_NFPROTO, }; enum { diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h index e8f4b5805743..91449ef1a3a3 100644 --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -1273,10 +1273,14 @@ enum nft_dup_attributes { * enum nft_fwd_attributes - nf_tables fwd expression netlink attributes * * @NFTA_FWD_SREG_DEV: source register of output interface (NLA_U32: nft_register) + * @NFTA_FWD_SREG_ADDR: source register of destination address (NLA_U32: nft_register) + * @NFTA_FWD_NFPROTO: layer 3 family of source register address (NLA_U32: enum nfproto) */ enum nft_fwd_attributes { NFTA_FWD_UNSPEC, NFTA_FWD_SREG_DEV, + NFTA_FWD_SREG_ADDR, + NFTA_FWD_NFPROTO, __NFTA_FWD_MAX }; #define NFTA_FWD_MAX (__NFTA_FWD_MAX - 1) diff --git a/src/expr/fwd.c b/src/expr/fwd.c index 1312ea10b07c..90216066cb07 100644 --- a/src/expr/fwd.c +++ b/src/expr/fwd.c @@ -23,6 +23,8 @@ struct nftnl_expr_fwd { enum nft_registers sreg_dev; + enum nft_registers sreg_addr; + uint32_t nfproto; }; static int nftnl_expr_fwd_set(struct nftnl_expr *e, uint16_t type, @@ -32,7 +34,13 @@ static int nftnl_expr_fwd_set(struct nftnl_expr *e, uint16_t type, switch (type) { case NFTNL_EXPR_FWD_SREG_DEV: - fwd->sreg_dev= *((uint32_t *)data); + fwd->sreg_dev = *((uint32_t *)data); + break; + case NFTNL_EXPR_FWD_SREG_ADDR: + fwd->sreg_addr = *((uint32_t *)data); + break; + case NFTNL_EXPR_FWD_NFPROTO: + fwd->nfproto = *((uint32_t *)data); break; default: return -1; @@ -49,6 +57,12 @@ static const void *nftnl_expr_fwd_get(const struct nftnl_expr *e, case NFTNL_EXPR_FWD_SREG_DEV: *data_len = sizeof(fwd->sreg_dev); return &fwd->sreg_dev; + case NFTNL_EXPR_FWD_SREG_ADDR: + *data_len = sizeof(fwd->sreg_addr); + return &fwd->sreg_addr; + case NFTNL_EXPR_FWD_NFPROTO: + *data_len = sizeof(fwd->nfproto); + return &fwd->nfproto; } return NULL; } @@ -63,6 +77,8 @@ static int nftnl_expr_fwd_cb(const struct nlattr *attr, void *data) switch (type) { case NFTA_FWD_SREG_DEV: + case NFTA_FWD_SREG_ADDR: + case NFTA_FWD_NFPROTO: if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) abi_breakage(); break; @@ -79,6 +95,10 @@ static void nftnl_expr_fwd_build(struct nlmsghdr *nlh, if (e->flags & (1 << NFTNL_EXPR_FWD_SREG_DEV)) mnl_attr_put_u32(nlh, NFTA_FWD_SREG_DEV, htonl(fwd->sreg_dev)); + if (e->flags & (1 << NFTNL_EXPR_FWD_SREG_ADDR)) + mnl_attr_put_u32(nlh, NFTA_FWD_SREG_ADDR, htonl(fwd->sreg_addr)); + if (e->flags & (1 << NFTNL_EXPR_FWD_NFPROTO)) + mnl_attr_put_u32(nlh, NFTA_FWD_NFPROTO, htonl(fwd->nfproto)); } static int nftnl_expr_fwd_parse(struct nftnl_expr *e, struct nlattr *attr) @@ -94,6 +114,14 @@ static int nftnl_expr_fwd_parse(struct nftnl_expr *e, struct nlattr *attr) fwd->sreg_dev = ntohl(mnl_attr_get_u32(tb[NFTA_FWD_SREG_DEV])); e->flags |= (1 << NFTNL_EXPR_FWD_SREG_DEV); } + if (tb[NFTA_FWD_SREG_ADDR]) { + fwd->sreg_addr = ntohl(mnl_attr_get_u32(tb[NFTA_FWD_SREG_ADDR])); + e->flags |= (1 << NFTNL_EXPR_FWD_SREG_ADDR); + } + if (tb[NFTA_FWD_NFPROTO]) { + fwd->nfproto = ntohl(mnl_attr_get_u32(tb[NFTA_FWD_NFPROTO])); + e->flags |= (1 << NFTNL_EXPR_FWD_NFPROTO); + } return ret; } @@ -102,12 +130,18 @@ static int nftnl_expr_fwd_json_parse(struct nftnl_expr *e, json_t *root, struct nftnl_parse_err *err) { #ifdef JSON_PARSING - uint32_t sreg_dev; + uint32_t u32val; int ret; - ret = nftnl_jansson_parse_val(root, "sreg_dev", NFTNL_TYPE_U32, &sreg_dev, err); + ret = nftnl_jansson_parse_val(root, "sreg_dev", NFTNL_TYPE_U32, &u32val, err); + if (ret >= 0) + nftnl_expr_set_u32(e, NFTNL_EXPR_FWD_SREG_DEV, u32val); + ret = nftnl_jansson_parse_val(root, "sreg_addr", NFTNL_TYPE_U32, &u32val, err); if (ret >= 0) - nftnl_expr_set_u32(e, NFTNL_EXPR_FWD_SREG_DEV, sreg_dev); + nftnl_expr_set_u32(e, NFTNL_EXPR_FWD_SREG_ADDR, u32val); + ret = nftnl_jansson_parse_val(root, "nfproto", NFTNL_TYPE_U32, &u32val, err); + if (ret >= 0) + nftnl_expr_set_u32(e, NFTNL_EXPR_FWD_NFPROTO, u32val); return 0; #else @@ -124,6 +158,10 @@ static int nftnl_expr_fwd_export(char *buf, size_t size, if (e->flags & (1 << NFTNL_EXPR_FWD_SREG_DEV)) nftnl_buf_u32(&b, type, fwd->sreg_dev, "sreg_dev"); + if (e->flags & (1 << NFTNL_EXPR_FWD_SREG_ADDR)) + nftnl_buf_u32(&b, type, fwd->sreg_dev, "sreg_addr"); + if (e->flags & (1 << NFTNL_EXPR_FWD_NFPROTO)) + nftnl_buf_u32(&b, type, fwd->nfproto, "nfproto"); return nftnl_buf_done(&b); } @@ -140,6 +178,16 @@ static int nftnl_expr_fwd_snprintf_default(char *buf, size_t len, fwd->sreg_dev); SNPRINTF_BUFFER_SIZE(ret, remain, offset); } + if (e->flags & (1 << NFTNL_EXPR_FWD_SREG_ADDR)) { + ret = snprintf(buf + offset, remain, "sreg_addr %u ", + fwd->sreg_addr); + SNPRINTF_BUFFER_SIZE(ret, remain, offset); + } + if (e->flags & (1 << NFTNL_EXPR_FWD_NFPROTO)) { + ret = snprintf(buf + offset, remain, "nfproto %u ", + fwd->nfproto); + SNPRINTF_BUFFER_SIZE(ret, remain, offset); + } return offset; } @@ -168,6 +216,10 @@ static bool nftnl_expr_fwd_cmp(const struct nftnl_expr *e1, if (e1->flags & (1 << NFTNL_EXPR_FWD_SREG_DEV)) eq &= (f1->sreg_dev == f2->sreg_dev); + if (e1->flags & (1 << NFTNL_EXPR_FWD_SREG_ADDR)) + eq &= (f1->sreg_addr == f2->sreg_addr); + if (e1->flags & (1 << NFTNL_EXPR_FWD_NFPROTO)) + eq &= (f1->nfproto == f2->nfproto); return eq; } -- 2.11.0 -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html