From patchwork Thu Jul 25 17:16:24 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Tomasz Bursztyka X-Patchwork-Id: 261803 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 686F52C0085 for ; Fri, 26 Jul 2013 03:16:53 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756471Ab3GYRQw (ORCPT ); Thu, 25 Jul 2013 13:16:52 -0400 Received: from mga11.intel.com ([192.55.52.93]:53512 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756427Ab3GYRQs (ORCPT ); Thu, 25 Jul 2013 13:16:48 -0400 Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga102.fm.intel.com with ESMTP; 25 Jul 2013 10:16:48 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.89,744,1367996400"; d="scan'208";a="376021615" Received: from unknown (HELO rd-180.ger.corp.intel.com) ([10.252.122.186]) by fmsmga002.fm.intel.com with ESMTP; 25 Jul 2013 10:16:46 -0700 From: Tomasz Bursztyka To: netfilter-devel@vger.kernel.org Cc: Tomasz Bursztyka Subject: [iptables-nftables - RFC v2 PATCH 04/17] nft: Add nft expressions translation engine as a library Date: Thu, 25 Jul 2013 20:16:24 +0300 Message-Id: <1374772597-20548-5-git-send-email-tomasz.bursztyka@linux.intel.com> X-Mailer: git-send-email 1.8.3.2 In-Reply-To: <1374772597-20548-1-git-send-email-tomasz.bursztyka@linux.intel.com> References: <1374772597-20548-1-git-send-email-tomasz.bursztyka@linux.intel.com> MIME-Version: 1.0 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org 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 --- Makefile.am | 3 + configure.ac | 1 + include/nft-translator.h | 81 ++++++ libnfttrans/.nft-translator.c.swp | Bin 0 -> 28672 bytes libnfttrans/Makefile.am | 28 ++ libnfttrans/libnfttrans.pc | 11 + libnfttrans/libnfttrans.pc.in | 11 + libnfttrans/nft-translator.c | 571 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 706 insertions(+) create mode 100644 include/nft-translator.h create mode 100644 libnfttrans/.nft-translator.c.swp 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 --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 + * + * 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 +#include +#include + +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/.nft-translator.c.swp b/libnfttrans/.nft-translator.c.swp new file mode 100644 index 0000000000000000000000000000000000000000..0f94354ee52aee9374279892aa9b04fe93da0dcd GIT binary patch literal 28672 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 EFV{Li$N&HU literal 0 HcmV?d00001 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 + * + * 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 +#include +#include + +#include + +#include + +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]; +} +