static void emit_ct(struct action_context *ctx, bool recirc_next, bool commit) { struct ofpact_conntrack *ct = ofpact_put_CT(ctx->ofpacts); ct->flags |= commit ? NX_CT_F_COMMIT : 0; /* If "recirc" is set, we automatically go to the next table. */ if (recirc_next) { if (ctx->cur_ltable < ctx->n_tables) { ct->recirc_table = ctx->first_ptable + ctx->cur_ltable + 1; } else { action_error(ctx, "\"ct_next\" action not allowed in last table."); return; } } else { ct->recirc_table = NX_CT_RECIRC_NONE; } ct->zone_src.field = mf_from_id(MFF_LOG_CT_ZONE); ct->zone_src.ofs = 0; ct->zone_src.n_bits = 16; /* We do not support ALGs yet. */ ct->alg = 0; /* CT only works with IP, so set up a prerequisite. */ struct expr *expr; char *error; expr = expr_parse_string("ip", ctx->symtab, &error); ovs_assert(!error); ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, expr); }
/* Parses 'prerequisite' as an expression in the context of 'ctx', then adds it * as a conjunction with the existing 'ctx->prereqs'. */ static void add_prerequisite(struct action_context *ctx, const char *prerequisite) { struct expr *expr; char *error; expr = expr_parse_string(prerequisite, ctx->ap->symtab, &error); ovs_assert(!error); ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, expr); }
static void parse_actions(struct action_context *ctx) { /* "drop;" by itself is a valid (empty) set of actions, but it can't be * combined with other actions because that doesn't make sense. */ if (ctx->lexer->token.type == LEX_T_ID && !strcmp(ctx->lexer->token.s, "drop") && lexer_lookahead(ctx->lexer) == LEX_T_SEMICOLON) { lexer_get(ctx->lexer); /* Skip "drop". */ lexer_get(ctx->lexer); /* Skip ";". */ if (ctx->lexer->token.type != LEX_T_END) { action_syntax_error(ctx, "expecting end of input"); } return; } while (ctx->lexer->token.type != LEX_T_END) { if (ctx->lexer->token.type != LEX_T_ID) { action_syntax_error(ctx, NULL); break; } enum lex_type lookahead = lexer_lookahead(ctx->lexer); if (lookahead == LEX_T_EQUALS || lookahead == LEX_T_EXCHANGE || lookahead == LEX_T_LSQUARE) { parse_set_action(ctx); } else if (lexer_match_id(ctx->lexer, "next")) { parse_next_action(ctx); } else if (lexer_match_id(ctx->lexer, "output")) { emit_resubmit(ctx, ctx->output_ptable); } else if (lexer_match_id(ctx->lexer, "ip4.ttl")) { if (lexer_match(ctx->lexer, LEX_T_DECREMENT)) { struct expr *e = expr_parse_string("ip4", ctx->symtab, &ctx->error); ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, e); ofpact_put_DEC_TTL(ctx->ofpacts); } else { action_syntax_error(ctx, "expecting `--'"); } } else if (lexer_match_id(ctx->lexer, "ct_next")) { emit_ct(ctx, true, false); } else if (lexer_match_id(ctx->lexer, "ct_commit")) { emit_ct(ctx, false, true); } else { action_syntax_error(ctx, "expecting action"); } if (!lexer_match(ctx->lexer, LEX_T_SEMICOLON)) { action_syntax_error(ctx, "expecting ';'"); } if (ctx->error) { return; } } }
/* Parses an assignment or exchange action. */ static void parse_set_action(struct action_context *ctx) { struct expr *prereqs; char *error; error = expr_parse_assignment(ctx->lexer, ctx->symtab, ctx->ports, ctx->ofpacts, &prereqs); if (error) { action_error(ctx, "%s", error); free(error); return; } ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, prereqs); }