actions: Factor parsing a single action into a new function parse_action().
[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 "logical-fields.h"
26 #include "ofp-actions.h"
27 #include "ofpbuf.h"
28 #include "simap.h"
29
30 /* Context maintained during actions_parse(). */
31 struct action_context {
32 /* Input. */
33
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. */
37
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. */
46
47 /* State. */
48     char *error;                /* Error, if any, otherwise NULL. */
49
50 /* Output. */
51     struct ofpbuf *ofpacts;     /* Actions. */
52     struct expr *prereqs;       /* Prerequisites to apply to match. */
53 };
54
55 static bool parse_action(struct action_context *);
56
57 static bool
58 action_error_handle_common(struct action_context *ctx)
59 {
60     if (ctx->error) {
61         /* Already have an error, suppress this one since the cascade seems
62          * unlikely to be useful. */
63         return true;
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);
69         return true;
70     } else {
71         return false;
72     }
73 }
74
75 static void OVS_PRINTF_FORMAT(2, 3)
76 action_error(struct action_context *ctx, const char *message, ...)
77 {
78     if (action_error_handle_common(ctx)) {
79         return;
80     }
81
82     va_list args;
83     va_start(args, message);
84     ctx->error = xvasprintf(message, args);
85     va_end(args);
86 }
87
88 static void OVS_PRINTF_FORMAT(2, 3)
89 action_syntax_error(struct action_context *ctx, const char *message, ...)
90 {
91     if (action_error_handle_common(ctx)) {
92         return;
93     }
94
95     struct ds s;
96
97     ds_init(&s);
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),
104                       ctx->lexer->start);
105     }
106
107     if (message) {
108         ds_put_char(&s, ' ');
109
110         va_list args;
111         va_start(args, message);
112         ds_put_format_valist(&s, message, args);
113         va_end(args);
114     }
115     ds_put_char(&s, '.');
116
117     ctx->error = ds_steal_cstr(&s);
118 }
119
120 /* Parses an assignment or exchange action. */
121 static void
122 parse_set_action(struct action_context *ctx)
123 {
124     struct expr *prereqs;
125     char *error;
126
127     error = expr_parse_assignment(ctx->lexer, ctx->symtab, ctx->ports,
128                                   ctx->ofpacts, &prereqs);
129     if (error) {
130         action_error(ctx, "%s", error);
131         free(error);
132         return;
133     }
134
135     ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, prereqs);
136 }
137
138 static void
139 emit_resubmit(struct action_context *ctx, uint8_t table_id)
140 {
141     struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(ctx->ofpacts);
142     resubmit->in_port = OFPP_IN_PORT;
143     resubmit->table_id = table_id;
144 }
145
146 static bool
147 action_get_int(struct action_context *ctx, int *value)
148 {
149     bool ok = lexer_get_int(ctx->lexer, value);
150     if (!ok) {
151         action_syntax_error(ctx, "expecting small integer");
152     }
153     return ok;
154 }
155
156 static void
157 parse_next_action(struct action_context *ctx)
158 {
159     if (!ctx->n_tables) {
160         action_error(ctx, "\"next\" action not allowed here.");
161     } else if (lexer_match(ctx->lexer, LEX_T_LPAREN)) {
162         int ltable;
163
164         if (!action_get_int(ctx, &ltable)) {
165             return;
166         }
167         if (!lexer_match(ctx->lexer, LEX_T_RPAREN)) {
168             action_syntax_error(ctx, "expecting `)'");
169             return;
170         }
171
172         if (ltable >= ctx->n_tables) {
173             action_error(ctx, "\"next\" argument must be in range 0 to %d.",
174                          ctx->n_tables - 1);
175             return;
176         }
177
178         emit_resubmit(ctx, ctx->first_ptable + ltable);
179     } else {
180         if (ctx->cur_ltable < ctx->n_tables) {
181             emit_resubmit(ctx, ctx->first_ptable + ctx->cur_ltable + 1);
182         } else {
183             action_error(ctx, "\"next\" action not allowed in last table.");
184         }
185     }
186 }
187
188 /* Parses 'prerequisite' as an expression in the context of 'ctx', then adds it
189  * as a conjunction with the existing 'ctx->prereqs'. */
190 static void
191 add_prerequisite(struct action_context *ctx, const char *prerequisite)
192 {
193     struct expr *expr;
194     char *error;
195
196     expr = expr_parse_string(prerequisite, ctx->symtab, &error);
197     ovs_assert(!error);
198     ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, expr);
199 }
200
201 static void
202 emit_ct(struct action_context *ctx, bool recirc_next, bool commit)
203 {
204     struct ofpact_conntrack *ct = ofpact_put_CT(ctx->ofpacts);
205     ct->flags |= commit ? NX_CT_F_COMMIT : 0;
206
207     /* If "recirc" is set, we automatically go to the next table. */
208     if (recirc_next) {
209         if (ctx->cur_ltable < ctx->n_tables) {
210             ct->recirc_table = ctx->first_ptable + ctx->cur_ltable + 1;
211         } else {
212             action_error(ctx, "\"ct_next\" action not allowed in last table.");
213             return;
214         }
215     } else {
216         ct->recirc_table = NX_CT_RECIRC_NONE;
217     }
218
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;
222
223     /* We do not support ALGs yet. */
224     ct->alg = 0;
225
226     /* CT only works with IP, so set up a prerequisite. */
227     add_prerequisite(ctx, "ip");
228 }
229
230 static bool
231 parse_action(struct action_context *ctx)
232 {
233     if (ctx->lexer->token.type != LEX_T_ID) {
234         action_syntax_error(ctx, NULL);
235         return false;
236     }
237
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);
250         } else {
251             action_syntax_error(ctx, "expecting `--'");
252         }
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);
257     } else {
258         action_syntax_error(ctx, "expecting action");
259     }
260     if (!lexer_match(ctx->lexer, LEX_T_SEMICOLON)) {
261         action_syntax_error(ctx, "expecting ';'");
262     }
263     return !ctx->error;
264 }
265
266 static void
267 parse_actions(struct action_context *ctx)
268 {
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");
278         }
279         return;
280     }
281
282     while (ctx->lexer->token.type != LEX_T_END) {
283         if (!parse_action(ctx)) {
284             return;
285         }
286     }
287 }
288
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.
292  *
293  * 'symtab' provides a table of "struct expr_symbol"s to support (as one would
294  * provide to expr_parse()).
295  *
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.
299  *
300  * 'ct_zones' provides a map from a port name to its connection tracking zone.
301  *
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:
305  *
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.
311  *
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.
316  *
317  * 'next_table_id' should be the OpenFlow table to which the "next" action will
318  * resubmit, or 0 to disable "next".
319  *
320  *     - 'output_ptable' should be the OpenFlow table to which the logical
321  *       "output" action will resubmit
322  *
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.
327  *
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
331  * 'lexer'.
332   */
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)
339 {
340     size_t ofpacts_start = ofpacts->size;
341
342     struct action_context ctx;
343     ctx.lexer = lexer;
344     ctx.symtab = symtab;
345     ctx.ports = ports;
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;
351     ctx.error = NULL;
352     ctx.ofpacts = ofpacts;
353     ctx.prereqs = NULL;
354
355     parse_actions(&ctx);
356
357     if (!ctx.error) {
358         *prereqsp = ctx.prereqs;
359         return NULL;
360     } else {
361         ofpacts->size = ofpacts_start;
362         expr_destroy(ctx.prereqs);
363         *prereqsp = NULL;
364         return ctx.error;
365     }
366 }
367
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)
375 {
376     struct lexer lexer;
377     char *error;
378
379     lexer_init(&lexer, s);
380     lexer_get(&lexer);
381     error = actions_parse(&lexer, symtab, ports, ct_zones, first_table,
382                           n_tables, cur_table, output_table, ofpacts,
383                           prereqsp);
384     lexer_destroy(&lexer);
385
386     return error;
387 }