This patch adds the generic infrastructure is used to describe the
transformation from abstract syntax tree to target internal
representation.

The target has to define the transformation callbacks:

struct nft_ast_xfrm_desc {
       const struct nft_ast_proto_desc *proto_desc;
       const struct nft_ast_meta_desc  *meta_desc;
};

The protocol and meta description structure provide the callback to
transform internal representation to the corresponding target.

struct nft_ast_{proto,meta}_desc {
       int (*xfrm)(const struct nft_ast_expr *dlexpr,
                   struct nft_ast_xfrm_state *state, void *data);
};

Signed-off-by: Pablo Neira Ayuso <pa...@netfilter.org>
---
 include/net/netfilter/nf_tables_jit.h | 39 +++++++++++++++++++
 net/netfilter/nf_tables_jit.c         | 71 +++++++++++++++++++++++++++++++++++
 2 files changed, 110 insertions(+)

diff --git a/include/net/netfilter/nf_tables_jit.h 
b/include/net/netfilter/nf_tables_jit.h
index 124d3da91b0d..dff3af7ad420 100644
--- a/include/net/netfilter/nf_tables_jit.h
+++ b/include/net/netfilter/nf_tables_jit.h
@@ -81,4 +81,43 @@ void nft_ast_stmt_list_print(struct list_head *stmt_list);
 
 int nft_delinearize(struct list_head *ast_stmt_list, struct nft_rule *rule);
 
+/*
+ * Tree of transformation callback definitions.
+ */
+struct nft_ast_xfrm_state;
+
+/**
+ *     struct nft_ast_proto_desc - nf_tables protocol transformation 
description
+ *
+ *     @xfrm: transformation callback
+ */
+struct nft_ast_proto_desc {
+       int (*xfrm)(const struct nft_ast_expr *dlexpr,
+                   struct nft_ast_xfrm_state *state, void *data);
+};
+
+/**
+ *     struct nft_ast_meta_desc - nf_tables meta transformation description
+ *
+ *     @xfrm: transformation callback
+ */
+struct nft_ast_meta_desc {
+       int (*xfrm)(const struct nft_ast_expr *dlexpr,
+                   struct nft_ast_xfrm_state *state, void *data);
+};
+
+/**
+ *     struct nft_ast_xfrm_desc - nf_tables generic transformation description
+ *
+ *     @key: meta key
+ *     @xfrm: transformation callback
+ */
+struct nft_ast_xfrm_desc {
+       const struct nft_ast_proto_desc *proto_desc;
+       const struct nft_ast_meta_desc  *meta_desc;
+};
+
+int nft_ast_xfrm(const struct list_head *ast_stmt_list,
+                const struct nft_ast_xfrm_desc *base_desc, void *data);
+
 #endif
diff --git a/net/netfilter/nf_tables_jit.c b/net/netfilter/nf_tables_jit.c
index e971b94bbc69..63673ea42be8 100644
--- a/net/netfilter/nf_tables_jit.c
+++ b/net/netfilter/nf_tables_jit.c
@@ -134,3 +134,74 @@ void nft_ast_stmt_list_print(struct list_head *stmt_list)
        }
 }
 EXPORT_SYMBOL_GPL(nft_ast_stmt_list_print);
+
+struct nft_ast_xfrm_state {
+       const struct nft_ast_xfrm_desc *xfrm_desc;
+       void *data;
+};
+
+static int nft_ast_xfrm_relational(const struct nft_ast_expr *dlexpr,
+                                  struct nft_ast_xfrm_state *state)
+{
+       const struct nft_ast_expr *left = dlexpr->relational.left;
+       const struct nft_ast_expr *right = dlexpr->relational.right;
+       const struct nft_ast_xfrm_desc *xfrm_desc = state->xfrm_desc;
+       int err;
+
+       if (right->type != NFT_AST_EXPR_VALUE)
+               return -EOPNOTSUPP;
+
+       switch (left->type) {
+       case NFT_AST_EXPR_META:
+               err = xfrm_desc->meta_desc->xfrm(dlexpr, state, state->data);
+               break;
+       case NFT_AST_EXPR_PAYLOAD:
+               err = xfrm_desc->proto_desc->xfrm(dlexpr, state, state->data);
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return err;
+}
+
+static int nft_ast_xfrm_expr(const struct nft_ast_expr *dlexpr,
+                            struct nft_ast_xfrm_state *state)
+{
+       int err;
+
+       switch (dlexpr->type) {
+       case NFT_AST_EXPR_RELATIONAL:
+               err = nft_ast_xfrm_relational(dlexpr, state);
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return err;
+}
+
+int nft_ast_xfrm(const struct list_head *ast_stmt_list,
+                const struct nft_ast_xfrm_desc *xfrm_desc, void *data)
+{
+       struct nft_ast_xfrm_state state = {
+               .xfrm_desc      = xfrm_desc,
+               .data           = data,
+       };
+       struct nft_ast_stmt *stmt;
+       int err = 0;
+
+       list_for_each_entry(stmt, ast_stmt_list, list) {
+               switch (stmt->type) {
+               case NFT_AST_STMT_EXPR:
+                       err = nft_ast_xfrm_expr(stmt->expr, &state);
+                       if (err < 0)
+                               return err;
+                       break;
+               default:
+                       return -EOPNOTSUPP;
+               }
+       }
+       return err;
+}
+EXPORT_SYMBOL_GPL(nft_ast_xfrm);
-- 
2.11.0

Reply via email to