diff mbox

[iptables-nftables,RFC,v3,03/16] nft: Add nft expressions translation engine as a library

Message ID 1376055090-26551-4-git-send-email-tomasz.bursztyka@linux.intel.com
State RFC
Headers show

Commit Message

Tomasz Bursztyka Aug. 9, 2013, 1:31 p.m. UTC
libnfttrans is a generic translation engine from nft expressions to
registered "complex instructions". It works on a simple tree based
pattern matching algorithm.

Idea is to be able to register any kind of expressions suit (or pattern)
linked to a parsing function representing the "complex instruction".
Then, being able to go through the whole expression list of a rule and
retrieving the original complex instructions suit.

This will fix at once the parsing of a rule, taking into account
current compatilbe layer for extentions but also their pure nft version.
As soon as an expression will implement its method to express itself as
pur nft expression the change will be totally transparent.

Once applied on xtables (iptables over nftables), this will allow to
retrieve the exact iptables_command_state structure for instance.
However, such engine is generic enough to be reused in any other tool,
like future arptables and ebtables compatible tool over nftables.

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
---
 Makefile.am                   |   3 +
 configure.ac                  |   1 +
 include/nft-translator.h      |  81 ++++++
 libnfttrans/Makefile.am       |  28 +++
 libnfttrans/libnfttrans.pc    |  11 +
 libnfttrans/libnfttrans.pc.in |  11 +
 libnfttrans/nft-translator.c  | 571 ++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 706 insertions(+)
 create mode 100644 include/nft-translator.h
 create mode 100644 libnfttrans/Makefile.am
 create mode 100644 libnfttrans/libnfttrans.pc
 create mode 100644 libnfttrans/libnfttrans.pc.in
 create mode 100644 libnfttrans/nft-translator.c
diff mbox

Patch

diff --git a/Makefile.am b/Makefile.am
index c38d360..fa762d4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,6 +4,9 @@  ACLOCAL_AMFLAGS  = -I m4
 AUTOMAKE_OPTIONS = foreign subdir-objects
 
 SUBDIRS          = libiptc libxtables
+if ENABLE_NFTABLES
+SUBDIRS		+= libnfttrans
+endif
 if ENABLE_DEVEL
 SUBDIRS         += include
 endif
diff --git a/configure.ac b/configure.ac
index 68f661c..4ca6f65 100644
--- a/configure.ac
+++ b/configure.ac
@@ -207,6 +207,7 @@  AC_CONFIG_FILES([Makefile extensions/GNUmakefile include/Makefile
 	libiptc/Makefile libiptc/libiptc.pc
 	libiptc/libip4tc.pc libiptc/libip6tc.pc
 	libxtables/Makefile utils/Makefile
+	libnfttrans/Makefile libnfttrans/libnfttrans.pc
 	include/xtables-version.h include/iptables/internal.h])
 AC_OUTPUT
 
