8afddee7e4f036e5ca13fb1ed171c6a23f65c56b
[cascardo/ovs.git] / ovn / lib / actions.c
1 /*
2  * Copyright (c) 2015 Nicira, Inc.
3  *
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:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <config.h>
18 #include "actions.h"
19 #include <stdarg.h>
20 #include <stdbool.h>
21 #include "compiler.h"
22 #include "dynamic-string.h"
23 #include "expr.h"
24 #include "lex.h"
25 #include "ofp-actions.h"
26 #include "ofpbuf.h"
27
28 /* Context maintained during actions_parse(). */
29 struct action_context {
30 /* Input. */
31
32     struct lexer *lexer;        /* Lexer for pulling more tokens. */
33     const struct simap *ports;  /* Map from port name to number. */
34     const struct shash *symtab; /* Symbol table. */
35
36     /* OVN maps each logical flow table (ltable), one-to-one, onto a physical
37      * OpenFlow flow table (ptable).  These members describe the mapping and
38      * data related to flow tables. */
39     uint8_t n_tables;           /* Number of flow tables. */
40     uint8_t first_ptable;       /* First OpenFlow table. */
41     uint8_t cur_ltable;         /* 0 <= cur_ltable < n_tables. */
42     uint8_t output_ptable;      /* OpenFlow table for 'output' to resubmit. */
43
44 /* State. */
45     char *error;                /* Error, if any, otherwise NULL. */
46
47 /* Output. */
48     struct ofpbuf *ofpacts;     /* Actions. */
49     struct expr *prereqs;       /* Prerequisites to apply to match. */
50 };
51
52 static bool
53 action_error_handle_common(struct action_context *ctx)
54 {
55     if (ctx->error) {
56         /* Already have an error, suppress this one since the cascade seems
57          * unlikely to be useful. */
58         return true;
59     } else if (ctx->lexer->token.type == LEX_T_ERROR) {
60         /* The lexer signaled an error.  Nothing at the action level
61          * accepts an error token, so we'll inevitably end up here with some
62          * meaningless parse error.  Report the lexical error instead. */
63         ctx->error = xstrdup(ctx->lexer->token.s);
64         return true;
65     } else {
66         return false;
67     }
68 }
69
70 static void OVS_PRINTF_FORMAT(2, 3)
71 action_error(struct action_context *ctx, const char *message, ...)
72 {
73     if (action_error_handle_common(ctx)) {
74         return;
75     }
76
77     va_list args;
78     va_start(args, message);
79     ctx->error = xvasprintf(message, args);
80     va_end(args);
81 }
82
83 static void OVS_PRINTF_FORMAT(2, 3)
84 action_syntax_error(struct action_context *ctx, const char *message, ...)
85 {
86     if (action_error_handle_common(ctx)) {
87         return;
88     }
89
90     struct ds s;
91
92     ds_init(&s);
93     ds_put_cstr(&s, "Syntax error");
94     if (ctx->lexer->token.type == LEX_T_END) {
95         ds_put_cstr(&s, " at end of input");
96     } else if (ctx->lexer->start) {
97         ds_put_format(&s, " at `%.*s'",
98                       (int) (ctx->lexer->input - ctx->lexer->start),
99                       ctx->lexer->start);
100     }
101
102     if (message) {
103         ds_put_char(&s, ' ');
104
105         va_list args;
106         va_start(args, message);
107         ds_put_format_valist(&s, message, args);
108         va_end(args);
109     }
110     ds_put_char(&s, '.');
111
112     ctx->error = ds_steal_cstr(&s);
113 }
114
115 /* Parses an assignment or exchange action. */
116 static void
117 parse_set_action(struct action_context *ctx)
118 {
119     struct expr *prereqs;
120     char *error;
121
122     error = expr_parse_assignment(ctx->lexer, ctx->symtab, ctx->ports,
123                                   ctx->ofpacts, &prereqs);
124     if (error) {
125         action_error(ctx, "%s", error);
126         free(error);
127         return;
128     }
129
130     ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, prereqs);
131 }
132
133 static void
134 emit_resubmit(struct action_context *ctx, uint8_t table_id)
135 {
136     struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(ctx->ofpacts);
137     resubmit->in_port = OFPP_IN_PORT;
138     resubmit->table_id = table_id;
139 }
140
141 static bool
142 action_get_int(struct action_context *ctx, int *value)
143 {
144     bool ok = lexer_get_int(ctx->lexer, value);
145     if (!ok) {
146         action_syntax_error(ctx, "expecting small integer");
147     }
148     return ok;
149 }
150
151 static void
152 parse_next_action(struct action_context *ctx)
153 {
154     if (!ctx->n_tables) {
155         action_error(ctx, "\"next\" action not allowed here.");
156     } else if (lexer_match(ctx->lexer, LEX_T_LPAREN)) {
157         int ltable;
158
159         if (!action_get_int(ctx, &ltable)) {
160             return;
161         }
162         if (!lexer_match(ctx->lexer, LEX_T_RPAREN)) {
163             action_syntax_error(ctx, "expecting `)'");
164             return;
165         }
166
167         if (ltable >= ctx->n_tables) {
168             action_error(ctx, "\"next\" argument must be in range 0 to %d.",
169                          ctx->n_tables - 1);
170             return;
171         }
172
173         emit_resubmit(ctx, ctx->first_ptable + ltable);
174     } else {
175         if (ctx->cur_ltable < ctx->n_tables) {
176             emit_resubmit(ctx, ctx->first_ptable + ctx->cur_ltable + 1);
177         } else {
178             action_error(ctx, "\"next\" action not allowed in last table.");
179         }
180     }
181 }
182
183 static void
184 parse_actions(struct action_context *ctx)
185 {
186     /* "drop;" by itself is a valid (empty) set of actions, but it can't be
187      * combined with other actions because that doesn't make sense. */
188     if (ctx->lexer->token.type == LEX_T_ID
189         && !strcmp(ctx->lexer->token.s, "drop")
190         && lexer_lookahead(ctx->lexer) == LEX_T_SEMICOLON) {
191         lexer_get(ctx->lexer);  /* Skip "drop". */
192         lexer_get(ctx->lexer);  /* Skip ";". */
193         if (ctx->lexer->token.type != LEX_T_END) {
194             action_syntax_error(ctx, "expecting end of input");
195         }
196         return;
197     }
198
199     while (ctx->lexer->token.type != LEX_T_END) {
200         if (ctx->lexer->token.type != LEX_T_ID) {
201             action_syntax_error(ctx, NULL);
202             break;
203         }
204
205         enum lex_type lookahead = lexer_lookahead(ctx->lexer);
206         if (lookahead == LEX_T_EQUALS || lookahead == LEX_T_EXCHANGE
207             || lookahead == LEX_T_LSQUARE) {
208             parse_set_action(ctx);
209         } else if (lexer_match_id(ctx->lexer, "next")) {
210             parse_next_action(ctx);
211         } else if (lexer_match_id(ctx->lexer, "output")) {
212             emit_resubmit(ctx, ctx->output_ptable);
213         } else {
214             action_syntax_error(ctx, "expecting action");
215         }
216         if (!lexer_match(ctx->lexer, LEX_T_SEMICOLON)) {
217             action_syntax_error(ctx, "expecting ';'");
218         }
219         if (ctx->error) {
220             return;
221         }
222     }
223 }
224
225 /* Parses OVN actions, in the format described for the "actions" column in the
226  * Logical_Flow table in ovn-sb(5), and appends the parsed versions of the
227  * actions to 'ofpacts' as "struct ofpact"s.
228  *
229  * 'symtab' provides a table of "struct expr_symbol"s to support (as one would
230  * provide to expr_parse()).
231  *
232  * 'ports' must be a map from strings (presumably names of ports) to integers
233  * (as one would provide to expr_to_matches()).  Strings used in the actions
234  * that are not in 'ports' are translated to zero.
235  *
236  * OVN maps each logical flow table (ltable), one-to-one, onto a physical
237  * OpenFlow flow table (ptable).  A number of parameters describe this mapping
238  * and data related to flow tables:
239  *
240  *     - 'first_ptable' and 'n_tables' define the range of OpenFlow tables to
241  *       which the logical "next" action should be able to jump.  Logical table
242  *       0 maps to OpenFlow table 'first_ptable', logical table 1 to
243  *       'first_ptable + 1', and so on.  If 'n_tables' is 0 then "next" is
244  *       disallowed entirely.
245  *
246  *     - 'cur_ltable' is an offset from 'first_ptable' (e.g. 0 <= cur_ltable <
247  *       n_ptables) of the logical flow that contains the actions.  If
248  *       cur_ltable + 1 < n_tables, then this defines the default table that
249  *       "next" will jump to.
250  *
251  *     - 'output_ptable' should be the OpenFlow table to which the logical
252  *       "output" action will resubmit
253  *
254  * Some actions add extra requirements (prerequisites) to the flow's match.  If
255  * so, this function sets '*prereqsp' to the actions' prerequisites; otherwise,
256  * it sets '*prereqsp' to NULL.  The caller owns '*prereqsp' and must
257  * eventually free it.
258  *
259  * Returns NULL on success, otherwise a malloc()'d error message that the
260  * caller must free.  On failure, 'ofpacts' has the same contents and
261  * '*prereqsp' is set to NULL, but some tokens may have been consumed from
262  * 'lexer'.
263   */
264 char * OVS_WARN_UNUSED_RESULT
265 actions_parse(struct lexer *lexer, const struct shash *symtab,
266               const struct simap *ports,
267               uint8_t first_ptable, uint8_t n_tables, uint8_t cur_ltable,
268               uint8_t output_ptable, struct ofpbuf *ofpacts,
269               struct expr **prereqsp)
270 {
271     size_t ofpacts_start = ofpacts->size;
272
273     struct action_context ctx;
274     ctx.lexer = lexer;
275     ctx.symtab = symtab;
276     ctx.ports = ports;
277     ctx.first_ptable = first_ptable;
278     ctx.n_tables = n_tables;
279     ctx.cur_ltable = cur_ltable;
280     ctx.output_ptable = output_ptable;
281     ctx.error = NULL;
282     ctx.ofpacts = ofpacts;
283     ctx.prereqs = NULL;
284
285     parse_actions(&ctx);
286
287     if (!ctx.error) {
288         *prereqsp = ctx.prereqs;
289         return NULL;
290     } else {
291         ofpacts->size = ofpacts_start;
292         expr_destroy(ctx.prereqs);
293         *prereqsp = NULL;
294         return ctx.error;
295     }
296 }
297
298 /* Like actions_parse(), but the actions are taken from 's'. */
299 char * OVS_WARN_UNUSED_RESULT
300 actions_parse_string(const char *s, const struct shash *symtab,
301                      const struct simap *ports, uint8_t first_table,
302                      uint8_t n_tables, uint8_t cur_table,
303                      uint8_t output_table, struct ofpbuf *ofpacts,
304                      struct expr **prereqsp)
305 {
306     struct lexer lexer;
307     char *error;
308
309     lexer_init(&lexer, s);
310     lexer_get(&lexer);
311     error = actions_parse(&lexer, symtab, ports, first_table, n_tables,
312                           cur_table, output_table, ofpacts, prereqsp);
313     lexer_destroy(&lexer);
314
315     return error;
316 }