actions: Implement OVN "arp" action.
[cascardo/ovs.git] / ovn / lib / actions.c
1 /*
2  * Copyright (c) 2015, 2016 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     const struct action_params *ap; /* Parameters. */
33     struct lexer *lexer;        /* Lexer for pulling more tokens. */
34     char *error;                /* Error, if any, otherwise NULL. */
35     struct ofpbuf *ofpacts;     /* Actions. */
36     struct expr *prereqs;       /* Prerequisites to apply to match. */
37 };
38
39 static bool parse_action(struct action_context *);
40
41 static bool
42 action_error_handle_common(struct action_context *ctx)
43 {
44     if (ctx->error) {
45         /* Already have an error, suppress this one since the cascade seems
46          * unlikely to be useful. */
47         return true;
48     } else if (ctx->lexer->token.type == LEX_T_ERROR) {
49         /* The lexer signaled an error.  Nothing at the action level
50          * accepts an error token, so we'll inevitably end up here with some
51          * meaningless parse error.  Report the lexical error instead. */
52         ctx->error = xstrdup(ctx->lexer->token.s);
53         return true;
54     } else {
55         return false;
56     }
57 }
58
59 static void OVS_PRINTF_FORMAT(2, 3)
60 action_error(struct action_context *ctx, const char *message, ...)
61 {
62     if (action_error_handle_common(ctx)) {
63         return;
64     }
65
66     va_list args;
67     va_start(args, message);
68     ctx->error = xvasprintf(message, args);
69     va_end(args);
70 }
71
72 static void OVS_PRINTF_FORMAT(2, 3)
73 action_syntax_error(struct action_context *ctx, const char *message, ...)
74 {
75     if (action_error_handle_common(ctx)) {
76         return;
77     }
78
79     struct ds s;
80
81     ds_init(&s);
82     ds_put_cstr(&s, "Syntax error");
83     if (ctx->lexer->token.type == LEX_T_END) {
84         ds_put_cstr(&s, " at end of input");
85     } else if (ctx->lexer->start) {
86         ds_put_format(&s, " at `%.*s'",
87                       (int) (ctx->lexer->input - ctx->lexer->start),
88                       ctx->lexer->start);
89     }
90
91     if (message) {
92         ds_put_char(&s, ' ');
93
94         va_list args;
95         va_start(args, message);
96         ds_put_format_valist(&s, message, args);
97         va_end(args);
98     }
99     ds_put_char(&s, '.');
100
101     ctx->error = ds_steal_cstr(&s);
102 }
103
104 /* Parses an assignment or exchange action. */
105 static void
106 parse_set_action(struct action_context *ctx)
107 {
108     struct expr *prereqs;
109     char *error;
110
111     error = expr_parse_assignment(ctx->lexer, ctx->ap->symtab, ctx->ap->ports,
112                                   ctx->ofpacts, &prereqs);
113     if (error) {
114         action_error(ctx, "%s", error);
115         free(error);
116         return;
117     }
118
119     ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, prereqs);
120 }
121
122 static void
123 emit_resubmit(struct action_context *ctx, uint8_t table_id)
124 {
125     struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(ctx->ofpacts);
126     resubmit->in_port = OFPP_IN_PORT;
127     resubmit->table_id = table_id;
128 }
129
130 static bool
131 action_get_int(struct action_context *ctx, int *value)
132 {
133     bool ok = lexer_get_int(ctx->lexer, value);
134     if (!ok) {
135         action_syntax_error(ctx, "expecting small integer");
136     }
137     return ok;
138 }
139
140 static void
141 parse_next_action(struct action_context *ctx)
142 {
143     if (!ctx->ap->n_tables) {
144         action_error(ctx, "\"next\" action not allowed here.");
145     } else if (lexer_match(ctx->lexer, LEX_T_LPAREN)) {
146         int ltable;
147
148         if (!action_get_int(ctx, &ltable)) {
149             return;
150         }
151         if (!lexer_match(ctx->lexer, LEX_T_RPAREN)) {
152             action_syntax_error(ctx, "expecting `)'");
153             return;
154         }
155
156         if (ltable >= ctx->ap->n_tables) {
157             action_error(ctx, "\"next\" argument must be in range 0 to %d.",
158                          ctx->ap->n_tables - 1);
159             return;
160         }
161
162         emit_resubmit(ctx, ctx->ap->first_ptable + ltable);
163     } else {
164         if (ctx->ap->cur_ltable < ctx->ap->n_tables) {
165             emit_resubmit(ctx,
166                           ctx->ap->first_ptable + ctx->ap->cur_ltable + 1);
167         } else {
168             action_error(ctx, "\"next\" action not allowed in last table.");
169         }
170     }
171 }
172
173 /* Parses 'prerequisite' as an expression in the context of 'ctx', then adds it
174  * as a conjunction with the existing 'ctx->prereqs'. */
175 static void
176 add_prerequisite(struct action_context *ctx, const char *prerequisite)
177 {
178     struct expr *expr;
179     char *error;
180
181     expr = expr_parse_string(prerequisite, ctx->ap->symtab, &error);
182     ovs_assert(!error);
183     ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, expr);
184 }
185
186 static void
187 parse_arp_action(struct action_context *ctx)
188 {
189     if (!lexer_match(ctx->lexer, LEX_T_LCURLY)) {
190         action_syntax_error(ctx, "expecting `{'");
191         return;
192     }
193
194     struct ofpbuf *outer_ofpacts = ctx->ofpacts;
195     uint64_t inner_ofpacts_stub[1024 / 8];
196     struct ofpbuf inner_ofpacts = OFPBUF_STUB_INITIALIZER(inner_ofpacts_stub);
197     ctx->ofpacts = &inner_ofpacts;
198
199     /* Save prerequisites.  (XXX What is the right treatment for prereqs?) */
200     struct expr *outer_prereqs = ctx->prereqs;
201     ctx->prereqs = NULL;
202
203     /* Parse inner actions. */
204     while (!lexer_match(ctx->lexer, LEX_T_RCURLY)) {
205         if (!parse_action(ctx)) {
206             break;
207         }
208     }
209
210     ctx->ofpacts = outer_ofpacts;
211
212     /* Add a "controller" action with the actions nested inside "arp {...}",
213      * converted to OpenFlow, as its userdata.  ovn-controller will convert the
214      * packet to an ARP and then send the packet and actions back to the switch
215      * inside an OFPT_PACKET_OUT message. */
216     size_t oc_offset = ctx->ofpacts->size;
217     ofpact_put_CONTROLLER(ctx->ofpacts);
218
219     struct action_header ah = { .opcode = htonl(ACTION_OPCODE_ARP) };
220     ofpbuf_put(ctx->ofpacts, &ah, sizeof ah);
221
222     ofpacts_put_openflow_actions(inner_ofpacts.data, inner_ofpacts.size,
223                                  ctx->ofpacts, OFP13_VERSION);
224
225     struct ofpact_controller *oc = ofpbuf_at_assert(ctx->ofpacts, oc_offset,
226                                                     sizeof *oc);
227     ctx->ofpacts->header = oc;
228     oc->max_len = UINT16_MAX;
229     oc->reason = OFPR_ACTION;
230     oc->userdata_len = ctx->ofpacts->size - (oc_offset + sizeof *oc);
231     ofpact_finish(ctx->ofpacts, &oc->ofpact);
232
233     /* Restore prerequisites. */
234     expr_destroy(ctx->prereqs);
235     ctx->prereqs = outer_prereqs;
236     add_prerequisite(ctx, "ip4");
237
238     /* Free memory. */
239     ofpbuf_uninit(&inner_ofpacts);
240 }
241
242 static void
243 emit_ct(struct action_context *ctx, bool recirc_next, bool commit)
244 {
245     struct ofpact_conntrack *ct = ofpact_put_CT(ctx->ofpacts);
246     ct->flags |= commit ? NX_CT_F_COMMIT : 0;
247
248     /* If "recirc" is set, we automatically go to the next table. */
249     if (recirc_next) {
250         if (ctx->ap->cur_ltable < ctx->ap->n_tables) {
251             ct->recirc_table = ctx->ap->first_ptable + ctx->ap->cur_ltable + 1;
252         } else {
253             action_error(ctx, "\"ct_next\" action not allowed in last table.");
254             return;
255         }
256     } else {
257         ct->recirc_table = NX_CT_RECIRC_NONE;
258     }
259
260     ct->zone_src.field = mf_from_id(MFF_LOG_CT_ZONE);
261     ct->zone_src.ofs = 0;
262     ct->zone_src.n_bits = 16;
263
264     /* We do not support ALGs yet. */
265     ct->alg = 0;
266
267     /* CT only works with IP, so set up a prerequisite. */
268     add_prerequisite(ctx, "ip");
269 }
270
271 static bool
272 parse_action(struct action_context *ctx)
273 {
274     if (ctx->lexer->token.type != LEX_T_ID) {
275         action_syntax_error(ctx, NULL);
276         return false;
277     }
278
279     enum lex_type lookahead = lexer_lookahead(ctx->lexer);
280     if (lookahead == LEX_T_EQUALS || lookahead == LEX_T_EXCHANGE
281         || lookahead == LEX_T_LSQUARE) {
282         parse_set_action(ctx);
283     } else if (lexer_match_id(ctx->lexer, "next")) {
284         parse_next_action(ctx);
285     } else if (lexer_match_id(ctx->lexer, "output")) {
286         emit_resubmit(ctx, ctx->ap->output_ptable);
287     } else if (lexer_match_id(ctx->lexer, "ip.ttl")) {
288         if (lexer_match(ctx->lexer, LEX_T_DECREMENT)) {
289             add_prerequisite(ctx, "ip");
290             ofpact_put_DEC_TTL(ctx->ofpacts);
291         } else {
292             action_syntax_error(ctx, "expecting `--'");
293         }
294     } else if (lexer_match_id(ctx->lexer, "ct_next")) {
295         emit_ct(ctx, true, false);
296     } else if (lexer_match_id(ctx->lexer, "ct_commit")) {
297         emit_ct(ctx, false, true);
298     } else if (lexer_match_id(ctx->lexer, "arp")) {
299         parse_arp_action(ctx);
300     } else {
301         action_syntax_error(ctx, "expecting action");
302     }
303     if (!lexer_match(ctx->lexer, LEX_T_SEMICOLON)) {
304         action_syntax_error(ctx, "expecting ';'");
305     }
306     return !ctx->error;
307 }
308
309 static void
310 parse_actions(struct action_context *ctx)
311 {
312     /* "drop;" by itself is a valid (empty) set of actions, but it can't be
313      * combined with other actions because that doesn't make sense. */
314     if (ctx->lexer->token.type == LEX_T_ID
315         && !strcmp(ctx->lexer->token.s, "drop")
316         && lexer_lookahead(ctx->lexer) == LEX_T_SEMICOLON) {
317         lexer_get(ctx->lexer);  /* Skip "drop". */
318         lexer_get(ctx->lexer);  /* Skip ";". */
319         if (ctx->lexer->token.type != LEX_T_END) {
320             action_syntax_error(ctx, "expecting end of input");
321         }
322         return;
323     }
324
325     while (ctx->lexer->token.type != LEX_T_END) {
326         if (!parse_action(ctx)) {
327             return;
328         }
329     }
330 }
331
332 /* Parses OVN actions, in the format described for the "actions" column in the
333  * Logical_Flow table in ovn-sb(5), and appends the parsed versions of the
334  * actions to 'ofpacts' as "struct ofpact"s.
335  *
336  * 'ap' provides most of the parameters for translation.
337  *
338  * Some actions add extra requirements (prerequisites) to the flow's match.  If
339  * so, this function sets '*prereqsp' to the actions' prerequisites; otherwise,
340  * it sets '*prereqsp' to NULL.  The caller owns '*prereqsp' and must
341  * eventually free it.
342  *
343  * Returns NULL on success, otherwise a malloc()'d error message that the
344  * caller must free.  On failure, 'ofpacts' has the same contents and
345  * '*prereqsp' is set to NULL, but some tokens may have been consumed from
346  * 'lexer'.
347   */
348 char * OVS_WARN_UNUSED_RESULT
349 actions_parse(struct lexer *lexer, const struct action_params *ap,
350               struct ofpbuf *ofpacts, struct expr **prereqsp)
351 {
352     size_t ofpacts_start = ofpacts->size;
353
354     struct action_context ctx = {
355         .ap = ap,
356         .lexer = lexer,
357         .error = NULL,
358         .ofpacts = ofpacts,
359         .prereqs = NULL,
360     };
361     parse_actions(&ctx);
362
363     if (!ctx.error) {
364         *prereqsp = ctx.prereqs;
365         return NULL;
366     } else {
367         ofpacts->size = ofpacts_start;
368         expr_destroy(ctx.prereqs);
369         *prereqsp = NULL;
370         return ctx.error;
371     }
372 }
373
374 /* Like actions_parse(), but the actions are taken from 's'. */
375 char * OVS_WARN_UNUSED_RESULT
376 actions_parse_string(const char *s, const struct action_params *ap,
377                      struct ofpbuf *ofpacts, struct expr **prereqsp)
378 {
379     struct lexer lexer;
380     char *error;
381
382     lexer_init(&lexer, s);
383     lexer_get(&lexer);
384     error = actions_parse(&lexer, ap, ofpacts, prereqsp);
385     lexer_destroy(&lexer);
386
387     return error;
388 }