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 "ofp-actions.h"
28 /* Context maintained during actions_parse(). */
29 struct action_context {
31 struct lexer *lexer; /* Lexer for pulling more tokens. */
32 const struct shash *symtab; /* Symbol table. */
33 uint8_t next_table_id; /* OpenFlow table for 'next' to resubmit. */
34 uint8_t output_table_id; /* OpenFlow table for 'output' to resubmit. */
35 const struct simap *ports; /* Map from port name to number. */
38 char *error; /* Error, if any, otherwise NULL. */
41 struct ofpbuf *ofpacts; /* Actions. */
42 struct expr *prereqs; /* Prerequisites to apply to match. */
46 action_error_handle_common(struct action_context *ctx)
49 /* Already have an error, suppress this one since the cascade seems
50 * unlikely to be useful. */
52 } else if (ctx->lexer->token.type == LEX_T_ERROR) {
53 /* The lexer signaled an error. Nothing at the action level
54 * accepts an error token, so we'll inevitably end up here with some
55 * meaningless parse error. Report the lexical error instead. */
56 ctx->error = xstrdup(ctx->lexer->token.s);
63 static void OVS_PRINTF_FORMAT(2, 3)
64 action_error(struct action_context *ctx, const char *message, ...)
66 if (action_error_handle_common(ctx)) {
71 va_start(args, message);
72 ctx->error = xvasprintf(message, args);
76 static void OVS_PRINTF_FORMAT(2, 3)
77 action_syntax_error(struct action_context *ctx, const char *message, ...)
79 if (action_error_handle_common(ctx)) {
86 ds_put_cstr(&s, "Syntax error");
87 if (ctx->lexer->token.type == LEX_T_END) {
88 ds_put_cstr(&s, " at end of input");
89 } else if (ctx->lexer->start) {
90 ds_put_format(&s, " at `%.*s'",
91 (int) (ctx->lexer->input - ctx->lexer->start),
99 va_start(args, message);
100 ds_put_format_valist(&s, message, args);
103 ds_put_char(&s, '.');
105 ctx->error = ds_steal_cstr(&s);
108 /* Parses an assignment or exchange action. */
110 parse_set_action(struct action_context *ctx)
112 struct expr *prereqs;
115 error = expr_parse_assignment(ctx->lexer, ctx->symtab, ctx->ports,
116 ctx->ofpacts, &prereqs);
118 action_error(ctx, "%s", error);
123 ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, prereqs);
127 emit_resubmit(struct action_context *ctx, uint8_t table_id)
129 struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(ctx->ofpacts);
130 resubmit->in_port = OFPP_IN_PORT;
131 resubmit->table_id = table_id;
135 parse_actions(struct action_context *ctx)
137 /* "drop;" by itself is a valid (empty) set of actions, but it can't be
138 * combined with other actions because that doesn't make sense. */
139 if (ctx->lexer->token.type == LEX_T_ID
140 && !strcmp(ctx->lexer->token.s, "drop")
141 && lexer_lookahead(ctx->lexer) == LEX_T_SEMICOLON) {
142 lexer_get(ctx->lexer); /* Skip "drop". */
143 lexer_get(ctx->lexer); /* Skip ";". */
144 if (ctx->lexer->token.type != LEX_T_END) {
145 action_syntax_error(ctx, "expecting end of input");
150 while (ctx->lexer->token.type != LEX_T_END) {
151 if (ctx->lexer->token.type != LEX_T_ID) {
152 action_syntax_error(ctx, NULL);
156 enum lex_type lookahead = lexer_lookahead(ctx->lexer);
157 if (lookahead == LEX_T_EQUALS || lookahead == LEX_T_EXCHANGE
158 || lookahead == LEX_T_LSQUARE) {
159 parse_set_action(ctx);
160 } else if (lexer_match_id(ctx->lexer, "next")) {
161 if (ctx->next_table_id) {
162 emit_resubmit(ctx, ctx->next_table_id);
164 action_error(ctx, "\"next\" action not allowed here.");
166 } else if (lexer_match_id(ctx->lexer, "output")) {
167 emit_resubmit(ctx, ctx->output_table_id);
169 action_syntax_error(ctx, "expecting action");
171 if (!lexer_match(ctx->lexer, LEX_T_SEMICOLON)) {
172 action_syntax_error(ctx, "expecting ';'");
180 /* Parses OVN actions, in the format described for the "actions" column in the
181 * Logical_Flow table in ovn-sb(5), and appends the parsed versions of the
182 * actions to 'ofpacts' as "struct ofpact"s.
184 * 'symtab' provides a table of "struct expr_symbol"s to support (as one would
185 * provide to expr_parse()).
187 * 'ports' must be a map from strings (presumably names of ports) to integers
188 * (as one would provide to expr_to_matches()). Strings used in the actions
189 * that are not in 'ports' are translated to zero.
191 * 'next_table_id' should be the OpenFlow table to which the "next" action will
192 * resubmit, or 0 to disable "next".
194 * 'output_table_id' should be the OpenFlow table to which the "output" action
197 * Some actions add extra requirements (prerequisites) to the flow's match. If
198 * so, this function sets '*prereqsp' to the actions' prerequisites; otherwise,
199 * it sets '*prereqsp' to NULL. The caller owns '*prereqsp' and must
200 * eventually free it.
202 * Returns NULL on success, otherwise a malloc()'d error message that the
203 * caller must free. On failure, 'ofpacts' has the same contents and
204 * '*prereqsp' is set to NULL, but some tokens may have been consumed from
207 char * OVS_WARN_UNUSED_RESULT
208 actions_parse(struct lexer *lexer, const struct shash *symtab,
209 const struct simap *ports, uint8_t next_table_id,
210 uint8_t output_table_id, struct ofpbuf *ofpacts,
211 struct expr **prereqsp)
213 size_t ofpacts_start = ofpacts->size;
215 struct action_context ctx;
219 ctx.next_table_id = next_table_id;
220 ctx.output_table_id = output_table_id;
222 ctx.ofpacts = ofpacts;
228 *prereqsp = ctx.prereqs;
231 ofpacts->size = ofpacts_start;
232 expr_destroy(ctx.prereqs);
238 /* Like actions_parse(), but the actions are taken from 's'. */
239 char * OVS_WARN_UNUSED_RESULT
240 actions_parse_string(const char *s, const struct shash *symtab,
241 const struct simap *ports, uint8_t next_table_id,
242 uint8_t output_table_id, struct ofpbuf *ofpacts,
243 struct expr **prereqsp)
248 lexer_init(&lexer, s);
250 error = actions_parse(&lexer, symtab, ports, next_table_id,
251 output_table_id, ofpacts, prereqsp);
252 lexer_destroy(&lexer);