extern const struct datatype ct_label_type;
extern const struct datatype ct_event_type;
+extern const struct stmt_ops ct_stmt_ops;
+extern const struct stmt_ops notrack_stmt_ops;
+extern const struct stmt_ops flow_offload_stmt_ops;
+
#endif /* NFTABLES_CT_H */
extern const struct exthdr_desc exthdr_mh;
extern const struct datatype mh_type_type;
+extern const struct stmt_ops exthdr_stmt_ops;
+
#endif /* NFTABLES_EXTHDR_H */
bool lhs_is_meta_hour(const struct expr *meta);
+extern const struct stmt_ops meta_stmt_ops;
+
#endif /* NFTABLES_META_H */
const struct proto_desc *find_proto_desc(const struct nftnl_udata *ud);
+extern const struct stmt_ops payload_stmt_ops;
+
#endif /* NFTABLES_PAYLOAD_H */
* struct stmt
*
* @list: rule list node
- * @ops: statement ops
* @location: location where the statement was defined
* @flags: statement flags
+ * @type: statement type
* @union: type specific data
*/
struct stmt {
struct list_head list;
- const struct stmt_ops *ops;
struct location location;
enum stmt_flags flags;
+ enum stmt_types type:8;
union {
struct expr *expr;
extern void stmt_free(struct stmt *stmt);
extern void stmt_list_free(struct list_head *list);
extern void stmt_print(const struct stmt *stmt, struct output_ctx *octx);
+const char *stmt_name(const struct stmt *stmt);
+const struct stmt_ops *stmt_ops(const struct stmt *stmt);
const char *get_rate(uint64_t byte_rate, uint64_t *rate);
const char *get_unit(uint64_t u);
expr_free(stmt->ct.expr);
}
-static const struct stmt_ops ct_stmt_ops = {
+const struct stmt_ops ct_stmt_ops = {
.type = STMT_CT,
.name = "ct",
.print = ct_stmt_print,
nft_print(octx, "notrack");
}
-static const struct stmt_ops notrack_stmt_ops = {
+const struct stmt_ops notrack_stmt_ops = {
.type = STMT_NOTRACK,
.name = "notrack",
.print = notrack_stmt_print,
free_const(stmt->flow.table_name);
}
-static const struct stmt_ops flow_offload_stmt_ops = {
+const struct stmt_ops flow_offload_stmt_ops = {
.type = STMT_FLOW_OFFLOAD,
.name = "flow_offload",
.print = flow_offload_stmt_print,
return -1;
}
-static const char *stmt_name(const struct stmt *stmt)
+const char *stmt_name(const struct stmt *stmt)
{
- switch (stmt->ops->type) {
+ switch (stmt->type) {
case STMT_NAT:
switch (stmt->nat.type) {
case NFT_NAT_SNAT:
break;
}
- return stmt->ops->name;
+ return stmt_ops(stmt)->name;
}
static int stmt_error_range(struct eval_ctx *ctx, const struct stmt *stmt, const struct expr *e)
* require the transformations that are needed for payload matching,
* skip this.
*/
- if (ctx->stmt && ctx->stmt->ops->type == STMT_PAYLOAD)
+ if (ctx->stmt && ctx->stmt->type == STMT_PAYLOAD)
return 0;
switch (expr->etype) {
if (stmt == nstmt)
break;
- if (stmt->ops->type != STMT_EXPRESSION ||
+ if (stmt->type != STMT_EXPRESSION ||
stmt->expr->etype != EXPR_RELATIONAL ||
stmt->expr->right->etype != EXPR_VALUE ||
stmt->expr->left->etype != EXPR_PAYLOAD ||
set_stmt = list_first_entry(&set->stmt_list, struct stmt, list);
list_for_each_entry(elem_stmt, &elem->stmt_list, list) {
- if (set_stmt->ops != elem_stmt->ops) {
+ if (set_stmt->type != elem_stmt->type) {
return stmt_error(ctx, elem_stmt,
"statement mismatch, element expects %s, "
"but %s has type %s",
- elem_stmt->ops->name,
+ stmt_name(elem_stmt),
set_is_map(set->flags) ? "map" : "set",
- set_stmt->ops->name);
+ stmt_name(set_stmt));
}
set_stmt = list_next_entry(set_stmt, list);
}
"conflicting protocols specified: %s vs. %s. You must specify ip or ip6 family in %s statement",
pctx->protocol[PROTO_BASE_NETWORK_HDR].desc->name,
family2str(family),
- stmt->ops->name);
+ stmt_name(stmt));
return 0;
}
if (ctx->nft->debug_mask & NFT_DEBUG_EVALUATION) {
struct error_record *erec;
erec = erec_create(EREC_INFORMATIONAL, &stmt->location,
- "Evaluate %s", stmt->ops->name);
+ "Evaluate %s", stmt_name(stmt));
erec_print(&ctx->nft->output, erec, ctx->nft->debug_mask);
stmt_print(stmt, &ctx->nft->output);
nft_print(&ctx->nft->output, "\n\n");
ctx->stmt_len = 0;
- switch (stmt->ops->type) {
+ switch (stmt->type) {
case STMT_CONNLIMIT:
case STMT_COUNTER:
case STMT_LAST:
case STMT_OPTSTRIP:
return stmt_evaluate_optstrip(ctx, stmt);
default:
- BUG("unknown statement type %s\n", stmt->ops->name);
+ BUG("unknown statement type %d\n", stmt->type);
}
}
expr_free(stmt->exthdr.val);
}
-static const struct stmt_ops exthdr_stmt_ops = {
+const struct stmt_ops exthdr_stmt_ops = {
.type = STMT_EXTHDR,
.name = "exthdr",
.print = exthdr_stmt_print,
static json_t *stmt_print_json(const struct stmt *stmt, struct output_ctx *octx)
{
+ const struct stmt_ops *ops = stmt_ops(stmt);
char buf[1024];
FILE *fp;
- if (stmt->ops->json)
- return stmt->ops->json(stmt, octx);
+ if (ops->json)
+ return ops->json(stmt, octx);
fprintf(stderr, "warning: stmt ops %s have no json callback\n",
- stmt->ops->name);
+ ops->name);
fp = octx->output_fp;
octx->output_fp = fmemopen(buf, 1024, "w");
- stmt->ops->print(stmt, octx);
+ ops->print(stmt, octx);
fclose(octx->output_fp);
octx->output_fp = fp;
expr_free(stmt->meta.expr);
}
-static const struct stmt_ops meta_stmt_ops = {
+const struct stmt_ops meta_stmt_ops = {
.type = STMT_META,
.name = "meta",
.print = meta_stmt_print,
expr_postprocess(ctx, &ctx->stmt->expr);
if (dl->pdctx.prev && ctx->stmt &&
- ctx->stmt->ops->type == dl->pdctx.prev->ops->type &&
+ ctx->stmt->type == dl->pdctx.prev->type &&
expr_may_merge_range(ctx->stmt->expr, dl->pdctx.prev->expr, &op))
expr_postprocess_range(ctx, op);
}
const struct stmt *stmt = rctx->stmt;
bool inner = false;
- switch (stmt->ops->type) {
+ switch (stmt->type) {
case STMT_EXPRESSION:
if (has_inner_desc(stmt->expr->left))
inner = true;
proto_ctx_init(&rctx._dl[1].pctx, NFPROTO_BRIDGE, ctx->debug_mask, true);
list_for_each_entry_safe(stmt, next, &rule->stmts, list) {
- enum stmt_types type = stmt->ops->type;
+ enum stmt_types type = stmt->type;
rctx.stmt = stmt;
dl = rule_update_dl_proto_ctx(&rctx);
struct nftnl_expr *netlink_gen_stmt_stateful(const struct stmt *stmt)
{
- switch (stmt->ops->type) {
+ switch (stmt->type) {
case STMT_CONNLIMIT:
return netlink_gen_connlimit_stmt(stmt);
case STMT_COUNTER:
case STMT_LAST:
return netlink_gen_last_stmt(stmt);
default:
- BUG("unknown stateful statement type %s\n", stmt->ops->name);
+ BUG("unknown stateful statement type %d\n", stmt->type);
}
}
{
struct nftnl_expr *nle;
- switch (stmt->ops->type) {
+ switch (stmt->type) {
case STMT_EXPRESSION:
return netlink_gen_expr(ctx, stmt->expr, NFT_REG_VERDICT);
case STMT_VERDICT:
case STMT_OPTSTRIP:
return netlink_gen_optstrip_stmt(ctx, stmt);
default:
- BUG("unknown statement type %s\n", stmt->ops->name);
+ BUG("unknown statement type %d\n", stmt->type);
}
}
{
struct expr *expr_a, *expr_b;
- if (stmt_a->ops->type != stmt_b->ops->type)
+ if (stmt_a->type != stmt_b->type)
return false;
- switch (stmt_a->ops->type) {
+ switch (stmt_a->type) {
case STMT_EXPRESSION:
expr_a = stmt_a->expr;
expr_b = stmt_b->expr;
{
struct expr *expr_a, *expr_b;
- assert (stmt_a->ops->type == STMT_VERDICT);
+ assert (stmt_a->type == STMT_VERDICT);
expr_a = stmt_a->expr;
expr_b = stmt_b->expr;
uint32_t i;
for (i = 0; i < ctx->num_stmts; i++) {
- if (ctx->stmt[i]->ops->type == STMT_INVALID)
+ if (ctx->stmt[i]->type == STMT_INVALID)
unsupported_exists = true;
if (__stmt_type_eq(stmt, ctx->stmt[i], false))
return true;
}
- switch (stmt->ops->type) {
+ switch (stmt->type) {
case STMT_EXPRESSION:
case STMT_VERDICT:
case STMT_COUNTER:
return false;
}
-static struct stmt_ops unsupported_stmt_ops = {
- .type = STMT_INVALID,
- .name = "unsupported",
-};
-
static int rule_collect_stmts(struct optimize_ctx *ctx, struct rule *rule)
{
+ const struct stmt_ops *ops;
struct stmt *stmt, *clone;
list_for_each_entry(stmt, &rule->stmts, list) {
/* No refcounter available in statement objects, clone it to
* to store in the array of selectors.
*/
- clone = stmt_alloc(&internal_location, stmt->ops);
- switch (stmt->ops->type) {
+ ops = stmt_ops(stmt);
+ clone = stmt_alloc(&internal_location, ops);
+ switch (stmt->type) {
case STMT_EXPRESSION:
if (stmt->expr->op != OP_IMPLICIT &&
stmt->expr->op != OP_EQ) {
- clone->ops = &unsupported_stmt_ops;
+ clone->type = STMT_INVALID;
break;
}
if (stmt->expr->left->etype == EXPR_CONCAT) {
- clone->ops = &unsupported_stmt_ops;
+ clone->type = STMT_INVALID;
break;
}
/* fall-through */
(stmt->nat.proto &&
(stmt->nat.proto->etype == EXPR_MAP ||
stmt->nat.proto->etype == EXPR_VARIABLE))) {
- clone->ops = &unsupported_stmt_ops;
+ clone->type = STMT_INVALID;
break;
}
clone->nat.type = stmt->nat.type;
clone->reject.family = stmt->reject.family;
break;
default:
- clone->ops = &unsupported_stmt_ops;
+ clone->type = STMT_INVALID;
break;
}
uint32_t i;
for (i = 0; i < ctx->num_stmts; i++) {
- if (ctx->stmt[i]->ops->type == STMT_INVALID)
+ if (ctx->stmt[i]->type == STMT_INVALID)
return i;
}
/* this should not happen. */
}
static struct stmt unsupported_stmt = {
- .ops = &unsupported_stmt_ops,
+ .type = STMT_INVALID,
};
static void rule_build_stmt_matrix_stmts(struct optimize_ctx *ctx,
uint32_t i;
for (i = 0; i < ctx->num_stmts; i++) {
- if (ctx->stmt[i]->ops->type != STMT_VERDICT)
+ if (ctx->stmt[i]->type != STMT_VERDICT)
continue;
return i;
for (i = from + 1; i <= to; i++) {
stmt_b = ctx->stmt_matrix[i][merge->stmt[0]];
- switch (stmt_b->ops->type) {
+ switch (stmt_b->type) {
case STMT_VERDICT:
switch (stmt_b->expr->etype) {
case EXPR_MAP:
{
struct stmt *stmt_a = ctx->stmt_matrix[from][merge->stmt[0]];
- switch (stmt_a->ops->type) {
+ switch (stmt_a->type) {
case STMT_EXPRESSION:
merge_expr_stmts(ctx, from, to, merge, stmt_a);
break;
if (!stmt)
continue;
- if (stmt->ops->type == STMT_COUNTER) {
+ if (stmt->type == STMT_COUNTER) {
list_del(&stmt->list);
stmt_free(stmt);
}
if (!stmt)
continue;
- if (stmt->ops->type == STMT_COUNTER) {
+ if (stmt->type == STMT_COUNTER) {
list_del(&stmt->list);
return stmt;
}
if (!ctx->stmt_matrix[from][j])
continue;
- if (ctx->stmt_matrix[from][j]->ops->type == STMT_NAT) {
+ if (ctx->stmt_matrix[from][j]->type == STMT_NAT) {
*nat_type = ctx->stmt_matrix[from][j]->nat.type;
return 0;
}
return -1;
for (i = 0; i < ctx->num_stmts; i++) {
- if (ctx->stmt[i]->ops->type != STMT_NAT ||
+ if (ctx->stmt[i]->type != STMT_NAT ||
ctx->stmt[i]->nat.type != nat_type)
continue;
{
struct expr *nat_expr;
- assert(nat_stmt->ops->type == STMT_NAT);
+ assert(nat_stmt->type == STMT_NAT);
if (nat_stmt->nat.proto) {
if (nat_stmt->nat.addr) {
stmt = ctx->stmt_matrix[i][j];
if (!stmt)
continue;
- if (stmt->ops->type == STMT_NAT) {
+ if (stmt->type == STMT_NAT) {
if ((stmt->nat.type == NFT_NAT_REDIR &&
!stmt->nat.proto) ||
stmt->nat.type == NFT_NAT_MASQ)
if (!stmt)
return false;
- switch (stmt->ops->type) {
+ switch (stmt->type) {
case STMT_VERDICT:
if (stmt->expr->etype == EXPR_MAP)
return true;
for (m = 0; m < ctx->num_stmts; m++) {
if (!ctx->stmt_matrix[i][m])
continue;
- switch (ctx->stmt_matrix[i][m]->ops->type) {
+ switch (ctx->stmt_matrix[i][m]->type) {
case STMT_EXPRESSION:
merge[k].stmt[merge[k].num_stmts++] = m;
break;
counter_arg : PACKETS NUM
{
- assert($<stmt>0->ops->type == STMT_COUNTER);
+ assert($<stmt>0->type == STMT_COUNTER);
$<stmt>0->counter.packets = $2;
}
| BYTES NUM
{
- assert($<stmt>0->ops->type == STMT_COUNTER);
+ assert($<stmt>0->type == STMT_COUNTER);
$<stmt>0->counter.bytes = $2;
}
;
expr_free(stmt->payload.val);
}
-static const struct stmt_ops payload_stmt_ops = {
+const struct stmt_ops payload_stmt_ops = {
.type = STMT_PAYLOAD,
.name = "payload",
.print = payload_stmt_print,
mpz_t bitmask, tmp, tmp2;
unsigned long n;
- assert(stmt->ops->type == STMT_PAYLOAD);
+ assert(stmt->type == STMT_PAYLOAD);
assert(expr->etype == EXPR_BINOP);
payload = expr->left;
void rule_print(const struct rule *rule, struct output_ctx *octx)
{
+ const struct stmt_ops *ops;
const struct stmt *stmt;
list_for_each_entry(stmt, &rule->stmts, list) {
- stmt->ops->print(stmt, octx);
+ ops = stmt_ops(stmt);
+ ops->print(stmt, octx);
if (!list_is_last(&stmt->list, &rule->stmts))
nft_print(octx, " ");
}
}
/* Must not merge across other statements */
- if (stmt->ops->type != STMT_EXPRESSION) {
+ if (stmt->type != STMT_EXPRESSION) {
if (idx >= 2)
payload_do_merge(sa, idx);
idx = 0;
#include <linux/netfilter/nf_log.h>
#include <linux/netfilter/nf_synproxy.h>
-struct stmt *stmt_alloc(const struct location *loc,
- const struct stmt_ops *ops)
+struct stmt *stmt_alloc(const struct location *loc, const struct stmt_ops *ops)
{
struct stmt *stmt;
stmt = xzalloc(sizeof(*stmt));
init_list_head(&stmt->list);
stmt->location = *loc;
- stmt->ops = ops;
+ stmt->type = ops->type;
return stmt;
}
void stmt_free(struct stmt *stmt)
{
+ const struct stmt_ops *ops;
+
if (stmt == NULL)
return;
- if (stmt->ops->destroy)
- stmt->ops->destroy(stmt);
+
+ ops = stmt_ops(stmt);
+ if (ops->destroy)
+ ops->destroy(stmt);
free(stmt);
}
void stmt_print(const struct stmt *stmt, struct output_ctx *octx)
{
- stmt->ops->print(stmt, octx);
+ const struct stmt_ops *ops = stmt_ops(stmt);
+
+ ops->print(stmt, octx);
}
static void expr_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
{
return stmt_alloc(loc, &synproxy_stmt_ops);
}
+
+/* For src/optimize.c */
+static struct stmt_ops invalid_stmt_ops = {
+ .type = STMT_INVALID,
+ .name = "unsupported",
+};
+
+static const struct stmt_ops *__stmt_ops_by_type(enum stmt_types type)
+{
+ switch (type) {
+ case STMT_INVALID: return &invalid_stmt_ops;
+ case STMT_EXPRESSION: return &expr_stmt_ops;
+ case STMT_VERDICT: return &verdict_stmt_ops;
+ case STMT_METER: return &meter_stmt_ops;
+ case STMT_COUNTER: return &counter_stmt_ops;
+ case STMT_PAYLOAD: return &payload_stmt_ops;
+ case STMT_META: return &meta_stmt_ops;
+ case STMT_LIMIT: return &limit_stmt_ops;
+ case STMT_LOG: return &log_stmt_ops;
+ case STMT_REJECT: return &reject_stmt_ops;
+ case STMT_NAT: return &nat_stmt_ops;
+ case STMT_TPROXY: return &tproxy_stmt_ops;
+ case STMT_QUEUE: return &queue_stmt_ops;
+ case STMT_CT: return &ct_stmt_ops;
+ case STMT_SET: return &set_stmt_ops;
+ case STMT_DUP: return &dup_stmt_ops;
+ case STMT_FWD: return &fwd_stmt_ops;
+ case STMT_XT: return &xt_stmt_ops;
+ case STMT_QUOTA: return "a_stmt_ops;
+ case STMT_NOTRACK: return ¬rack_stmt_ops;
+ case STMT_OBJREF: return &objref_stmt_ops;
+ case STMT_EXTHDR: return &exthdr_stmt_ops;
+ case STMT_FLOW_OFFLOAD: return &flow_offload_stmt_ops;
+ case STMT_CONNLIMIT: return &connlimit_stmt_ops;
+ case STMT_MAP: return &map_stmt_ops;
+ case STMT_SYNPROXY: return &synproxy_stmt_ops;
+ case STMT_CHAIN: return &chain_stmt_ops;
+ case STMT_OPTSTRIP: return &optstrip_stmt_ops;
+ case STMT_LAST: return &last_stmt_ops;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+const struct stmt_ops *stmt_ops(const struct stmt *stmt)
+{
+ const struct stmt_ops *ops;
+
+ ops = __stmt_ops_by_type(stmt->type);
+ if (!ops)
+ BUG("Unknown statement type %d\n", stmt->type);
+
+ return ops;
+}