2 * Copyright (c) 2015 Nicira, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
22 #include "dynamic-string.h"
25 #include "logical-fields.h"
26 #include "ofp-actions.h"
30 /* Context maintained during actions_parse(). */
31 struct action_context {
34 struct lexer *lexer; /* Lexer for pulling more tokens. */
35 const struct simap *ports; /* Map from port name to number. */
36 const struct shash *symtab; /* Symbol table. */
38 /* OVN maps each logical flow table (ltable), one-to-one, onto a physical
39 * OpenFlow flow table (ptable). These members describe the mapping and
40 * data related to flow tables. */
41 uint8_t n_tables; /* Number of flow tables. */
42 uint8_t first_ptable; /* First OpenFlow table. */
43 uint8_t cur_ltable; /* 0 <= cur_ltable < n_tables. */
44 uint8_t output_ptable; /* OpenFlow table for 'output' to resubmit. */
45 const struct simap *ct_zones; /* Map from port name to conntrack zone. */
48 char *error; /* Error, if any, otherwise NULL. */
51 struct ofpbuf *ofpacts; /* Actions. */
52 struct expr *prereqs; /* Prerequisites to apply to match. */
55 static bool parse_action(struct action_context *);
58 action_error_handle_common(struct action_context *ctx)
61 /* Already have an error, suppress this one since the cascade seems
62 * unlikely to be useful. */
64 } else if (ctx->lexer->token.type == LEX_T_ERROR) {
65 /* The lexer signaled an error. Nothing at the action level
66 * accepts an error token, so we'll inevitably end up here with some
67 * meaningless parse error. Report the lexical error instead. */
68 ctx->error = xstrdup(ctx->lexer->token.s);
75 static void OVS_PRINTF_FORMAT(2, 3)
76 action_error(struct action_context *ctx, const char *message, ...)
78 if (action_error_handle_common(ctx)) {
83 va_start(args, message);
84 ctx->error = xvasprintf(message, args);
88 static void OVS_PRINTF_FORMAT(2, 3)
89 action_syntax_error(struct action_context *ctx, const char *message, ...)
91 if (action_error_handle_common(ctx)) {
98 ds_put_cstr(&s, "Syntax error");
99 if (ctx->lexer->token.type == LEX_T_END) {
100 ds_put_cstr(&s, " at end of input");
101 } else if (ctx->lexer->start) {
102 ds_put_format(&s, " at `%.*s'",
103 (int) (ctx->lexer->input - ctx->lexer->start),
108 ds_put_char(&s, ' ');
111 va_start(args, message);
112 ds_put_format_valist(&s, message, args);
115 ds_put_char(&s, '.');
117 ctx->error = ds_steal_cstr(&s);
120 /* Parses an assignment or exchange action. */
122 parse_set_action(struct action_context *ctx)
124 struct expr *prereqs;
127 error = expr_parse_assignment(ctx->lexer, ctx->symtab, ctx->ports,
128 ctx->ofpacts, &prereqs);
130 action_error(ctx, "%s", error);
135 ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, prereqs);
139 emit_resubmit(struct action_context *ctx, uint8_t table_id)
141 struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(ctx->ofpacts);
142 resubmit->in_port = OFPP_IN_PORT;
143 resubmit->table_id = table_id;
147 action_get_int(struct action_context *ctx, int *value)
149 bool ok = lexer_get_int(ctx->lexer, value);
151 action_syntax_error(ctx, "expecting small integer");
157 parse_next_action(struct action_context *ctx)
159 if (!ctx->n_tables) {
160 action_error(ctx, "\"next\" action not allowed here.");
161 } else if (lexer_match(ctx->lexer, LEX_T_LPAREN)) {
164 if (!action_get_int(ctx, <able)) {
167 if (!lexer_match(ctx->lexer, LEX_T_RPAREN)) {
168 action_syntax_error(ctx, "expecting `)'");
172 if (ltable >= ctx->n_tables) {
173 action_error(ctx, "\"next\" argument must be in range 0 to %d.",
178 emit_resubmit(ctx, ctx->first_ptable + ltable);
180 if (ctx->cur_ltable < ctx->n_tables) {
181 emit_resubmit(ctx, ctx->first_ptable + ctx->cur_ltable + 1);
183 action_error(ctx, "\"next\" action not allowed in last table.");
188 /* Parses 'prerequisite' as an expression in the context of 'ctx', then adds it
189 * as a conjunction with the existing 'ctx->prereqs'. */
191 add_prerequisite(struct action_context *ctx, const char *prerequisite)
196 expr = expr_parse_string(prerequisite, ctx->symtab, &error);
198 ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, expr);
202 emit_ct(struct action_context *ctx, bool recirc_next, bool commit)
204 struct ofpact_conntrack *ct = ofpact_put_CT(ctx->ofpacts);
205 ct->flags |= commit ? NX_CT_F_COMMIT : 0;
207 /* If "recirc" is set, we automatically go to the next table. */
209 if (ctx->cur_ltable < ctx->n_tables) {
210 ct->recirc_table = ctx->first_ptable + ctx->cur_ltable + 1;
212 action_error(ctx, "\"ct_next\" action not allowed in last table.");
216 ct->recirc_table = NX_CT_RECIRC_NONE;
219 ct->zone_src.field = mf_from_id(MFF_LOG_CT_ZONE);
220 ct->zone_src.ofs = 0;
221 ct->zone_src.n_bits = 16;
223 /* We do not support ALGs yet. */
226 /* CT only works with IP, so set up a prerequisite. */
227 add_prerequisite(ctx, "ip");
231 parse_action(struct action_context *ctx)
233 if (ctx->lexer->token.type != LEX_T_ID) {
234 action_syntax_error(ctx, NULL);
238 enum lex_type lookahead = lexer_lookahead(ctx->lexer);
239 if (lookahead == LEX_T_EQUALS || lookahead == LEX_T_EXCHANGE
240 || lookahead == LEX_T_LSQUARE) {
241 parse_set_action(ctx);
242 } else if (lexer_match_id(ctx->lexer, "next")) {
243 parse_next_action(ctx);
244 } else if (lexer_match_id(ctx->lexer, "output")) {
245 emit_resubmit(ctx, ctx->output_ptable);
246 } else if (lexer_match_id(ctx->lexer, "ip.ttl")) {
247 if (lexer_match(ctx->lexer, LEX_T_DECREMENT)) {
248 add_prerequisite(ctx, "ip");
249 ofpact_put_DEC_TTL(ctx->ofpacts);
251 action_syntax_error(ctx, "expecting `--'");
253 } else if (lexer_match_id(ctx->lexer, "ct_next")) {
254 emit_ct(ctx, true, false);
255 } else if (lexer_match_id(ctx->lexer, "ct_commit")) {
256 emit_ct(ctx, false, true);
258 action_syntax_error(ctx, "expecting action");
260 if (!lexer_match(ctx->lexer, LEX_T_SEMICOLON)) {
261 action_syntax_error(ctx, "expecting ';'");
267 parse_actions(struct action_context *ctx)
269 /* "drop;" by itself is a valid (empty) set of actions, but it can't be
270 * combined with other actions because that doesn't make sense. */
271 if (ctx->lexer->token.type == LEX_T_ID
272 && !strcmp(ctx->lexer->token.s, "drop")
273 && lexer_lookahead(ctx->lexer) == LEX_T_SEMICOLON) {
274 lexer_get(ctx->lexer); /* Skip "drop". */
275 lexer_get(ctx->lexer); /* Skip ";". */
276 if (ctx->lexer->token.type != LEX_T_END) {
277 action_syntax_error(ctx, "expecting end of input");
282 while (ctx->lexer->token.type != LEX_T_END) {
283 if (!parse_action(ctx)) {
289 /* Parses OVN actions, in the format described for the "actions" column in the
290 * Logical_Flow table in ovn-sb(5), and appends the parsed versions of the
291 * actions to 'ofpacts' as "struct ofpact"s.
293 * 'symtab' provides a table of "struct expr_symbol"s to support (as one would
294 * provide to expr_parse()).
296 * 'ports' must be a map from strings (presumably names of ports) to integers
297 * (as one would provide to expr_to_matches()). Strings used in the actions
298 * that are not in 'ports' are translated to zero.
300 * 'ct_zones' provides a map from a port name to its connection tracking zone.
302 * OVN maps each logical flow table (ltable), one-to-one, onto a physical
303 * OpenFlow flow table (ptable). A number of parameters describe this mapping
304 * and data related to flow tables:
306 * - 'first_ptable' and 'n_tables' define the range of OpenFlow tables to
307 * which the logical "next" action should be able to jump. Logical table
308 * 0 maps to OpenFlow table 'first_ptable', logical table 1 to
309 * 'first_ptable + 1', and so on. If 'n_tables' is 0 then "next" is
310 * disallowed entirely.
312 * - 'cur_ltable' is an offset from 'first_ptable' (e.g. 0 <= cur_ltable <
313 * n_ptables) of the logical flow that contains the actions. If
314 * cur_ltable + 1 < n_tables, then this defines the default table that
315 * "next" will jump to.
317 * 'next_table_id' should be the OpenFlow table to which the "next" action will
318 * resubmit, or 0 to disable "next".
320 * - 'output_ptable' should be the OpenFlow table to which the logical
321 * "output" action will resubmit
323 * Some actions add extra requirements (prerequisites) to the flow's match. If
324 * so, this function sets '*prereqsp' to the actions' prerequisites; otherwise,
325 * it sets '*prereqsp' to NULL. The caller owns '*prereqsp' and must
326 * eventually free it.
328 * Returns NULL on success, otherwise a malloc()'d error message that the
329 * caller must free. On failure, 'ofpacts' has the same contents and
330 * '*prereqsp' is set to NULL, but some tokens may have been consumed from
333 char * OVS_WARN_UNUSED_RESULT
334 actions_parse(struct lexer *lexer, const struct shash *symtab,
335 const struct simap *ports, const struct simap *ct_zones,
336 uint8_t first_ptable, uint8_t n_tables, uint8_t cur_ltable,
337 uint8_t output_ptable, struct ofpbuf *ofpacts,
338 struct expr **prereqsp)
340 size_t ofpacts_start = ofpacts->size;
342 struct action_context ctx;
346 ctx.ct_zones = ct_zones;
347 ctx.first_ptable = first_ptable;
348 ctx.n_tables = n_tables;
349 ctx.cur_ltable = cur_ltable;
350 ctx.output_ptable = output_ptable;
352 ctx.ofpacts = ofpacts;
358 *prereqsp = ctx.prereqs;
361 ofpacts->size = ofpacts_start;
362 expr_destroy(ctx.prereqs);
368 /* Like actions_parse(), but the actions are taken from 's'. */
369 char * OVS_WARN_UNUSED_RESULT
370 actions_parse_string(const char *s, const struct shash *symtab,
371 const struct simap *ports, const struct simap *ct_zones,
372 uint8_t first_table, uint8_t n_tables, uint8_t cur_table,
373 uint8_t output_table, struct ofpbuf *ofpacts,
374 struct expr **prereqsp)
379 lexer_init(&lexer, s);
381 error = actions_parse(&lexer, symtab, ports, ct_zones, first_table,
382 n_tables, cur_table, output_table, ofpacts,
384 lexer_destroy(&lexer);