diff --git a/include/nft-translator.h b/include/nft-translator.h
new file mode 100644
index 0000000..318f248
--- /dev/null
+++ b/include/nft-translator.h
@@ -0,0 +1,81 @@ 
+/*
+ * (C) 2013 by Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _NFT_TRANSLATOR_H
+#define _NFT_TRANSLATOR_H
+
+#include <stdint.h>
+#include <libnftables/rule.h>
+#include <libnftables/expr.h>
+
+enum nft_instruction {
+	NFT_INSTRUCTION_BITWISE   = 0,
+	NFT_INSTRUCTION_BYTEORDER = 1,
+	NFT_INSTRUCTION_CMP       = 2,
+	NFT_INSTRUCTION_COUNTER   = 3,
+	NFT_INSTRUCTION_CT        = 4,
+	NFT_INSTRUCTION_EXTHDR    = 5,
+	NFT_INSTRUCTION_IMMEDIATE = 6,
+	NFT_INSTRUCTION_LIMIT     = 7,
+	NFT_INSTRUCTION_LOG       = 8,
+	NFT_INSTRUCTION_LOOKUP    = 9,
+	NFT_INSTRUCTION_MATCH     = 10,
+	NFT_INSTRUCTION_META      = 11,
+	NFT_INSTRUCTION_NAT       = 12,
+	NFT_INSTRUCTION_PAYLOAD   = 13,
+	NFT_INSTRUCTION_REJECT    = 14,
+	NFT_INSTRUCTION_TARGET    = 15,
+	NFT_INSTRUCTION_MAX       = 16,
+};
+
+struct nft_trans_instruction_tree;
+struct nft_trans_rule_context;
+struct nft_trans_instruction_context;
+
+typedef int (*nft_trans_parse_callback_f)(const char *ident,
+					  void *data,
+					  void *user_data);
+
+typedef int
+(*nft_trans_parse_instruction_f)(struct nft_trans_rule_context *rule_ctx,
+				 struct nft_trans_instruction_context *first,
+				 struct nft_trans_instruction_context *last,
+				 nft_trans_parse_callback_f user_cb,
+				 void *user_data);
+
+struct nft_trans_instruction {
+	enum nft_instruction *instructions;
+	nft_trans_parse_instruction_f function;
+};
+
+struct nft_trans_instruction_tree *nft_trans_instruction_tree_new(void);
+
+void
+nft_trans_instruction_tree_destroy(struct nft_trans_instruction_tree *tree);
+
+int nft_trans_add_instruction(struct nft_trans_instruction_tree *tree,
+			      struct nft_trans_instruction *ipt_i);
+
+int
+nft_trans_rule_translate_to_instructions(struct nft_trans_instruction_tree *tree,
+					 struct nft_rule *rule,
+					 nft_trans_parse_callback_f user_cb,
+					 void *user_data);
+
+struct nft_trans_instruction_context *
+nft_trans_instruction_context_get_next(struct nft_trans_instruction_context *i_ctx);
+
+struct nft_rule_expr *
+nft_trans_instruction_context_get_expr(struct nft_trans_instruction_context *i_ctx);
+
+struct nft_rule_expr *
+nft_trans_instruction_context_get_register(struct nft_trans_instruction_context *i_ctx,
+					   int reg);
+
+#endif /* _NFT_TRANSLATOR_H */
diff --git a/libnfttrans/Makefile.am b/libnfttrans/Makefile.am
new file mode 100644
index 0000000..5befb63
--- /dev/null
+++ b/libnfttrans/Makefile.am
@@ -0,0 +1,28 @@ 
+# -*- Makefile -*-
+if ENABLE_NFTABLES
+if HAVE_LIBMNL
+if HAVE_LIBNFTABLES
+
+AM_CFLAGS   = ${regular_CFLAGS}
+AM_CPPFLAGS = ${regular_CPPFLAGS}  -I${top_builddir}/include \
+		-I${top_srcdir}/include  -I./ ${kinclude_CPPFLAGS}
+
+lib_LTLIBRARIES       = libnfttrans.la
+libnfttrans_la_SOURCES = nft-translator.c
+libnfttrans_la_LDFLAGS =
+libnfttrans_la_LIBADD  =
+if ENABLE_STATIC
+# With --enable-static, shipped extensions are linked into the main executable,
+# so we need all the LIBADDs here too
+libnfttrans_la_LIBADD += -lm
+endif
+if ENABLE_SHARED
+libnfttrans_la_CFLAGS  = ${AM_CFLAGS}
+libnfttrans_la_LIBADD += -ldl
+else
+libnfttrans_la_CFLAGS  = ${AM_CFLAGS} -DNO_SHARED_LIBS=1
+endif
+
+endif # HAVE_LIBNFTABLES
+endif # HAVE_LIBMNL
+endif # ENABLE_NFTABLES
diff --git a/libnfttrans/libnfttrans.pc b/libnfttrans/libnfttrans.pc
new file mode 100644
index 0000000..fe0b4c0
--- /dev/null
+++ b/libnfttrans/libnfttrans.pc
@@ -0,0 +1,11 @@ 
+
+prefix=/usr
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name:		libnfttrans
+Description:	Small engine to translate nft expressions list into more complex registered subset
+Version:	1.4.19.1
+Libs:		-L${libdir} -lnfttrans
+Cflags:		-I${includedir}
diff --git a/libnfttrans/libnfttrans.pc.in b/libnfttrans/libnfttrans.pc.in
new file mode 100644
index 0000000..f3363de
--- /dev/null
+++ b/libnfttrans/libnfttrans.pc.in
@@ -0,0 +1,11 @@ 
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name:		libnfttrans
+Description:	Small engine to translate nft expressions list into more complex registered subset
+Version:	@PACKAGE_VERSION@
+Libs:		-L${libdir} -lnfttrans
+Cflags:		-I${includedir}
diff --git a/libnfttrans/nft-translator.c b/libnfttrans/nft-translator.c
new file mode 100644
index 0000000..12bd7e5
--- /dev/null
+++ b/libnfttrans/nft-translator.c
@@ -0,0 +1,571 @@ 
+/*
+ * (C) 2013 by Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <linux/netfilter/nf_tables.h>
+
+#include <nft-translator.h>
+
+static const char *nft_instruction_name[NFT_INSTRUCTION_MAX] = {
+	"bitwise",
+	"byteorder",
+	"cmp",
+	"counter",
+	"ct",
+	"exthdr",
+	"immediate",
+	"limit",
+	"log",
+	"lookup",
+	"match",
+	"meta",
+	"nat",
+	"payload",
+	"reject",
+	"target",
+};
+
+typedef void (*free_function_f)(void *);
+
+struct s_list {
+	void *data;
+	struct s_list *next;
+};
+
+struct nft_trans_instruction_node {
+	struct s_list *functions;
+	struct nft_trans_instruction_node *nodes[NFT_INSTRUCTION_MAX];
+};
+
+struct nft_trans_instruction_tree {
+	struct s_list *nodes;
+	struct nft_trans_instruction_node *root;
+};
+
+struct nft_trans_register_context {
+	struct nft_rule_expr *reg[NFT_REG_MAX];
+};
+
+struct nft_trans_instruction_context {
+	struct nft_trans_instruction_context *next;
+
+	struct nft_rule_expr *current_expr;
+	enum nft_instruction instruction;
+	struct nft_trans_register_context *registers;
+};
+
+struct nft_trans_rule_context {
+	struct nft_trans_instruction_context *instr_contexts;
+};
+
+struct nft_trans_found_instruction {
+	const struct s_list *functions;
+	struct nft_trans_instruction_context *position;
+};
+
+static enum nft_instruction str2nft_intruction(const char *name)
+{
+	enum nft_instruction i;
+
+	for (i = 0; i < NFT_INSTRUCTION_MAX; i++) {
+		 if (strncmp(nft_instruction_name[i], name,
+					strlen(nft_instruction_name[i])) == 0)
+			 return i;
+	}
+
+	return NFT_INSTRUCTION_MAX;
+}
+
+static struct s_list *s_list_prepend(struct s_list *list, void *data)
+{
+	struct s_list *n_list;
+
+	n_list = calloc(1, sizeof(struct s_list));
+	if (n_list == NULL)
+		return list;
+
+	n_list->data = data;
+	n_list->next = list;
+
+	return n_list;
+}
+
+static void s_list_free(struct s_list *list, int data_too,
+			 free_function_f _free)
+{
+	struct s_list *previous = NULL;
+
+	for (; list != NULL; list = list->next) {
+		if (previous != NULL) {
+			if (previous->data != NULL && data_too != 0) {
+				if (_free != NULL)
+					_free(previous->data);
+				else
+					free(previous->data);
+			}
+
+			free(previous);
+		}
+
+		previous = list;
+	}
+
+	if (previous != NULL) {
+		if (previous->data != NULL && data_too != 0) {
+			if (_free != NULL)
+				_free(previous->data);
+			else
+				free(previous->data);
+		}
+
+		free(previous);
+	}
+}
+
+struct nft_trans_instruction_tree *nft_trans_instruction_tree_new(void)
+{
+	struct nft_trans_instruction_tree *tree;
+
+	tree = calloc(1, sizeof(struct nft_trans_instruction_tree));
+	if (tree != NULL) {
+		tree->root = calloc(1, sizeof(struct nft_trans_instruction_node));
+		if (tree->root == NULL)
+			goto error;
+
+		tree->nodes = s_list_prepend(tree->nodes, tree->root);
+		if (tree->nodes == NULL)
+			goto error;
+	}
+
+	return tree;
+
+error:
+	free(tree);
+	return NULL;
+}
+
+static void _free_nft_trans_instruction_node(void *data)
+{
+	struct nft_trans_instruction_node *node = data;
+
+	if (node == NULL)
+		return;
+
+	s_list_free(node->functions, 0, NULL);
+	free(node);
+}
+
+void
+nft_trans_instruction_tree_destroy(struct nft_trans_instruction_tree *tree)
+{
+	if (tree == NULL)
+		return;
+
+	s_list_free(tree->nodes, 1, _free_nft_trans_instruction_node);
+	free(tree);
+}
+
+int nft_trans_add_instruction(struct nft_trans_instruction_tree *tree,
+			      struct nft_trans_instruction *ipt_i)
+{
+	struct nft_trans_instruction_node *node;
+	enum nft_instruction *instr;
+
+	if (tree == NULL)
+		return -EINVAL;
+
+	node = tree->root;
+	for (instr = ipt_i->instructions;
+				*instr < NFT_INSTRUCTION_MAX; instr++) {
+		if (node->nodes[*instr] == NULL) {
+			node->nodes[*instr] = calloc(1,
+					sizeof(struct nft_trans_instruction_node));
+			if (node->nodes[*instr] == NULL)
+				return -ENOMEM;
+		}
+
+		node = node->nodes[*instr];
+		tree->nodes = s_list_prepend(tree->nodes, node);
+	}
+
+	node->functions = s_list_prepend(node->functions, ipt_i->function);
+
+	return 0;
+}
+
+static void
+free_nft_trans_instruction_context(struct nft_trans_instruction_context *i_ctx)
+{
+	if (i_ctx == NULL)
+		return;
+
+	free(i_ctx->registers);
+	free(i_ctx);
+}
+
+static void
+destroy_nft_trans_rule_context(struct nft_trans_rule_context *rule_ctx)
+{
+	if (rule_ctx == NULL)
+		return;
+
+	if (rule_ctx->instr_contexts != NULL) {
+		struct nft_trans_instruction_context *i_ctx, *prev = NULL;
+
+		for (i_ctx = rule_ctx->instr_contexts;
+					i_ctx != NULL; i_ctx = i_ctx->next) {
+			free_nft_trans_instruction_context(prev);
+			prev = i_ctx;
+		}
+
+		free_nft_trans_instruction_context(prev);
+	}
+
+	free(rule_ctx);
+}
+
+static void
+update_register_from_bitwise(struct nft_rule_expr *expr,
+			     struct nft_trans_register_context *registers)
+{
+	if (nft_rule_expr_is_set(expr, NFT_EXPR_BITWISE_DREG))
+		registers->reg[nft_rule_expr_get_u32(expr,
+						NFT_EXPR_BITWISE_DREG)] = expr;
+}
+
+static void
+update_register_from_byteorder(struct nft_rule_expr *expr,
+			       struct nft_trans_register_context *registers)
+{
+	if (nft_rule_expr_is_set(expr, NFT_EXPR_BYTEORDER_DREG))
+		registers->reg[nft_rule_expr_get_u32(expr,
+					NFT_EXPR_BYTEORDER_DREG)] = expr;
+}
+
+static void
+update_register_from_ct(struct nft_rule_expr *expr,
+			struct nft_trans_register_context *registers)
+{
+	if (nft_rule_expr_is_set(expr, NFT_EXPR_CT_DREG))
+		registers->reg[nft_rule_expr_get_u32(expr,
+						NFT_EXPR_CT_DREG)] = expr;
+}
+
+static void
+update_register_from_exthdr(struct nft_rule_expr *expr,
+			    struct nft_trans_register_context *registers)
+{
+	if (nft_rule_expr_is_set(expr, NFT_EXPR_EXTHDR_DREG))
+		registers->reg[nft_rule_expr_get_u32(expr,
+						NFT_EXPR_EXTHDR_DREG)] = expr;
+}
+
+static void
+update_register_from_immediate(struct nft_rule_expr *expr,
+			       struct nft_trans_register_context *registers)
+{
+	if (nft_rule_expr_is_set(expr, NFT_EXPR_IMM_DREG))
+		registers->reg[nft_rule_expr_get_u32(expr,
+						NFT_EXPR_IMM_DREG)] = expr;
+}
+
+static void
+update_register_from_lookup(struct nft_rule_expr *expr,
+			    struct nft_trans_register_context *registers)
+{
+	if (nft_rule_expr_is_set(expr, NFT_EXPR_LOOKUP_DREG))
+		registers->reg[nft_rule_expr_get_u32(expr,
+						NFT_EXPR_LOOKUP_DREG)] = expr;
+}
+
+static void
+update_register_from_meta(struct nft_rule_expr *expr,
+			  struct nft_trans_register_context *registers)
+{
+	if (nft_rule_expr_is_set(expr, NFT_EXPR_META_DREG))
+		registers->reg[nft_rule_expr_get_u32(expr,
+						NFT_EXPR_META_DREG)] = expr;
+}
+
+static void
+update_register_from_payload(struct nft_rule_expr *expr,
+			     struct nft_trans_register_context *registers)
+{
+	if (nft_rule_expr_is_set(expr, NFT_EXPR_PAYLOAD_DREG))
+		registers->reg[nft_rule_expr_get_u32(expr,
+						NFT_EXPR_PAYLOAD_DREG)] = expr;
+}
+
+static struct nft_trans_register_context *
+update_registers(enum nft_instruction instruction, struct nft_rule_expr *expr,
+		 struct nft_trans_register_context *registers)
+{
+	struct nft_trans_register_context *new_registers;
+
+	new_registers = calloc(1, sizeof(struct nft_trans_register_context));
+	if (new_registers == NULL)
+		return NULL;
+
+	memcpy(new_registers, registers, sizeof(struct nft_trans_register_context));
+
+	switch (instruction) {
+	case NFT_INSTRUCTION_BITWISE:
+		update_register_from_bitwise(expr, new_registers);
+		break;
+	case NFT_INSTRUCTION_BYTEORDER:
+		update_register_from_byteorder(expr, new_registers);
+		break;
+	case NFT_INSTRUCTION_CMP:
+	case NFT_INSTRUCTION_COUNTER:
+		break;
+	case NFT_INSTRUCTION_CT:
+		update_register_from_ct(expr, new_registers);
+		break;
+	case NFT_INSTRUCTION_EXTHDR:
+		update_register_from_exthdr(expr, new_registers);
+		break;
+	case NFT_INSTRUCTION_IMMEDIATE:
+		update_register_from_immediate(expr, new_registers);
+		break;
+	case NFT_INSTRUCTION_LIMIT:
+	case NFT_INSTRUCTION_LOG:
+		break;
+	case NFT_INSTRUCTION_LOOKUP:
+		update_register_from_lookup(expr, new_registers);
+		break;
+	case NFT_INSTRUCTION_MATCH:
+		break;
+	case NFT_INSTRUCTION_META:
+		update_register_from_meta(expr, new_registers);
+		break;
+	case NFT_INSTRUCTION_NAT:
+		break;
+	case NFT_INSTRUCTION_PAYLOAD:
+		update_register_from_payload(expr, new_registers);
+		break;
+	case NFT_INSTRUCTION_REJECT:
+	case NFT_INSTRUCTION_TARGET:
+		break;
+	case NFT_INSTRUCTION_MAX:
+		return NULL;
+	};
+
+	return new_registers;
+}
+
+static struct nft_trans_rule_context *
+generate_nft_trans_rule_context(struct nft_rule *rule)
+{
+	struct nft_trans_instruction_context *cur_ctx = NULL;
+	struct nft_trans_register_context *cur_regs = NULL;
+	struct nft_trans_rule_context *rule_ctx;
+	struct nft_rule_expr_iter *iter;
+	struct nft_rule_expr *expr;
+
+	rule_ctx = calloc(1, sizeof(struct nft_trans_rule_context));
+	if (rule_ctx == NULL)
+		return NULL;
+
+	iter = nft_rule_expr_iter_create(rule);
+	if (iter == NULL)
+		goto error;
+
+	cur_regs = calloc(1, sizeof(struct nft_trans_register_context));
+	if (cur_regs == NULL)
+		goto error;
+
+	expr = nft_rule_expr_iter_next(iter);
+	while (expr != NULL) {
+		struct nft_trans_instruction_context *ctx;
+		enum nft_instruction instr;
+
+		ctx = calloc(1, sizeof(struct nft_trans_instruction_context));
+		if (ctx == NULL)
+			goto error;
+
+		instr = str2nft_intruction(nft_rule_expr_get_str(expr,
+						NFT_RULE_EXPR_ATTR_NAME));
+		if (instr == NFT_INSTRUCTION_MAX)
+			goto error;
+
+		ctx->current_expr = expr;
+		ctx->instruction = instr;
+		ctx->registers = cur_regs;
+
+		if (cur_ctx == NULL)
+			rule_ctx->instr_contexts = ctx;
+		else
+			cur_ctx->next = ctx;
+
+		cur_ctx = ctx;
+
+		cur_regs = update_registers(instr, expr, cur_regs);
+		if (cur_regs == NULL)
+			goto error;
+
+		expr = nft_rule_expr_iter_next(iter);
+	}
+
+	if (cur_regs != NULL)
+		free(cur_regs);
+
+	nft_rule_expr_iter_destroy(iter);
+
+	return rule_ctx;
+
+error:
+	destroy_nft_trans_rule_context(rule_ctx);
+
+	if (cur_regs != NULL)
+		free(cur_regs);
+
+	if (iter != NULL)
+		nft_rule_expr_iter_destroy(iter);
+
+	return NULL;
+}
+
+static struct s_list *
+retrieve_nft_trans_instructions(struct nft_trans_instruction_tree *tree,
+				struct nft_trans_instruction_context *instructions)
+{
+	struct s_list *nft_trans_instructions = NULL;
+	struct nft_trans_instruction_context *ctx;
+	struct nft_trans_found_instruction *ipt_i;
+	struct nft_trans_instruction_node *node;
+
+	ctx = instructions;
+	node = tree->root;
+
+	while (ctx != NULL) {
+		if (node->nodes[ctx->instruction] != NULL) {
+			node = node->nodes[ctx->instruction];
+
+			if (node->functions != NULL) {
+				ipt_i = calloc(1,
+					sizeof(struct nft_trans_found_instruction));
+
+				ipt_i->functions = node->functions;
+				ipt_i->position = ctx;
+
+				/* It prepends since "longest path first"
+				 * is applied */
+				nft_trans_instructions = s_list_prepend(
+						nft_trans_instructions, ipt_i);
+			}
+		} else
+			break;
+
+		ctx = ctx->next;
+	};
+
+	return nft_trans_instructions;
+}
+
+static struct nft_trans_instruction_context *
+execute_relevant_instruction(struct s_list *instructions,
+			     struct nft_trans_rule_context *rule_ctx,
+			     struct nft_trans_instruction_context *position,
+			     nft_trans_parse_callback_f user_cb,
+			     void *user_data)
+{
+	for (; instructions != NULL; instructions = instructions->next) {
+		struct nft_trans_found_instruction *i_f = instructions->data;
+		const struct s_list *fl;
+
+		for (fl = i_f->functions; fl != NULL; fl = fl->next) {
+			nft_trans_parse_instruction_f function = fl->data;
+
+			if (function(rule_ctx, position, i_f->position,
+						user_cb, user_data) == 0)
+				return i_f->position;
+		}
+	}
+
+	return NULL;
+}
+
+int
+nft_trans_rule_translate_to_instructions(struct nft_trans_instruction_tree *tree,
+					 struct nft_rule *rule,
+					 nft_trans_parse_callback_f user_cb,
+					 void *user_data)
+{
+	struct nft_trans_instruction_context *position;
+	struct s_list *nft_trans_instructions;
+	struct nft_trans_rule_context *rule_ctx;
+
+	if (tree == NULL)
+		return -1;
+
+	rule_ctx = generate_nft_trans_rule_context(rule);
+	if (rule_ctx == NULL)
+		return -1;
+
+	position = rule_ctx->instr_contexts;
+	while (position != NULL) {
+		struct nft_trans_instruction_context *pos;
+
+		nft_trans_instructions = retrieve_nft_trans_instructions(tree,
+								position);
+		if (nft_trans_instructions == NULL)
+			goto error;
+
+		pos = execute_relevant_instruction(nft_trans_instructions,
+				rule_ctx, position, user_cb, user_data);
+		if (pos == NULL)
+			goto error;
+
+		s_list_free(nft_trans_instructions, 1, NULL);
+		position = pos->next;
+	}
+
+	destroy_nft_trans_rule_context(rule_ctx);
+
+	return 0;
+
+error:
+	s_list_free(nft_trans_instructions, 1, NULL);
+	destroy_nft_trans_rule_context(rule_ctx);
+
+	return -1;
+}
+
+struct nft_trans_instruction_context *
+nft_trans_instruction_context_get_next(struct nft_trans_instruction_context *i_ctx)
+{
+	if (i_ctx == NULL)
+		return NULL;
+
+	return i_ctx->next;
+}
+
+struct nft_rule_expr *
+nft_trans_instruction_context_get_expr(struct nft_trans_instruction_context *i_ctx)
+{
+	if (i_ctx == NULL)
+		return NULL;
+
+	return i_ctx->current_expr;
+}
+
+struct nft_rule_expr *
+nft_trans_instruction_context_get_register(struct nft_trans_instruction_context *i_ctx,
+					int register_index)
+{
+	if (i_ctx == NULL || i_ctx->registers == NULL ||
+					register_index >= NFT_REG_MAX)
+		return NULL;
+
+	return i_ctx->registers->reg[register_index];
+}
+