]> git.proxmox.com Git - ovs.git/blame - ovn/lib/actions.c
actions: Add new OVN action "clone".
[ovs.git] / ovn / lib / actions.c
CommitLineData
3b7cb7e1 1/*
80b6743d 2 * Copyright (c) 2015, 2016, 2017 Nicira, Inc.
3b7cb7e1
BP
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>
3b7cb7e1
BP
18#include <stdarg.h>
19#include <stdbool.h>
467085fd 20#include "bitmap.h"
f4248336 21#include "byte-order.h"
3b7cb7e1 22#include "compiler.h"
42814145 23#include "ovn-dhcp.h"
467085fd 24#include "hash.h"
667e2b0b 25#include "logical-fields.h"
42814145 26#include "nx-match.h"
b598f214 27#include "openvswitch/dynamic-string.h"
d5a76da4
BP
28#include "openvswitch/hmap.h"
29#include "openvswitch/json.h"
b598f214 30#include "openvswitch/ofp-actions.h"
64c96779 31#include "openvswitch/ofpbuf.h"
d5a76da4 32#include "openvswitch/vlog.h"
8b2ed684
AR
33#include "ovn/actions.h"
34#include "ovn/expr.h"
35#include "ovn/lex.h"
42814145 36#include "packets.h"
ee89ea7b 37#include "openvswitch/shash.h"
78aab811 38#include "simap.h"
3b7cb7e1 39
d5a76da4
BP
40VLOG_DEFINE_THIS_MODULE(actions);
41\f
42/* Prototypes for functions to be defined by each action. */
43#define OVNACT(ENUM, STRUCT) \
44 static void format_##ENUM(const struct STRUCT *, struct ds *); \
45 static void encode_##ENUM(const struct STRUCT *, \
46 const struct ovnact_encode_params *, \
47 struct ofpbuf *ofpacts); \
80b6743d 48 static void STRUCT##_free(struct STRUCT *a);
d5a76da4
BP
49OVNACTS
50#undef OVNACT
51\f
52/* Helpers. */
53
54/* Implementation of ovnact_put_<ENUM>(). */
55void *
56ovnact_put(struct ofpbuf *ovnacts, enum ovnact_type type, size_t len)
57{
8a41ad8e 58 ovs_assert(len == OVNACT_ALIGN(len));
d5a76da4
BP
59
60 ovnacts->header = ofpbuf_put_uninit(ovnacts, len);
8a41ad8e 61 struct ovnact *ovnact = ovnacts->header;
d5a76da4
BP
62 ovnact_init(ovnact, type, len);
63 return ovnact;
64}
65
66/* Implementation of ovnact_init_<ENUM>(). */
67void
68ovnact_init(struct ovnact *ovnact, enum ovnact_type type, size_t len)
69{
8a41ad8e 70 ovs_assert(len == OVNACT_ALIGN(len));
d5a76da4
BP
71 memset(ovnact, 0, len);
72 ovnact->type = type;
73 ovnact->len = len;
74}
75
76static size_t
77encode_start_controller_op(enum action_opcode opcode, bool pause,
78 struct ofpbuf *ofpacts)
79{
80 size_t ofs = ofpacts->size;
81
82 struct ofpact_controller *oc = ofpact_put_CONTROLLER(ofpacts);
83 oc->max_len = UINT16_MAX;
84 oc->reason = OFPR_ACTION;
85 oc->pause = pause;
86
87 struct action_header ah = { .opcode = htonl(opcode) };
88 ofpbuf_put(ofpacts, &ah, sizeof ah);
89
90 return ofs;
91}
92
93static void
94encode_finish_controller_op(size_t ofs, struct ofpbuf *ofpacts)
95{
96 struct ofpact_controller *oc = ofpbuf_at_assert(ofpacts, ofs, sizeof *oc);
97 ofpacts->header = oc;
98 oc->userdata_len = ofpacts->size - (ofs + sizeof *oc);
99 ofpact_finish_CONTROLLER(ofpacts, &oc);
100}
101
102static void
103encode_controller_op(enum action_opcode opcode, struct ofpbuf *ofpacts)
104{
105 size_t ofs = encode_start_controller_op(opcode, false, ofpacts);
106 encode_finish_controller_op(ofs, ofpacts);
107}
108
109static void
110init_stack(struct ofpact_stack *stack, enum mf_field_id field)
111{
112 stack->subfield.field = mf_from_id(field);
113 stack->subfield.ofs = 0;
114 stack->subfield.n_bits = stack->subfield.field->n_bits;
115}
116
117struct arg {
118 const struct mf_subfield src;
119 enum mf_field_id dst;
120};
121
122static void
123encode_setup_args(const struct arg args[], size_t n_args,
124 struct ofpbuf *ofpacts)
125{
126 /* 1. Save all of the destinations that will be modified. */
127 for (const struct arg *a = args; a < &args[n_args]; a++) {
128 ovs_assert(a->src.n_bits == mf_from_id(a->dst)->n_bits);
129 if (a->src.field->id != a->dst) {
130 init_stack(ofpact_put_STACK_PUSH(ofpacts), a->dst);
131 }
132 }
133
134 /* 2. Push the sources, in reverse order. */
135 for (size_t i = n_args - 1; i < n_args; i--) {
136 const struct arg *a = &args[i];
137 if (a->src.field->id != a->dst) {
138 ofpact_put_STACK_PUSH(ofpacts)->subfield = a->src;
139 }
140 }
141
142 /* 3. Pop the sources into the destinations. */
143 for (const struct arg *a = args; a < &args[n_args]; a++) {
144 if (a->src.field->id != a->dst) {
145 init_stack(ofpact_put_STACK_POP(ofpacts), a->dst);
146 }
147 }
148}
149
150static void
151encode_restore_args(const struct arg args[], size_t n_args,
152 struct ofpbuf *ofpacts)
153{
154 for (size_t i = n_args - 1; i < n_args; i--) {
155 const struct arg *a = &args[i];
156 if (a->src.field->id != a->dst) {
157 init_stack(ofpact_put_STACK_POP(ofpacts), a->dst);
158 }
159 }
160}
161
162static void
163put_load(uint64_t value, enum mf_field_id dst, int ofs, int n_bits,
164 struct ofpbuf *ofpacts)
165{
128684a6
JR
166 struct ofpact_set_field *sf = ofpact_put_set_field(ofpacts,
167 mf_from_id(dst), NULL,
168 NULL);
d5a76da4 169 ovs_be64 n_value = htonll(value);
128684a6
JR
170 bitwise_copy(&n_value, 8, 0, sf->value, sf->field->n_bytes, ofs, n_bits);
171 bitwise_one(ofpact_set_field_mask(sf), sf->field->n_bytes, ofs, n_bits);
d5a76da4
BP
172}
173\f
174/* Context maintained during ovnacts_parse(). */
3b7cb7e1 175struct action_context {
d5a76da4 176 const struct ovnact_parse_params *pp; /* Parameters. */
3b7cb7e1 177 struct lexer *lexer; /* Lexer for pulling more tokens. */
d5a76da4 178 struct ofpbuf *ovnacts; /* Actions. */
3b7cb7e1
BP
179 struct expr *prereqs; /* Prerequisites to apply to match. */
180};
181
bac29564 182static void parse_actions(struct action_context *, enum lex_type sentinel);
d8681a83 183
3b7cb7e1 184static bool
9aef3c1b
BP
185action_parse_field(struct action_context *ctx,
186 int n_bits, bool rw, struct expr_field *f)
3b7cb7e1 187{
9aef3c1b 188 if (!expr_field_parse(ctx->lexer, ctx->pp->symtab, f, &ctx->prereqs)) {
3b7cb7e1
BP
189 return false;
190 }
d5a76da4 191
9aef3c1b
BP
192 char *error = expr_type_check(f, n_bits, rw);
193 if (error) {
194 lexer_error(ctx->lexer, "%s", error);
195 free(error);
d5a76da4 196 return false;
3b7cb7e1 197 }
3b7cb7e1 198
9aef3c1b 199 return true;
558ec83d
BP
200}
201
d5a76da4
BP
202static bool
203action_parse_port(struct action_context *ctx, uint16_t *port)
204{
205 if (lexer_is_int(ctx->lexer)) {
206 int value = ntohll(ctx->lexer->token.value.integer);
207 if (value <= UINT16_MAX) {
208 *port = value;
209 lexer_get(ctx->lexer);
210 return true;
211 }
212 }
9aef3c1b 213 lexer_syntax_error(ctx->lexer, "expecting port number");
d5a76da4
BP
214 return false;
215}
216
217/* Parses 'prerequisite' as an expression in the context of 'ctx', then adds it
218 * as a conjunction with the existing 'ctx->prereqs'. */
219static void
220add_prerequisite(struct action_context *ctx, const char *prerequisite)
221{
222 struct expr *expr;
223 char *error;
224
225 expr = expr_parse_string(prerequisite, ctx->pp->symtab, NULL, &error);
226 ovs_assert(!error);
227 ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, expr);
228}
80b6743d
BP
229
230static void
231ovnact_null_free(struct ovnact_null *a OVS_UNUSED)
232{
233}
d5a76da4
BP
234\f
235static void
236format_OUTPUT(const struct ovnact_null *a OVS_UNUSED, struct ds *s)
237{
238 ds_put_cstr(s, "output;");
239}
240
241static void
242emit_resubmit(struct ofpbuf *ofpacts, uint8_t ptable)
243{
244 struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(ofpacts);
245 resubmit->in_port = OFPP_IN_PORT;
246 resubmit->table_id = ptable;
247}
248
249static void
250encode_OUTPUT(const struct ovnact_null *a OVS_UNUSED,
251 const struct ovnact_encode_params *ep,
252 struct ofpbuf *ofpacts)
253{
254 emit_resubmit(ofpacts, ep->output_ptable);
255}
d5a76da4 256\f
558ec83d 257static void
d5a76da4 258parse_NEXT(struct action_context *ctx)
558ec83d 259{
d5a76da4 260 if (!ctx->pp->n_tables) {
9aef3c1b 261 lexer_error(ctx->lexer, "\"next\" action not allowed here.");
558ec83d
BP
262 } else if (lexer_match(ctx->lexer, LEX_T_LPAREN)) {
263 int ltable;
264
9aef3c1b
BP
265 if (!lexer_force_int(ctx->lexer, &ltable) ||
266 !lexer_force_match(ctx->lexer, LEX_T_RPAREN)) {
558ec83d
BP
267 return;
268 }
269
d5a76da4 270 if (ltable >= ctx->pp->n_tables) {
9aef3c1b
BP
271 lexer_error(ctx->lexer,
272 "\"next\" argument must be in range 0 to %d.",
d5a76da4 273 ctx->pp->n_tables - 1);
558ec83d
BP
274 return;
275 }
276
d5a76da4 277 ovnact_put_NEXT(ctx->ovnacts)->ltable = ltable;
558ec83d 278 } else {
d5a76da4
BP
279 if (ctx->pp->cur_ltable < ctx->pp->n_tables) {
280 ovnact_put_NEXT(ctx->ovnacts)->ltable = ctx->pp->cur_ltable + 1;
558ec83d 281 } else {
9aef3c1b
BP
282 lexer_error(ctx->lexer,
283 "\"next\" action not allowed in last table.");
558ec83d
BP
284 }
285 }
286}
287
5b84185b 288static void
d5a76da4 289format_NEXT(const struct ovnact_next *next, struct ds *s)
5b84185b 290{
d5a76da4
BP
291 ds_put_format(s, "next(%d);", next->ltable);
292}
5b84185b 293
d5a76da4
BP
294static void
295encode_NEXT(const struct ovnact_next *next,
296 const struct ovnact_encode_params *ep,
297 struct ofpbuf *ofpacts)
298{
299 emit_resubmit(ofpacts, ep->first_ptable + next->ltable);
5b84185b
BP
300}
301
d5a76da4 302static void
80b6743d 303ovnact_next_free(struct ovnact_next *a OVS_UNUSED)
0bac7164 304{
d5a76da4
BP
305}
306\f
307static void
308parse_LOAD(struct action_context *ctx, const struct expr_field *lhs)
309{
310 size_t ofs = ctx->ovnacts->size;
311 struct ovnact_load *load = ovnact_put_LOAD(ctx->ovnacts);
312 load->dst = *lhs;
9aef3c1b 313
d5a76da4 314 char *error = expr_type_check(lhs, lhs->n_bits, true);
d5a76da4
BP
315 if (error) {
316 ctx->ovnacts->size = ofs;
9aef3c1b 317 lexer_error(ctx->lexer, "%s", error);
d5a76da4 318 free(error);
9aef3c1b
BP
319 return;
320 }
321 if (!expr_constant_parse(ctx->lexer, lhs, &load->imm)) {
322 ctx->ovnacts->size = ofs;
323 return;
d5a76da4
BP
324 }
325}
0bac7164 326
d5a76da4
BP
327static enum expr_constant_type
328load_type(const struct ovnact_load *load)
329{
330 return load->dst.symbol->width > 0 ? EXPR_C_INTEGER : EXPR_C_STRING;
331}
0bac7164 332
d5a76da4
BP
333static void
334format_LOAD(const struct ovnact_load *load, struct ds *s)
335{
336 expr_field_format(&load->dst, s);
337 ds_put_cstr(s, " = ");
338 expr_constant_format(&load->imm, load_type(load), s);
339 ds_put_char(s, ';');
340}
0bac7164 341
128684a6
JR
342static void
343encode_LOAD(const struct ovnact_load *load,
344 const struct ovnact_encode_params *ep,
345 struct ofpbuf *ofpacts)
d5a76da4
BP
346{
347 const union expr_constant *c = &load->imm;
348 struct mf_subfield dst = expr_resolve_field(&load->dst);
128684a6
JR
349 struct ofpact_set_field *sf = ofpact_put_set_field(ofpacts, dst.field,
350 NULL, NULL);
d5a76da4
BP
351
352 if (load->dst.symbol->width) {
353 bitwise_copy(&c->value, sizeof c->value, 0,
128684a6 354 sf->value, dst.field->n_bytes, dst.ofs,
d5a76da4
BP
355 dst.n_bits);
356 if (c->masked) {
357 bitwise_copy(&c->mask, sizeof c->mask, 0,
128684a6
JR
358 ofpact_set_field_mask(sf), dst.field->n_bytes,
359 dst.ofs, dst.n_bits);
d5a76da4 360 } else {
128684a6 361 bitwise_one(ofpact_set_field_mask(sf), dst.field->n_bytes,
d5a76da4
BP
362 dst.ofs, dst.n_bits);
363 }
364 } else {
365 uint32_t port;
128684a6 366 if (!ep->lookup_port(ep->aux, load->imm.string, &port)) {
d5a76da4
BP
367 port = 0;
368 }
128684a6 369 bitwise_put(port, sf->value,
d5a76da4 370 sf->field->n_bytes, 0, sf->field->n_bits);
128684a6
JR
371 bitwise_one(ofpact_set_field_mask(sf), sf->field->n_bytes, 0,
372 sf->field->n_bits);
d5a76da4 373 }
0bac7164
BP
374}
375
376static void
80b6743d 377ovnact_load_free(struct ovnact_load *load)
0bac7164 378{
d5a76da4
BP
379 expr_constant_destroy(&load->imm, load_type(load));
380}
381\f
382static void
383format_assignment(const struct ovnact_move *move, const char *operator,
384 struct ds *s)
385{
386 expr_field_format(&move->lhs, s);
387 ds_put_format(s, " %s ", operator);
388 expr_field_format(&move->rhs, s);
389 ds_put_char(s, ';');
0bac7164
BP
390}
391
392static void
d5a76da4 393format_MOVE(const struct ovnact_move *move, struct ds *s)
0bac7164 394{
d5a76da4 395 format_assignment(move, "=", s);
0bac7164
BP
396}
397
6335d074 398static void
d5a76da4
BP
399format_EXCHANGE(const struct ovnact_move *move, struct ds *s)
400{
401 format_assignment(move, "<->", s);
402}
403
404static void
405parse_assignment_action(struct action_context *ctx, bool exchange,
406 const struct expr_field *lhs)
6335d074 407{
d5a76da4 408 struct expr_field rhs;
9aef3c1b 409 if (!expr_field_parse(ctx->lexer, ctx->pp->symtab, &rhs, &ctx->prereqs)) {
6335d074
BP
410 return;
411 }
412
d5a76da4
BP
413 const struct expr_symbol *ls = lhs->symbol;
414 const struct expr_symbol *rs = rhs.symbol;
415 if ((ls->width != 0) != (rs->width != 0)) {
416 if (exchange) {
9aef3c1b
BP
417 lexer_error(ctx->lexer,
418 "Can't exchange %s field (%s) with %s field (%s).",
419 ls->width ? "integer" : "string",
420 ls->name,
421 rs->width ? "integer" : "string",
422 rs->name);
d5a76da4 423 } else {
9aef3c1b
BP
424 lexer_error(ctx->lexer,
425 "Can't assign %s field (%s) to %s field (%s).",
426 rs->width ? "integer" : "string",
427 rs->name,
428 ls->width ? "integer" : "string",
429 ls->name);
d5a76da4
BP
430 }
431 return;
432 }
6335d074 433
d5a76da4
BP
434 if (lhs->n_bits != rhs.n_bits) {
435 if (exchange) {
9aef3c1b
BP
436 lexer_error(ctx->lexer,
437 "Can't exchange %d-bit field with %d-bit field.",
438 lhs->n_bits, rhs.n_bits);
d5a76da4 439 } else {
9aef3c1b
BP
440 lexer_error(ctx->lexer,
441 "Can't assign %d-bit value to %d-bit destination.",
442 rhs.n_bits, lhs->n_bits);
6335d074 443 }
d5a76da4
BP
444 return;
445 } else if (!lhs->n_bits &&
446 ls->field->n_bits != rs->field->n_bits) {
9aef3c1b
BP
447 lexer_error(ctx->lexer, "String fields %s and %s are incompatible for "
448 "%s.", ls->name, rs->name,
449 exchange ? "exchange" : "assignment");
d5a76da4 450 return;
6335d074
BP
451 }
452
9aef3c1b 453 char *error = expr_type_check(lhs, lhs->n_bits, true);
d5a76da4
BP
454 if (!error) {
455 error = expr_type_check(&rhs, rhs.n_bits, true);
456 }
457 if (error) {
9aef3c1b 458 lexer_error(ctx->lexer, "%s", error);
d5a76da4
BP
459 free(error);
460 return;
461 }
6335d074 462
d5a76da4
BP
463 struct ovnact_move *move;
464 move = (exchange
465 ? ovnact_put_EXCHANGE(ctx->ovnacts)
466 : ovnact_put_MOVE(ctx->ovnacts));
467 move->lhs = *lhs;
468 move->rhs = rhs;
469}
6335d074 470
d5a76da4
BP
471static void
472encode_MOVE(const struct ovnact_move *move,
473 const struct ovnact_encode_params *ep OVS_UNUSED,
474 struct ofpbuf *ofpacts)
475{
476 struct ofpact_reg_move *orm = ofpact_put_REG_MOVE(ofpacts);
477 orm->src = expr_resolve_field(&move->rhs);
478 orm->dst = expr_resolve_field(&move->lhs);
6335d074
BP
479}
480
d5a76da4
BP
481static void
482encode_EXCHANGE(const struct ovnact_move *xchg,
483 const struct ovnact_encode_params *ep OVS_UNUSED,
484 struct ofpbuf *ofpacts)
0bac7164 485{
d5a76da4
BP
486 ofpact_put_STACK_PUSH(ofpacts)->subfield = expr_resolve_field(&xchg->rhs);
487 ofpact_put_STACK_PUSH(ofpacts)->subfield = expr_resolve_field(&xchg->lhs);
488 ofpact_put_STACK_POP(ofpacts)->subfield = expr_resolve_field(&xchg->rhs);
489 ofpact_put_STACK_POP(ofpacts)->subfield = expr_resolve_field(&xchg->lhs);
490}
0bac7164 491
d5a76da4 492static void
80b6743d 493ovnact_move_free(struct ovnact_move *move OVS_UNUSED)
d5a76da4
BP
494{
495}
496\f
497static void
498parse_DEC_TTL(struct action_context *ctx)
499{
9aef3c1b 500 lexer_force_match(ctx->lexer, LEX_T_DECREMENT);
d5a76da4
BP
501 ovnact_put_DEC_TTL(ctx->ovnacts);
502 add_prerequisite(ctx, "ip");
503}
0bac7164 504
d5a76da4
BP
505static void
506format_DEC_TTL(const struct ovnact_null *null OVS_UNUSED, struct ds *s)
507{
508 ds_put_cstr(s, "ip.ttl--;");
0bac7164
BP
509}
510
d5a76da4
BP
511static void
512encode_DEC_TTL(const struct ovnact_null *null OVS_UNUSED,
513 const struct ovnact_encode_params *ep OVS_UNUSED,
514 struct ofpbuf *ofpacts)
0bac7164 515{
d5a76da4
BP
516 ofpact_put_DEC_TTL(ofpacts);
517}
d5a76da4
BP
518\f
519static void
520parse_CT_NEXT(struct action_context *ctx)
521{
522 if (ctx->pp->cur_ltable >= ctx->pp->n_tables) {
9aef3c1b
BP
523 lexer_error(ctx->lexer,
524 "\"ct_next\" action not allowed in last table.");
d5a76da4 525 return;
0bac7164
BP
526 }
527
d5a76da4
BP
528 add_prerequisite(ctx, "ip");
529 ovnact_put_CT_NEXT(ctx->ovnacts)->ltable = ctx->pp->cur_ltable + 1;
0bac7164
BP
530}
531
532static void
d5a76da4 533format_CT_NEXT(const struct ovnact_next *next OVS_UNUSED, struct ds *s)
0bac7164 534{
d5a76da4 535 ds_put_cstr(s, "ct_next;");
0bac7164
BP
536}
537
d5a76da4
BP
538static void
539encode_CT_NEXT(const struct ovnact_next *next,
540 const struct ovnact_encode_params *ep,
541 struct ofpbuf *ofpacts)
542{
543 struct ofpact_conntrack *ct = ofpact_put_CT(ofpacts);
544 ct->recirc_table = ep->first_ptable + next->ltable;
d7039b9a
GS
545 ct->zone_src.field = ep->is_switch ? mf_from_id(MFF_LOG_CT_ZONE)
546 : mf_from_id(MFF_LOG_DNAT_ZONE);
d5a76da4
BP
547 ct->zone_src.ofs = 0;
548 ct->zone_src.n_bits = 16;
549 ofpact_finish(ofpacts, &ct->ofpact);
550}
d5a76da4
BP
551\f
552static void
553parse_ct_commit_arg(struct action_context *ctx,
554 struct ovnact_ct_commit *cc)
555{
556 if (lexer_match_id(ctx->lexer, "ct_mark")) {
9aef3c1b 557 if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) {
d5a76da4 558 return;
0bac7164 559 }
d5a76da4
BP
560 if (ctx->lexer->token.type == LEX_T_INTEGER) {
561 cc->ct_mark = ntohll(ctx->lexer->token.value.integer);
562 cc->ct_mark_mask = UINT32_MAX;
563 } else if (ctx->lexer->token.type == LEX_T_MASKED_INTEGER) {
564 cc->ct_mark = ntohll(ctx->lexer->token.value.integer);
565 cc->ct_mark_mask = ntohll(ctx->lexer->token.mask.integer);
566 } else {
9aef3c1b 567 lexer_syntax_error(ctx->lexer, "expecting integer");
d5a76da4 568 return;
0bac7164 569 }
d5a76da4
BP
570 lexer_get(ctx->lexer);
571 } else if (lexer_match_id(ctx->lexer, "ct_label")) {
9aef3c1b 572 if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) {
d5a76da4 573 return;
0bac7164 574 }
d5a76da4
BP
575 if (ctx->lexer->token.type == LEX_T_INTEGER) {
576 cc->ct_label = ctx->lexer->token.value.be128_int;
577 cc->ct_label_mask = OVS_BE128_MAX;
578 } else if (ctx->lexer->token.type == LEX_T_MASKED_INTEGER) {
579 cc->ct_label = ctx->lexer->token.value.be128_int;
580 cc->ct_label_mask = ctx->lexer->token.mask.be128_int;
581 } else {
9aef3c1b 582 lexer_syntax_error(ctx->lexer, "expecting integer");
d5a76da4
BP
583 return;
584 }
585 lexer_get(ctx->lexer);
586 } else {
9aef3c1b 587 lexer_syntax_error(ctx->lexer, NULL);
0bac7164
BP
588 }
589}
590
591static void
d5a76da4 592parse_CT_COMMIT(struct action_context *ctx)
0bac7164 593{
d5a76da4
BP
594 add_prerequisite(ctx, "ip");
595
596 struct ovnact_ct_commit *ct_commit = ovnact_put_CT_COMMIT(ctx->ovnacts);
597 if (lexer_match(ctx->lexer, LEX_T_LPAREN)) {
598 while (!lexer_match(ctx->lexer, LEX_T_RPAREN)) {
599 parse_ct_commit_arg(ctx, ct_commit);
9aef3c1b 600 if (ctx->lexer->error) {
d5a76da4
BP
601 return;
602 }
603 lexer_match(ctx->lexer, LEX_T_COMMA);
0bac7164
BP
604 }
605 }
606}
607
608static void
d5a76da4 609format_CT_COMMIT(const struct ovnact_ct_commit *cc, struct ds *s)
0bac7164 610{
d5a76da4
BP
611 ds_put_cstr(s, "ct_commit(");
612 if (cc->ct_mark_mask) {
613 ds_put_format(s, "ct_mark=%#"PRIx32, cc->ct_mark);
614 if (cc->ct_mark_mask != UINT32_MAX) {
615 ds_put_format(s, "/%#"PRIx32, cc->ct_mark_mask);
616 }
617 }
618 if (!ovs_be128_is_zero(cc->ct_label_mask)) {
619 if (ds_last(s) != '(') {
620 ds_put_cstr(s, ", ");
621 }
0bac7164 622
d5a76da4
BP
623 ds_put_format(s, "ct_label=");
624 ds_put_hex(s, &cc->ct_label, sizeof cc->ct_label);
625 if (!ovs_be128_equals(cc->ct_label_mask, OVS_BE128_MAX)) {
626 ds_put_char(s, '/');
627 ds_put_hex(s, &cc->ct_label_mask, sizeof cc->ct_label_mask);
628 }
629 }
630 if (!ds_chomp(s, '(')) {
631 ds_put_char(s, ')');
632 }
633 ds_put_char(s, ';');
0bac7164
BP
634}
635
636static void
d5a76da4
BP
637encode_CT_COMMIT(const struct ovnact_ct_commit *cc,
638 const struct ovnact_encode_params *ep OVS_UNUSED,
639 struct ofpbuf *ofpacts)
0bac7164 640{
d5a76da4
BP
641 struct ofpact_conntrack *ct = ofpact_put_CT(ofpacts);
642 ct->flags = NX_CT_F_COMMIT;
643 ct->recirc_table = NX_CT_RECIRC_NONE;
644 ct->zone_src.field = mf_from_id(MFF_LOG_CT_ZONE);
645 ct->zone_src.ofs = 0;
646 ct->zone_src.n_bits = 16;
0bac7164 647
d5a76da4
BP
648 size_t set_field_offset = ofpacts->size;
649 ofpbuf_pull(ofpacts, set_field_offset);
0bac7164 650
d5a76da4 651 if (cc->ct_mark_mask) {
128684a6
JR
652 const ovs_be32 value = htonl(cc->ct_mark);
653 const ovs_be32 mask = htonl(cc->ct_mark_mask);
654 ofpact_put_set_field(ofpacts, mf_from_id(MFF_CT_MARK), &value, &mask);
d5a76da4 655 }
0bac7164 656
d5a76da4 657 if (!ovs_be128_is_zero(cc->ct_label_mask)) {
128684a6
JR
658 ofpact_put_set_field(ofpacts, mf_from_id(MFF_CT_LABEL), &cc->ct_label,
659 &cc->ct_label_mask);
d5a76da4 660 }
0bac7164 661
d5a76da4
BP
662 ofpacts->header = ofpbuf_push_uninit(ofpacts, set_field_offset);
663 ct = ofpacts->header;
664 ofpact_finish(ofpacts, &ct->ofpact);
0bac7164
BP
665}
666
667static void
80b6743d 668ovnact_ct_commit_free(struct ovnact_ct_commit *cc OVS_UNUSED)
0bac7164 669{
0bac7164 670}
d5a76da4 671\f
42814145 672static void
d5a76da4
BP
673parse_ct_nat(struct action_context *ctx, const char *name,
674 struct ovnact_ct_nat *cn)
42814145 675{
d5a76da4 676 add_prerequisite(ctx, "ip");
42814145 677
d5a76da4 678 if (ctx->pp->cur_ltable >= ctx->pp->n_tables) {
9aef3c1b
BP
679 lexer_error(ctx->lexer,
680 "\"%s\" action not allowed in last table.", name);
42814145
NS
681 return;
682 }
d5a76da4 683 cn->ltable = ctx->pp->cur_ltable + 1;
42814145 684
d5a76da4
BP
685 if (lexer_match(ctx->lexer, LEX_T_LPAREN)) {
686 if (ctx->lexer->token.type != LEX_T_INTEGER
687 || ctx->lexer->token.format != LEX_F_IPV4) {
9aef3c1b 688 lexer_syntax_error(ctx->lexer, "expecting IPv4 address");
42814145
NS
689 return;
690 }
d5a76da4
BP
691 cn->ip = ctx->lexer->token.value.ipv4;
692 lexer_get(ctx->lexer);
693
9aef3c1b 694 if (!lexer_force_match(ctx->lexer, LEX_T_RPAREN)) {
42814145
NS
695 return;
696 }
697 }
d5a76da4 698}
42814145 699
d5a76da4
BP
700static void
701parse_CT_DNAT(struct action_context *ctx)
702{
703 parse_ct_nat(ctx, "ct_dnat", ovnact_put_CT_DNAT(ctx->ovnacts));
704}
42814145 705
d5a76da4
BP
706static void
707parse_CT_SNAT(struct action_context *ctx)
708{
709 parse_ct_nat(ctx, "ct_snat", ovnact_put_CT_SNAT(ctx->ovnacts));
710}
42814145 711
d5a76da4
BP
712static void
713format_ct_nat(const struct ovnact_ct_nat *cn, const char *name, struct ds *s)
714{
715 ds_put_cstr(s, name);
716 if (cn->ip) {
717 ds_put_format(s, "("IP_FMT")", IP_ARGS(cn->ip));
42814145 718 }
d5a76da4
BP
719 ds_put_char(s, ';');
720}
42814145 721
d5a76da4
BP
722static void
723format_CT_DNAT(const struct ovnact_ct_nat *cn, struct ds *s)
724{
725 format_ct_nat(cn, "ct_dnat", s);
726}
42814145 727
d5a76da4
BP
728static void
729format_CT_SNAT(const struct ovnact_ct_nat *cn, struct ds *s)
730{
731 format_ct_nat(cn, "ct_snat", s);
732}
42814145 733
d5a76da4
BP
734static void
735encode_ct_nat(const struct ovnact_ct_nat *cn,
736 const struct ovnact_encode_params *ep,
737 bool snat, struct ofpbuf *ofpacts)
738{
739 const size_t ct_offset = ofpacts->size;
740 ofpbuf_pull(ofpacts, ct_offset);
42814145 741
d5a76da4
BP
742 struct ofpact_conntrack *ct = ofpact_put_CT(ofpacts);
743 ct->recirc_table = cn->ltable + ep->first_ptable;
744 if (snat) {
745 ct->zone_src.field = mf_from_id(MFF_LOG_SNAT_ZONE);
746 } else {
747 ct->zone_src.field = mf_from_id(MFF_LOG_DNAT_ZONE);
748 }
749 ct->zone_src.ofs = 0;
750 ct->zone_src.n_bits = 16;
751 ct->flags = 0;
752 ct->alg = 0;
42814145 753
d5a76da4
BP
754 struct ofpact_nat *nat;
755 size_t nat_offset;
756 nat_offset = ofpacts->size;
757 ofpbuf_pull(ofpacts, nat_offset);
758
759 nat = ofpact_put_NAT(ofpacts);
760 nat->flags = 0;
761 nat->range_af = AF_UNSPEC;
762
763 if (cn->ip) {
764 nat->range_af = AF_INET;
765 nat->range.addr.ipv4.min = cn->ip;
766 if (snat) {
767 nat->flags |= NX_NAT_F_SRC;
768 } else {
769 nat->flags |= NX_NAT_F_DST;
42814145 770 }
42814145
NS
771 }
772
d5a76da4
BP
773 ofpacts->header = ofpbuf_push_uninit(ofpacts, nat_offset);
774 ct = ofpacts->header;
775 if (cn->ip) {
776 ct->flags |= NX_CT_F_COMMIT;
777 } else if (snat) {
778 /* XXX: For performance reasons, we try to prevent additional
779 * recirculations. So far, ct_snat which is used in a gateway router
780 * does not need a recirculation. ct_snat(IP) does need a
781 * recirculation. Should we consider a method to let the actions
782 * specify whether an action needs recirculation if there more use
783 * cases?. */
784 ct->recirc_table = NX_CT_RECIRC_NONE;
785 }
786 ofpact_finish(ofpacts, &ct->ofpact);
787 ofpbuf_push_uninit(ofpacts, ct_offset);
42814145
NS
788}
789
42814145 790static void
d5a76da4
BP
791encode_CT_DNAT(const struct ovnact_ct_nat *cn,
792 const struct ovnact_encode_params *ep,
793 struct ofpbuf *ofpacts)
42814145 794{
d5a76da4 795 encode_ct_nat(cn, ep, false, ofpacts);
42814145
NS
796}
797
01cfdb2f 798static void
d5a76da4
BP
799encode_CT_SNAT(const struct ovnact_ct_nat *cn,
800 const struct ovnact_encode_params *ep,
801 struct ofpbuf *ofpacts)
01cfdb2f 802{
d5a76da4
BP
803 encode_ct_nat(cn, ep, true, ofpacts);
804}
01cfdb2f 805
d5a76da4 806static void
80b6743d 807ovnact_ct_nat_free(struct ovnact_ct_nat *ct_nat OVS_UNUSED)
d5a76da4
BP
808{
809}
810\f
811static void
812parse_ct_lb_action(struct action_context *ctx)
813{
814 if (ctx->pp->cur_ltable >= ctx->pp->n_tables) {
9aef3c1b 815 lexer_error(ctx->lexer, "\"ct_lb\" action not allowed in last table.");
01cfdb2f
NS
816 return;
817 }
818
d5a76da4 819 add_prerequisite(ctx, "ip");
01cfdb2f 820
d5a76da4
BP
821 struct ovnact_ct_lb_dst *dsts = NULL;
822 size_t allocated_dsts = 0;
823 size_t n_dsts = 0;
01cfdb2f 824
d5a76da4
BP
825 if (lexer_match(ctx->lexer, LEX_T_LPAREN)) {
826 while (!lexer_match(ctx->lexer, LEX_T_RPAREN)) {
827 if (ctx->lexer->token.type != LEX_T_INTEGER
828 || mf_subvalue_width(&ctx->lexer->token.value) > 32) {
9aef3c1b 829 lexer_syntax_error(ctx->lexer, "expecting IPv4 address");
d5a76da4
BP
830 return;
831 }
01cfdb2f 832
d5a76da4
BP
833 /* Parse IP. */
834 ovs_be32 ip = ctx->lexer->token.value.ipv4;
835 lexer_get(ctx->lexer);
01cfdb2f 836
d5a76da4
BP
837 /* Parse optional port. */
838 uint16_t port = 0;
839 if (lexer_match(ctx->lexer, LEX_T_COLON)
840 && !action_parse_port(ctx, &port)) {
841 free(dsts);
842 return;
843 }
844 lexer_match(ctx->lexer, LEX_T_COMMA);
01cfdb2f 845
d5a76da4
BP
846 /* Append to dsts. */
847 if (n_dsts >= allocated_dsts) {
848 dsts = x2nrealloc(dsts, &allocated_dsts, sizeof *dsts);
849 }
850 dsts[n_dsts++] = (struct ovnact_ct_lb_dst) { ip, port };
01cfdb2f 851 }
01cfdb2f
NS
852 }
853
d5a76da4
BP
854 struct ovnact_ct_lb *cl = ovnact_put_CT_LB(ctx->ovnacts);
855 cl->ltable = ctx->pp->cur_ltable + 1;
856 cl->dsts = dsts;
857 cl->n_dsts = n_dsts;
01cfdb2f
NS
858}
859
01cfdb2f 860static void
d5a76da4 861format_CT_LB(const struct ovnact_ct_lb *cl, struct ds *s)
01cfdb2f 862{
d5a76da4
BP
863 ds_put_cstr(s, "ct_lb");
864 if (cl->n_dsts) {
865 ds_put_char(s, '(');
866 for (size_t i = 0; i < cl->n_dsts; i++) {
867 if (i) {
868 ds_put_cstr(s, ", ");
869 }
01cfdb2f 870
d5a76da4
BP
871 const struct ovnact_ct_lb_dst *dst = &cl->dsts[i];
872 ds_put_format(s, IP_FMT, IP_ARGS(dst->ip));
873 if (dst->port) {
874 ds_put_format(s, ":%"PRIu16, dst->port);
875 }
467085fd 876 }
d5a76da4 877 ds_put_char(s, ')');
467085fd 878 }
d5a76da4 879 ds_put_char(s, ';');
467085fd
GS
880}
881
882static void
d5a76da4
BP
883encode_CT_LB(const struct ovnact_ct_lb *cl,
884 const struct ovnact_encode_params *ep,
885 struct ofpbuf *ofpacts)
467085fd 886{
d5a76da4
BP
887 uint8_t recirc_table = cl->ltable + ep->first_ptable;
888 if (!cl->n_dsts) {
889 /* ct_lb without any destinations means that this is an established
467085fd 890 * connection and we just need to do a NAT. */
d5a76da4
BP
891 const size_t ct_offset = ofpacts->size;
892 ofpbuf_pull(ofpacts, ct_offset);
467085fd 893
d5a76da4 894 struct ofpact_conntrack *ct = ofpact_put_CT(ofpacts);
467085fd
GS
895 struct ofpact_nat *nat;
896 size_t nat_offset;
c2e954a1
GS
897 ct->zone_src.field = ep->is_switch ? mf_from_id(MFF_LOG_CT_ZONE)
898 : mf_from_id(MFF_LOG_DNAT_ZONE);
467085fd
GS
899 ct->zone_src.ofs = 0;
900 ct->zone_src.n_bits = 16;
901 ct->flags = 0;
902 ct->recirc_table = recirc_table;
903 ct->alg = 0;
904
d5a76da4
BP
905 nat_offset = ofpacts->size;
906 ofpbuf_pull(ofpacts, nat_offset);
467085fd 907
d5a76da4 908 nat = ofpact_put_NAT(ofpacts);
467085fd
GS
909 nat->flags = 0;
910 nat->range_af = AF_UNSPEC;
911
d5a76da4
BP
912 ofpacts->header = ofpbuf_push_uninit(ofpacts, nat_offset);
913 ct = ofpacts->header;
914 ofpact_finish(ofpacts, &ct->ofpact);
915 ofpbuf_push_uninit(ofpacts, ct_offset);
467085fd
GS
916 return;
917 }
918
d5a76da4 919 uint32_t group_id = 0, hash;
467085fd
GS
920 struct group_info *group_info;
921 struct ofpact_group *og;
c2e954a1
GS
922 uint32_t zone_reg = ep->is_switch ? MFF_LOG_CT_ZONE - MFF_REG0
923 : MFF_LOG_DNAT_ZONE - MFF_REG0;
467085fd
GS
924
925 struct ds ds = DS_EMPTY_INITIALIZER;
926 ds_put_format(&ds, "type=select");
927
928 BUILD_ASSERT(MFF_LOG_CT_ZONE >= MFF_REG0);
929 BUILD_ASSERT(MFF_LOG_CT_ZONE < MFF_REG0 + FLOW_N_REGS);
c2e954a1
GS
930 BUILD_ASSERT(MFF_LOG_DNAT_ZONE >= MFF_REG0);
931 BUILD_ASSERT(MFF_LOG_DNAT_ZONE < MFF_REG0 + FLOW_N_REGS);
d5a76da4
BP
932 for (size_t bucket_id = 0; bucket_id < cl->n_dsts; bucket_id++) {
933 const struct ovnact_ct_lb_dst *dst = &cl->dsts[bucket_id];
934 ds_put_format(&ds, ",bucket=bucket_id=%"PRIuSIZE",weight:100,actions="
935 "ct(nat(dst="IP_FMT, bucket_id, IP_ARGS(dst->ip));
936 if (dst->port) {
937 ds_put_format(&ds, ":%"PRIu16, dst->port);
467085fd
GS
938 }
939 ds_put_format(&ds, "),commit,table=%d,zone=NXM_NX_REG%d[0..15])",
c2e954a1 940 recirc_table, zone_reg);
d5a76da4 941 }
467085fd
GS
942
943 hash = hash_string(ds_cstr(&ds), 0);
944
945 /* Check whether we have non installed but allocated group_id. */
946 HMAP_FOR_EACH_WITH_HASH (group_info, hmap_node, hash,
d5a76da4 947 &ep->group_table->desired_groups) {
467085fd
GS
948 if (!strcmp(ds_cstr(&group_info->group), ds_cstr(&ds))) {
949 group_id = group_info->group_id;
950 break;
951 }
952 }
953
954 if (!group_id) {
955 /* Check whether we already have an installed entry for this
956 * combination. */
957 HMAP_FOR_EACH_WITH_HASH (group_info, hmap_node, hash,
d5a76da4 958 &ep->group_table->existing_groups) {
467085fd
GS
959 if (!strcmp(ds_cstr(&group_info->group), ds_cstr(&ds))) {
960 group_id = group_info->group_id;
961 }
962 }
963
e4f7cf9c 964 bool new_group_id = false;
467085fd
GS
965 if (!group_id) {
966 /* Reserve a new group_id. */
d5a76da4 967 group_id = bitmap_scan(ep->group_table->group_ids, 0, 1,
467085fd 968 MAX_OVN_GROUPS + 1);
e4f7cf9c 969 new_group_id = true;
467085fd
GS
970 }
971
972 if (group_id == MAX_OVN_GROUPS + 1) {
d5a76da4
BP
973 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
974 VLOG_ERR_RL(&rl, "out of group ids");
975
467085fd 976 ds_destroy(&ds);
467085fd
GS
977 return;
978 }
d5a76da4 979 bitmap_set1(ep->group_table->group_ids, group_id);
467085fd
GS
980
981 group_info = xmalloc(sizeof *group_info);
982 group_info->group = ds;
983 group_info->group_id = group_id;
984 group_info->hmap_node.hash = hash;
e4f7cf9c 985 group_info->new_group_id = new_group_id;
467085fd 986
d5a76da4 987 hmap_insert(&ep->group_table->desired_groups,
467085fd
GS
988 &group_info->hmap_node, group_info->hmap_node.hash);
989 } else {
990 ds_destroy(&ds);
991 }
992
d5a76da4
BP
993 /* Create an action to set the group. */
994 og = ofpact_put_GROUP(ofpacts);
995 og->group_id = group_id;
996}
997
998static void
80b6743d 999ovnact_ct_lb_free(struct ovnact_ct_lb *ct_lb)
d5a76da4
BP
1000{
1001 free(ct_lb->dsts);
1002}
1003\f
b3bd2c33
BP
1004/* Implements the "arp", "nd_na", and "clone" actions, which execute nested
1005 * actions on a packet derived from the one being processed. */
d5a76da4
BP
1006static void
1007parse_nested_action(struct action_context *ctx, enum ovnact_type type,
1008 const char *prereq)
1009{
9aef3c1b 1010 if (!lexer_force_match(ctx->lexer, LEX_T_LCURLY)) {
d5a76da4
BP
1011 return;
1012 }
1013
1014 uint64_t stub[1024 / 8];
1015 struct ofpbuf nested = OFPBUF_STUB_INITIALIZER(stub);
1016
1017 struct action_context inner_ctx = {
1018 .pp = ctx->pp,
1019 .lexer = ctx->lexer,
d5a76da4 1020 .ovnacts = &nested,
b3bd2c33 1021 .prereqs = NULL,
d5a76da4 1022 };
bac29564 1023 parse_actions(&inner_ctx, LEX_T_RCURLY);
d5a76da4 1024
b3bd2c33
BP
1025 if (prereq) {
1026 /* XXX Not really sure what we should do with prerequisites for "arp"
1027 * and "nd_na" actions. */
1028 expr_destroy(inner_ctx.prereqs);
1029 add_prerequisite(ctx, prereq);
1030 } else {
1031 /* For "clone", the inner prerequisites should just add to the outer
1032 * ones. */
1033 ctx->prereqs = expr_combine(EXPR_T_AND,
1034 inner_ctx.prereqs, ctx->prereqs);
1035 }
d5a76da4 1036
9aef3c1b 1037 if (inner_ctx.lexer->error) {
d5a76da4
BP
1038 ovnacts_free(nested.data, nested.size);
1039 ofpbuf_uninit(&nested);
1040 return;
1041 }
1042
8a41ad8e
BP
1043 struct ovnact_nest *on = ovnact_put(ctx->ovnacts, type,
1044 OVNACT_ALIGN(sizeof *on));
d5a76da4
BP
1045 on->nested_len = nested.size;
1046 on->nested = ofpbuf_steal_data(&nested);
1047}
1048
1049static void
1050parse_ARP(struct action_context *ctx)
1051{
1052 parse_nested_action(ctx, OVNACT_ARP, "ip4");
1053}
1054
1055static void
1056parse_ND_NA(struct action_context *ctx)
1057{
1058 parse_nested_action(ctx, OVNACT_ND_NA, "nd_ns");
1059}
1060
b3bd2c33
BP
1061static void
1062parse_CLONE(struct action_context *ctx)
1063{
1064 parse_nested_action(ctx, OVNACT_CLONE, NULL);
1065}
1066
d5a76da4
BP
1067static void
1068format_nested_action(const struct ovnact_nest *on, const char *name,
1069 struct ds *s)
1070{
1071 ds_put_format(s, "%s { ", name);
1072 ovnacts_format(on->nested, on->nested_len, s);
1073 ds_put_format(s, " };");
1074}
1075
1076static void
1077format_ARP(const struct ovnact_nest *nest, struct ds *s)
1078{
1079 format_nested_action(nest, "arp", s);
1080}
1081
1082static void
1083format_ND_NA(const struct ovnact_nest *nest, struct ds *s)
1084{
1085 format_nested_action(nest, "nd_na", s);
1086}
1087
1088static void
b3bd2c33
BP
1089format_CLONE(const struct ovnact_nest *nest, struct ds *s)
1090{
1091 format_nested_action(nest, "clone", s);
1092}
1093
1094static void
1095encode_nested_neighbor_actions(const struct ovnact_nest *on,
1096 const struct ovnact_encode_params *ep,
1097 enum action_opcode opcode,
1098 struct ofpbuf *ofpacts)
d5a76da4
BP
1099{
1100 /* Convert nested actions into ofpacts. */
1101 uint64_t inner_ofpacts_stub[1024 / 8];
1102 struct ofpbuf inner_ofpacts = OFPBUF_STUB_INITIALIZER(inner_ofpacts_stub);
1103 ovnacts_encode(on->nested, on->nested_len, ep, &inner_ofpacts);
1104
1105 /* Add a "controller" action with the actions nested inside "{...}",
1106 * converted to OpenFlow, as its userdata. ovn-controller will convert the
1107 * packet to ARP or NA and then send the packet and actions back to the
1108 * switch inside an OFPT_PACKET_OUT message. */
1109 size_t oc_offset = encode_start_controller_op(opcode, false, ofpacts);
1110 ofpacts_put_openflow_actions(inner_ofpacts.data, inner_ofpacts.size,
1111 ofpacts, OFP13_VERSION);
1112 encode_finish_controller_op(oc_offset, ofpacts);
1113
1114 /* Free memory. */
1115 ofpbuf_uninit(&inner_ofpacts);
1116}
1117
1118static void
1119encode_ARP(const struct ovnact_nest *on,
1120 const struct ovnact_encode_params *ep,
1121 struct ofpbuf *ofpacts)
1122{
b3bd2c33 1123 encode_nested_neighbor_actions(on, ep, ACTION_OPCODE_ARP, ofpacts);
d5a76da4
BP
1124}
1125
1126static void
1127encode_ND_NA(const struct ovnact_nest *on,
1128 const struct ovnact_encode_params *ep,
1129 struct ofpbuf *ofpacts)
1130{
b3bd2c33 1131 encode_nested_neighbor_actions(on, ep, ACTION_OPCODE_ND_NA, ofpacts);
d5a76da4
BP
1132}
1133
b3bd2c33
BP
1134static void
1135encode_CLONE(const struct ovnact_nest *on,
1136 const struct ovnact_encode_params *ep,
1137 struct ofpbuf *ofpacts)
1138{
1139 size_t ofs = ofpacts->size;
1140 ofpact_put_CLONE(ofpacts);
1141 ovnacts_encode(on->nested, on->nested_len, ep, ofpacts);
1142
1143 struct ofpact_nest *clone = ofpbuf_at_assert(ofpacts, ofs, sizeof *clone);
1144 ofpacts->header = clone;
1145 ofpact_finish_CLONE(ofpacts, &clone);
1146}
80b6743d 1147
d5a76da4 1148static void
80b6743d 1149ovnact_nest_free(struct ovnact_nest *on)
d5a76da4
BP
1150{
1151 ovnacts_free(on->nested, on->nested_len);
1152 free(on->nested);
1153}
d5a76da4
BP
1154\f
1155static void
1156parse_get_mac_bind(struct action_context *ctx, int width,
1157 struct ovnact_get_mac_bind *get_mac)
1158{
9aef3c1b 1159 lexer_force_match(ctx->lexer, LEX_T_LPAREN);
d5a76da4 1160 action_parse_field(ctx, 0, false, &get_mac->port);
9aef3c1b 1161 lexer_force_match(ctx->lexer, LEX_T_COMMA);
d5a76da4 1162 action_parse_field(ctx, width, false, &get_mac->ip);
9aef3c1b 1163 lexer_force_match(ctx->lexer, LEX_T_RPAREN);
d5a76da4
BP
1164}
1165
1166static void
1167format_get_mac_bind(const struct ovnact_get_mac_bind *get_mac,
1168 const char *name, struct ds *s)
1169{
1170 ds_put_format(s, "%s(", name);
1171 expr_field_format(&get_mac->port, s);
1172 ds_put_cstr(s, ", ");
1173 expr_field_format(&get_mac->ip, s);
1174 ds_put_cstr(s, ");");
1175}
1176
1177static void
1178format_GET_ARP(const struct ovnact_get_mac_bind *get_mac, struct ds *s)
1179{
1180 format_get_mac_bind(get_mac, "get_arp", s);
1181}
1182
1183static void
1184format_GET_ND(const struct ovnact_get_mac_bind *get_mac, struct ds *s)
1185{
1186 format_get_mac_bind(get_mac, "get_nd", s);
1187}
1188
1189static void
1190encode_get_mac(const struct ovnact_get_mac_bind *get_mac,
1191 enum mf_field_id ip_field,
1192 const struct ovnact_encode_params *ep,
1193 struct ofpbuf *ofpacts)
1194{
1195 const struct arg args[] = {
1196 { expr_resolve_field(&get_mac->port), MFF_LOG_OUTPORT },
1197 { expr_resolve_field(&get_mac->ip), ip_field },
1198 };
1199 encode_setup_args(args, ARRAY_SIZE(args), ofpacts);
1200
1201 put_load(0, MFF_ETH_DST, 0, 48, ofpacts);
1202 emit_resubmit(ofpacts, ep->mac_bind_ptable);
1203
1204 encode_restore_args(args, ARRAY_SIZE(args), ofpacts);
1205}
1206
1207static void
1208encode_GET_ARP(const struct ovnact_get_mac_bind *get_mac,
1209 const struct ovnact_encode_params *ep,
1210 struct ofpbuf *ofpacts)
1211{
1212 encode_get_mac(get_mac, MFF_REG0, ep, ofpacts);
1213}
1214
1215static void
1216encode_GET_ND(const struct ovnact_get_mac_bind *get_mac,
1217 const struct ovnact_encode_params *ep,
1218 struct ofpbuf *ofpacts)
1219{
1220 encode_get_mac(get_mac, MFF_XXREG0, ep, ofpacts);
1221}
1222
1223static void
80b6743d 1224ovnact_get_mac_bind_free(struct ovnact_get_mac_bind *get_mac OVS_UNUSED)
d5a76da4
BP
1225{
1226}
1227\f
1228static void
1229parse_put_mac_bind(struct action_context *ctx, int width,
1230 struct ovnact_put_mac_bind *put_mac)
1231{
9aef3c1b 1232 lexer_force_match(ctx->lexer, LEX_T_LPAREN);
d5a76da4 1233 action_parse_field(ctx, 0, false, &put_mac->port);
9aef3c1b 1234 lexer_force_match(ctx->lexer, LEX_T_COMMA);
d5a76da4 1235 action_parse_field(ctx, width, false, &put_mac->ip);
9aef3c1b 1236 lexer_force_match(ctx->lexer, LEX_T_COMMA);
d5a76da4 1237 action_parse_field(ctx, 48, false, &put_mac->mac);
9aef3c1b 1238 lexer_force_match(ctx->lexer, LEX_T_RPAREN);
d5a76da4
BP
1239}
1240
1241static void
1242format_put_mac_bind(const struct ovnact_put_mac_bind *put_mac,
1243 const char *name, struct ds *s)
1244{
1245 ds_put_format(s, "%s(", name);
1246 expr_field_format(&put_mac->port, s);
1247 ds_put_cstr(s, ", ");
1248 expr_field_format(&put_mac->ip, s);
1249 ds_put_cstr(s, ", ");
1250 expr_field_format(&put_mac->mac, s);
1251 ds_put_cstr(s, ");");
1252}
1253
1254static void
1255format_PUT_ARP(const struct ovnact_put_mac_bind *put_mac, struct ds *s)
1256{
1257 format_put_mac_bind(put_mac, "put_arp", s);
1258}
1259
1260static void
1261format_PUT_ND(const struct ovnact_put_mac_bind *put_mac, struct ds *s)
1262{
1263 format_put_mac_bind(put_mac, "put_nd", s);
1264}
1265
1266static void
1267encode_put_mac(const struct ovnact_put_mac_bind *put_mac,
1268 enum mf_field_id ip_field, enum action_opcode opcode,
1269 struct ofpbuf *ofpacts)
1270{
1271 const struct arg args[] = {
1272 { expr_resolve_field(&put_mac->port), MFF_LOG_INPORT },
1273 { expr_resolve_field(&put_mac->ip), ip_field },
1274 { expr_resolve_field(&put_mac->mac), MFF_ETH_SRC }
1275 };
1276 encode_setup_args(args, ARRAY_SIZE(args), ofpacts);
1277 encode_controller_op(opcode, ofpacts);
1278 encode_restore_args(args, ARRAY_SIZE(args), ofpacts);
1279}
1280
1281static void
1282encode_PUT_ARP(const struct ovnact_put_mac_bind *put_mac,
1283 const struct ovnact_encode_params *ep OVS_UNUSED,
1284 struct ofpbuf *ofpacts)
1285{
1286 encode_put_mac(put_mac, MFF_REG0, ACTION_OPCODE_PUT_ARP, ofpacts);
1287}
1288
1289static void
1290encode_PUT_ND(const struct ovnact_put_mac_bind *put_mac,
1291 const struct ovnact_encode_params *ep OVS_UNUSED,
1292 struct ofpbuf *ofpacts)
1293{
1294 encode_put_mac(put_mac, MFF_XXREG0, ACTION_OPCODE_PUT_ND, ofpacts);
467085fd
GS
1295}
1296
c34a87b6 1297static void
80b6743d 1298ovnact_put_mac_bind_free(struct ovnact_put_mac_bind *put_mac OVS_UNUSED)
d5a76da4
BP
1299{
1300}
1301\f
1302static void
1303parse_dhcp_opt(struct action_context *ctx, struct ovnact_dhcp_option *o,
1304 bool v6)
1305{
1306 if (ctx->lexer->token.type != LEX_T_ID) {
9aef3c1b 1307 lexer_syntax_error(ctx->lexer, NULL);
c34a87b6
JP
1308 return;
1309 }
1310
d5a76da4
BP
1311 const char *name = v6 ? "DHCPv6" : "DHCPv4";
1312 const struct hmap *map = v6 ? ctx->pp->dhcpv6_opts : ctx->pp->dhcp_opts;
ebf8381b 1313 o->option = map ? dhcp_opts_find(map, ctx->lexer->token.s) : NULL;
d5a76da4 1314 if (!o->option) {
9aef3c1b 1315 lexer_syntax_error(ctx->lexer, "expecting %s option name", name);
d5a76da4
BP
1316 return;
1317 }
1318 lexer_get(ctx->lexer);
1319
9aef3c1b 1320 if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) {
d5a76da4
BP
1321 return;
1322 }
1323
9aef3c1b 1324 if (!expr_constant_set_parse(ctx->lexer, &o->value)) {
d5a76da4 1325 memset(&o->value, 0, sizeof o->value);
d5a76da4
BP
1326 return;
1327 }
c34a87b6 1328
d5a76da4
BP
1329 if (!strcmp(o->option->type, "str")) {
1330 if (o->value.type != EXPR_C_STRING) {
9aef3c1b
BP
1331 lexer_error(ctx->lexer, "%s option %s requires string value.",
1332 name, o->option->name);
d5a76da4
BP
1333 return;
1334 }
1335 } else {
1336 if (o->value.type != EXPR_C_INTEGER) {
9aef3c1b
BP
1337 lexer_error(ctx->lexer, "%s option %s requires numeric value.",
1338 name, o->option->name);
d5a76da4
BP
1339 return;
1340 }
1341 }
1342}
c34a87b6 1343
d5a76da4
BP
1344static const struct ovnact_dhcp_option *
1345find_offerip(const struct ovnact_dhcp_option *options, size_t n)
1346{
1347 for (const struct ovnact_dhcp_option *o = options; o < &options[n]; o++) {
1348 if (o->option->code == 0) {
1349 return o;
1350 }
1351 }
1352 return NULL;
c34a87b6
JP
1353}
1354
1355static void
d5a76da4 1356free_dhcp_options(struct ovnact_dhcp_option *options, size_t n)
c34a87b6 1357{
d5a76da4
BP
1358 for (struct ovnact_dhcp_option *o = options; o < &options[n]; o++) {
1359 expr_constant_set_destroy(&o->value);
c34a87b6 1360 }
d5a76da4 1361 free(options);
c34a87b6
JP
1362}
1363
d5a76da4
BP
1364/* Parses the "put_dhcp_opts" and "put_dhcpv6_opts" actions.
1365 *
1366 * The caller has already consumed "<dst> =", so this just parses the rest. */
78aab811 1367static void
d5a76da4
BP
1368parse_put_dhcp_opts(struct action_context *ctx,
1369 const struct expr_field *dst,
1370 struct ovnact_put_dhcp_opts *pdo)
78aab811 1371{
d5a76da4
BP
1372 lexer_get(ctx->lexer); /* Skip put_dhcp[v6]_opts. */
1373 lexer_get(ctx->lexer); /* Skip '('. */
78aab811 1374
d5a76da4
BP
1375 /* Validate that the destination is a 1-bit, modifiable field. */
1376 char *error = expr_type_check(dst, 1, true);
1377 if (error) {
9aef3c1b 1378 lexer_error(ctx->lexer, "%s", error);
d5a76da4
BP
1379 free(error);
1380 return;
78aab811 1381 }
d5a76da4 1382 pdo->dst = *dst;
78aab811 1383
d5a76da4
BP
1384 size_t allocated_options = 0;
1385 while (!lexer_match(ctx->lexer, LEX_T_RPAREN)) {
1386 if (pdo->n_options >= allocated_options) {
1387 pdo->options = x2nrealloc(pdo->options, &allocated_options,
1388 sizeof *pdo->options);
1389 }
78aab811 1390
d5a76da4
BP
1391 struct ovnact_dhcp_option *o = &pdo->options[pdo->n_options++];
1392 memset(o, 0, sizeof *o);
1393 parse_dhcp_opt(ctx, o, pdo->ovnact.type == OVNACT_PUT_DHCPV6_OPTS);
9aef3c1b 1394 if (ctx->lexer->error) {
d5a76da4
BP
1395 return;
1396 }
a9e1b66f 1397
d5a76da4
BP
1398 lexer_match(ctx->lexer, LEX_T_COMMA);
1399 }
a9e1b66f 1400
d5a76da4
BP
1401 if (pdo->ovnact.type == OVNACT_PUT_DHCPV4_OPTS
1402 && !find_offerip(pdo->options, pdo->n_options)) {
9aef3c1b
BP
1403 lexer_error(ctx->lexer,
1404 "put_dhcp_opts requires offerip to be specified.");
d5a76da4 1405 return;
a9e1b66f 1406 }
d5a76da4 1407}
a9e1b66f 1408
d5a76da4
BP
1409static void
1410format_put_dhcp_opts(const char *name,
1411 const struct ovnact_put_dhcp_opts *pdo, struct ds *s)
1412{
1413 expr_field_format(&pdo->dst, s);
1414 ds_put_format(s, " = %s(", name);
1415 for (const struct ovnact_dhcp_option *o = pdo->options;
1416 o < &pdo->options[pdo->n_options]; o++) {
1417 if (o != pdo->options) {
1418 ds_put_cstr(s, ", ");
1419 }
1420 ds_put_format(s, "%s = ", o->option->name);
1421 expr_constant_set_format(&o->value, s);
a9e1b66f 1422 }
d5a76da4
BP
1423 ds_put_cstr(s, ");");
1424}
a9e1b66f 1425
d5a76da4
BP
1426static void
1427format_PUT_DHCPV4_OPTS(const struct ovnact_put_dhcp_opts *pdo, struct ds *s)
1428{
1429 format_put_dhcp_opts("put_dhcp_opts", pdo, s);
a9e1b66f
RB
1430}
1431
d5a76da4
BP
1432static void
1433format_PUT_DHCPV6_OPTS(const struct ovnact_put_dhcp_opts *pdo, struct ds *s)
a9e1b66f 1434{
d5a76da4
BP
1435 format_put_dhcp_opts("put_dhcpv6_opts", pdo, s);
1436}
1437
1438static void
1439encode_put_dhcpv4_option(const struct ovnact_dhcp_option *o,
1440 struct ofpbuf *ofpacts)
1441{
1442 uint8_t *opt_header = ofpbuf_put_zeros(ofpacts, 2);
1443 opt_header[0] = o->option->code;
1444
1445 const union expr_constant *c = o->value.values;
1446 size_t n_values = o->value.n_values;
1447 if (!strcmp(o->option->type, "bool") ||
1448 !strcmp(o->option->type, "uint8")) {
1449 opt_header[1] = 1;
1450 ofpbuf_put(ofpacts, &c->value.u8_val, 1);
1451 } else if (!strcmp(o->option->type, "uint16")) {
1452 opt_header[1] = 2;
1453 ofpbuf_put(ofpacts, &c->value.be16_int, 2);
1454 } else if (!strcmp(o->option->type, "uint32")) {
1455 opt_header[1] = 4;
1456 ofpbuf_put(ofpacts, &c->value.be32_int, 4);
1457 } else if (!strcmp(o->option->type, "ipv4")) {
1458 opt_header[1] = n_values * sizeof(ovs_be32);
1459 for (size_t i = 0; i < n_values; i++) {
1460 ofpbuf_put(ofpacts, &c[i].value.ipv4, sizeof(ovs_be32));
a9e1b66f 1461 }
d5a76da4
BP
1462 } else if (!strcmp(o->option->type, "static_routes")) {
1463 size_t no_of_routes = n_values;
1464 if (no_of_routes % 2) {
1465 no_of_routes -= 1;
a9e1b66f 1466 }
d5a76da4 1467 opt_header[1] = 0;
354b8f27 1468
d5a76da4
BP
1469 /* Calculating the length of this option first because when
1470 * we call ofpbuf_put, it might reallocate the buffer if the
1471 * tail room is short making "opt_header" pointer invalid.
1472 * So running the for loop twice.
1473 */
1474 for (size_t i = 0; i < no_of_routes; i += 2) {
1475 uint8_t plen = 32;
1476 if (c[i].masked) {
1477 plen = (uint8_t) ip_count_cidr_bits(c[i].mask.ipv4);
1478 }
1479 opt_header[1] += (1 + (plen / 8) + sizeof(ovs_be32)) ;
a9e1b66f 1480 }
a9e1b66f 1481
d5a76da4
BP
1482 /* Copied from RFC 3442. Please refer to this RFC for the format of
1483 * the classless static route option.
1484 *
1485 * The following table contains some examples of how various subnet
1486 * number/mask combinations can be encoded:
1487 *
1488 * Subnet number Subnet mask Destination descriptor
1489 * 0 0 0
1490 * 10.0.0.0 255.0.0.0 8.10
1491 * 10.0.0.0 255.255.255.0 24.10.0.0
1492 * 10.17.0.0 255.255.0.0 16.10.17
1493 * 10.27.129.0 255.255.255.0 24.10.27.129
1494 * 10.229.0.128 255.255.255.128 25.10.229.0.128
1495 * 10.198.122.47 255.255.255.255 32.10.198.122.47
1496 */
1497
1498 for (size_t i = 0; i < no_of_routes; i += 2) {
1499 uint8_t plen = 32;
1500 if (c[i].masked) {
1501 plen = ip_count_cidr_bits(c[i].mask.ipv4);
1502 }
1503 ofpbuf_put(ofpacts, &plen, 1);
1504 ofpbuf_put(ofpacts, &c[i].value.ipv4, plen / 8);
1505 ofpbuf_put(ofpacts, &c[i + 1].value.ipv4,
1506 sizeof(ovs_be32));
a9e1b66f 1507 }
d5a76da4
BP
1508 } else if (!strcmp(o->option->type, "str")) {
1509 opt_header[1] = strlen(c->string);
1510 ofpbuf_put(ofpacts, c->string, opt_header[1]);
a9e1b66f 1511 }
a9e1b66f
RB
1512}
1513
1514static void
d5a76da4
BP
1515encode_put_dhcpv6_option(const struct ovnact_dhcp_option *o,
1516 struct ofpbuf *ofpacts)
a9e1b66f 1517{
d5a76da4 1518 struct dhcp_opt6_header *opt = ofpbuf_put_uninit(ofpacts, sizeof *opt);
d5a76da4
BP
1519 const union expr_constant *c = o->value.values;
1520 size_t n_values = o->value.n_values;
a55dacac
DDP
1521 size_t size;
1522
1523 opt->opt_code = htons(o->option->code);
1524
d5a76da4 1525 if (!strcmp(o->option->type, "ipv6")) {
a55dacac
DDP
1526 size = n_values * sizeof(struct in6_addr);
1527 opt->size = htons(size);
d5a76da4
BP
1528 for (size_t i = 0; i < n_values; i++) {
1529 ofpbuf_put(ofpacts, &c[i].value.ipv6, sizeof(struct in6_addr));
1530 }
1531 } else if (!strcmp(o->option->type, "mac")) {
a55dacac
DDP
1532 size = sizeof(struct eth_addr);
1533 opt->size = htons(size);
1534 ofpbuf_put(ofpacts, &c->value.mac, size);
d5a76da4 1535 } else if (!strcmp(o->option->type, "str")) {
a55dacac
DDP
1536 size = strlen(c->string);
1537 opt->size = htons(size);
1538 ofpbuf_put(ofpacts, c->string, size);
a9e1b66f 1539 }
d5a76da4 1540}
a9e1b66f 1541
d5a76da4
BP
1542static void
1543encode_PUT_DHCPV4_OPTS(const struct ovnact_put_dhcp_opts *pdo,
1544 const struct ovnact_encode_params *ep OVS_UNUSED,
1545 struct ofpbuf *ofpacts)
1546{
1547 struct mf_subfield dst = expr_resolve_field(&pdo->dst);
1548
1549 size_t oc_offset = encode_start_controller_op(ACTION_OPCODE_PUT_DHCP_OPTS,
1550 true, ofpacts);
1551 nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false);
1552 ovs_be32 ofs = htonl(dst.ofs);
1553 ofpbuf_put(ofpacts, &ofs, sizeof ofs);
1554
1555 /* Encode the offerip option first, because it's a special case and needs
1556 * to be first in the actual DHCP response, and then encode the rest
1557 * (skipping offerip the second time around). */
1558 const struct ovnact_dhcp_option *offerip_opt = find_offerip(
1559 pdo->options, pdo->n_options);
1560 ovs_be32 offerip = offerip_opt->value.values[0].value.ipv4;
1561 ofpbuf_put(ofpacts, &offerip, sizeof offerip);
1562
1563 for (const struct ovnact_dhcp_option *o = pdo->options;
1564 o < &pdo->options[pdo->n_options]; o++) {
1565 if (o != offerip_opt) {
1566 encode_put_dhcpv4_option(o, ofpacts);
a9e1b66f
RB
1567 }
1568 }
1569
d5a76da4 1570 encode_finish_controller_op(oc_offset, ofpacts);
78aab811
JP
1571}
1572
de297547 1573static void
d5a76da4
BP
1574encode_PUT_DHCPV6_OPTS(const struct ovnact_put_dhcp_opts *pdo,
1575 const struct ovnact_encode_params *ep OVS_UNUSED,
1576 struct ofpbuf *ofpacts)
de297547 1577{
d5a76da4 1578 struct mf_subfield dst = expr_resolve_field(&pdo->dst);
de297547 1579
d5a76da4
BP
1580 size_t oc_offset = encode_start_controller_op(
1581 ACTION_OPCODE_PUT_DHCPV6_OPTS, true, ofpacts);
1582 nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false);
1583 ovs_be32 ofs = htonl(dst.ofs);
1584 ofpbuf_put(ofpacts, &ofs, sizeof ofs);
de297547 1585
d5a76da4
BP
1586 for (const struct ovnact_dhcp_option *o = pdo->options;
1587 o < &pdo->options[pdo->n_options]; o++) {
1588 encode_put_dhcpv6_option(o, ofpacts);
de297547 1589 }
de297547 1590
d5a76da4
BP
1591 encode_finish_controller_op(oc_offset, ofpacts);
1592}
de297547 1593
d5a76da4 1594static void
80b6743d 1595ovnact_put_dhcp_opts_free(struct ovnact_put_dhcp_opts *pdo)
d5a76da4
BP
1596{
1597 free_dhcp_options(pdo->options, pdo->n_options);
1598}
de297547 1599
a6095f81
BS
1600static void
1601parse_SET_QUEUE(struct action_context *ctx)
1602{
1603 int queue_id;
1604
1605 if (!lexer_force_match(ctx->lexer, LEX_T_LPAREN)
1606 || !lexer_get_int(ctx->lexer, &queue_id)
1607 || !lexer_force_match(ctx->lexer, LEX_T_RPAREN)) {
1608 return;
1609 }
1610
1611 if (queue_id < QDISC_MIN_QUEUE_ID || queue_id > QDISC_MAX_QUEUE_ID) {
1612 lexer_error(ctx->lexer, "Queue ID %d for set_queue is "
1613 "not in valid range %d to %d.",
1614 queue_id, QDISC_MIN_QUEUE_ID, QDISC_MAX_QUEUE_ID);
1615 return;
1616 }
1617
1618 ovnact_put_SET_QUEUE(ctx->ovnacts)->queue_id = queue_id;
1619}
1620
1621static void
1622format_SET_QUEUE(const struct ovnact_set_queue *set_queue, struct ds *s)
1623{
1624 ds_put_format(s, "set_queue(%d);", set_queue->queue_id);
1625}
1626
1627static void
1628encode_SET_QUEUE(const struct ovnact_set_queue *set_queue,
1629 const struct ovnact_encode_params *ep OVS_UNUSED,
1630 struct ofpbuf *ofpacts)
1631{
1632 ofpact_put_SET_QUEUE(ofpacts)->queue_id = set_queue->queue_id;
1633}
1634
1635static void
80b6743d 1636ovnact_set_queue_free(struct ovnact_set_queue *a OVS_UNUSED)
a6095f81
BS
1637{
1638}
d5a76da4
BP
1639\f
1640/* Parses an assignment or exchange or put_dhcp_opts action. */
1641static void
1642parse_set_action(struct action_context *ctx)
1643{
d5a76da4 1644 struct expr_field lhs;
9aef3c1b
BP
1645 if (!expr_field_parse(ctx->lexer, ctx->pp->symtab, &lhs, &ctx->prereqs)) {
1646 return;
1647 }
de297547 1648
9aef3c1b
BP
1649 if (lexer_match(ctx->lexer, LEX_T_EXCHANGE)) {
1650 parse_assignment_action(ctx, true, &lhs);
1651 } else if (lexer_match(ctx->lexer, LEX_T_EQUALS)) {
1652 if (ctx->lexer->token.type != LEX_T_ID) {
1653 parse_LOAD(ctx, &lhs);
1654 } else if (!strcmp(ctx->lexer->token.s, "put_dhcp_opts")
1655 && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
1656 parse_put_dhcp_opts(ctx, &lhs, ovnact_put_PUT_DHCPV4_OPTS(
1657 ctx->ovnacts));
1658 } else if (!strcmp(ctx->lexer->token.s, "put_dhcpv6_opts")
1659 && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
1660 parse_put_dhcp_opts(ctx, &lhs, ovnact_put_PUT_DHCPV6_OPTS(
1661 ctx->ovnacts));
de297547 1662 } else {
9aef3c1b 1663 parse_assignment_action(ctx, false, &lhs);
de297547 1664 }
9aef3c1b
BP
1665 } else {
1666 lexer_syntax_error(ctx->lexer, "expecting `=' or `<->'");
de297547 1667 }
de297547
GS
1668}
1669
d8681a83
BP
1670static bool
1671parse_action(struct action_context *ctx)
1672{
1673 if (ctx->lexer->token.type != LEX_T_ID) {
9aef3c1b 1674 lexer_syntax_error(ctx->lexer, NULL);
d8681a83
BP
1675 return false;
1676 }
1677
1678 enum lex_type lookahead = lexer_lookahead(ctx->lexer);
1679 if (lookahead == LEX_T_EQUALS || lookahead == LEX_T_EXCHANGE
1680 || lookahead == LEX_T_LSQUARE) {
1681 parse_set_action(ctx);
1682 } else if (lexer_match_id(ctx->lexer, "next")) {
d5a76da4 1683 parse_NEXT(ctx);
d8681a83 1684 } else if (lexer_match_id(ctx->lexer, "output")) {
d5a76da4 1685 ovnact_put_OUTPUT(ctx->ovnacts);
d8681a83 1686 } else if (lexer_match_id(ctx->lexer, "ip.ttl")) {
d5a76da4 1687 parse_DEC_TTL(ctx);
d8681a83 1688 } else if (lexer_match_id(ctx->lexer, "ct_next")) {
d5a76da4 1689 parse_CT_NEXT(ctx);
d8681a83 1690 } else if (lexer_match_id(ctx->lexer, "ct_commit")) {
d5a76da4 1691 parse_CT_COMMIT(ctx);
de297547 1692 } else if (lexer_match_id(ctx->lexer, "ct_dnat")) {
d5a76da4 1693 parse_CT_DNAT(ctx);
de297547 1694 } else if (lexer_match_id(ctx->lexer, "ct_snat")) {
d5a76da4 1695 parse_CT_SNAT(ctx);
467085fd
GS
1696 } else if (lexer_match_id(ctx->lexer, "ct_lb")) {
1697 parse_ct_lb_action(ctx);
b3bd2c33
BP
1698 } else if (lexer_match_id(ctx->lexer, "clone")) {
1699 parse_CLONE(ctx);
6335d074 1700 } else if (lexer_match_id(ctx->lexer, "arp")) {
d5a76da4
BP
1701 parse_ARP(ctx);
1702 } else if (lexer_match_id(ctx->lexer, "nd_na")) {
1703 parse_ND_NA(ctx);
0bac7164 1704 } else if (lexer_match_id(ctx->lexer, "get_arp")) {
d5a76da4 1705 parse_get_mac_bind(ctx, 32, ovnact_put_GET_ARP(ctx->ovnacts));
0bac7164 1706 } else if (lexer_match_id(ctx->lexer, "put_arp")) {
d5a76da4 1707 parse_put_mac_bind(ctx, 32, ovnact_put_PUT_ARP(ctx->ovnacts));
c34a87b6 1708 } else if (lexer_match_id(ctx->lexer, "get_nd")) {
d5a76da4 1709 parse_get_mac_bind(ctx, 128, ovnact_put_GET_ND(ctx->ovnacts));
c34a87b6 1710 } else if (lexer_match_id(ctx->lexer, "put_nd")) {
d5a76da4 1711 parse_put_mac_bind(ctx, 128, ovnact_put_PUT_ND(ctx->ovnacts));
a6095f81
BS
1712 } else if (lexer_match_id(ctx->lexer, "set_queue")) {
1713 parse_SET_QUEUE(ctx);
d8681a83 1714 } else {
9aef3c1b 1715 lexer_syntax_error(ctx->lexer, "expecting action");
d8681a83 1716 }
9aef3c1b
BP
1717 lexer_force_match(ctx->lexer, LEX_T_SEMICOLON);
1718 return !ctx->lexer->error;
d8681a83
BP
1719}
1720
3b7cb7e1 1721static void
bac29564 1722parse_actions(struct action_context *ctx, enum lex_type sentinel)
3b7cb7e1
BP
1723{
1724 /* "drop;" by itself is a valid (empty) set of actions, but it can't be
1725 * combined with other actions because that doesn't make sense. */
1726 if (ctx->lexer->token.type == LEX_T_ID
1727 && !strcmp(ctx->lexer->token.s, "drop")
1728 && lexer_lookahead(ctx->lexer) == LEX_T_SEMICOLON) {
1729 lexer_get(ctx->lexer); /* Skip "drop". */
1730 lexer_get(ctx->lexer); /* Skip ";". */
bac29564 1731 lexer_force_match(ctx->lexer, sentinel);
3b7cb7e1
BP
1732 return;
1733 }
1734
bac29564 1735 while (!lexer_match(ctx->lexer, sentinel)) {
d8681a83 1736 if (!parse_action(ctx)) {
3b7cb7e1
BP
1737 return;
1738 }
1739 }
1740}
1741
1742/* Parses OVN actions, in the format described for the "actions" column in the
48605550 1743 * Logical_Flow table in ovn-sb(5), and appends the parsed versions of the
d5a76da4
BP
1744 * actions to 'ovnacts' as "struct ovnact"s. The caller must eventually free
1745 * the parsed ovnacts with ovnacts_free().
3b7cb7e1 1746 *
d5a76da4 1747 * 'pp' provides most of the parameters for translation.
3646e396 1748 *
3b7cb7e1
BP
1749 * Some actions add extra requirements (prerequisites) to the flow's match. If
1750 * so, this function sets '*prereqsp' to the actions' prerequisites; otherwise,
1751 * it sets '*prereqsp' to NULL. The caller owns '*prereqsp' and must
1752 * eventually free it.
1753 *
9aef3c1b
BP
1754 * Returns true if successful, false if an error occurred. Upon return,
1755 * returns true if and only if lexer->error is NULL.
d5a76da4 1756 */
9aef3c1b 1757bool
d5a76da4
BP
1758ovnacts_parse(struct lexer *lexer, const struct ovnact_parse_params *pp,
1759 struct ofpbuf *ovnacts, struct expr **prereqsp)
3b7cb7e1 1760{
d5a76da4 1761 size_t ovnacts_start = ovnacts->size;
3b7cb7e1 1762
1d7b2ece 1763 struct action_context ctx = {
d5a76da4 1764 .pp = pp,
1d7b2ece 1765 .lexer = lexer,
d5a76da4 1766 .ovnacts = ovnacts,
1d7b2ece
BP
1767 .prereqs = NULL,
1768 };
9aef3c1b 1769 if (!lexer->error) {
bac29564 1770 parse_actions(&ctx, LEX_T_END);
9aef3c1b 1771 }
3b7cb7e1 1772
9aef3c1b 1773 if (!lexer->error) {
3b7cb7e1 1774 *prereqsp = ctx.prereqs;
9aef3c1b 1775 return true;
3b7cb7e1 1776 } else {
d5a76da4
BP
1777 ofpbuf_pull(ovnacts, ovnacts_start);
1778 ovnacts_free(ovnacts->data, ovnacts->size);
1779 ofpbuf_push_uninit(ovnacts, ovnacts_start);
1780
1781 ovnacts->size = ovnacts_start;
3b7cb7e1
BP
1782 expr_destroy(ctx.prereqs);
1783 *prereqsp = NULL;
9aef3c1b 1784 return false;
3b7cb7e1
BP
1785 }
1786}
1787
d5a76da4 1788/* Like ovnacts_parse(), but the actions are taken from 's'. */
3b7cb7e1 1789char * OVS_WARN_UNUSED_RESULT
d5a76da4 1790ovnacts_parse_string(const char *s, const struct ovnact_parse_params *pp,
1d7b2ece 1791 struct ofpbuf *ofpacts, struct expr **prereqsp)
3b7cb7e1
BP
1792{
1793 struct lexer lexer;
3b7cb7e1
BP
1794
1795 lexer_init(&lexer, s);
1796 lexer_get(&lexer);
9aef3c1b
BP
1797 ovnacts_parse(&lexer, pp, ofpacts, prereqsp);
1798 char *error = lexer_steal_error(&lexer);
3b7cb7e1
BP
1799 lexer_destroy(&lexer);
1800
1801 return error;
1802}
d5a76da4
BP
1803\f
1804/* Formatting ovnacts. */
1805
1806static void
1807ovnact_format(const struct ovnact *a, struct ds *s)
1808{
1809 switch (a->type) {
1810#define OVNACT(ENUM, STRUCT) \
1811 case OVNACT_##ENUM: \
1812 format_##ENUM(ALIGNED_CAST(const struct STRUCT *, a), s); \
1813 break;
1814 OVNACTS
1815#undef OVNACT
1816 default:
1817 OVS_NOT_REACHED();
1818 }
1819}
1820
1821/* Appends a string representing the 'ovnacts_len' bytes of ovnacts in
1822 * 'ovnacts' to 'string'. */
1823void
1824ovnacts_format(const struct ovnact *ovnacts, size_t ovnacts_len,
1825 struct ds *string)
1826{
1827 if (!ovnacts_len) {
1828 ds_put_cstr(string, "drop;");
1829 } else {
1830 const struct ovnact *a;
1831
1832 OVNACT_FOR_EACH (a, ovnacts, ovnacts_len) {
1833 if (a != ovnacts) {
1834 ds_put_char(string, ' ');
1835 }
1836 ovnact_format(a, string);
1837 }
1838 }
1839}
1840\f
1841/* Encoding ovnacts to OpenFlow. */
1842
1843static void
1844ovnact_encode(const struct ovnact *a, const struct ovnact_encode_params *ep,
1845 struct ofpbuf *ofpacts)
1846{
1847 switch (a->type) {
1848#define OVNACT(ENUM, STRUCT) \
1849 case OVNACT_##ENUM: \
1850 encode_##ENUM(ALIGNED_CAST(const struct STRUCT *, a), \
1851 ep, ofpacts); \
1852 break;
1853 OVNACTS
1854#undef OVNACT
1855 default:
1856 OVS_NOT_REACHED();
1857 }
1858}
1859
1860/* Appends ofpacts to 'ofpacts' that represent the actions in the 'ovnacts_len'
1861 * bytes of actions starting at 'ovnacts'. */
1862void
1863ovnacts_encode(const struct ovnact *ovnacts, size_t ovnacts_len,
1864 const struct ovnact_encode_params *ep,
1865 struct ofpbuf *ofpacts)
1866{
1867 if (ovnacts) {
1868 const struct ovnact *a;
1869
1870 OVNACT_FOR_EACH (a, ovnacts, ovnacts_len) {
1871 ovnact_encode(a, ep, ofpacts);
1872 }
1873 }
1874}
1875\f
1876/* Freeing ovnacts. */
1877
1878static void
1879ovnact_free(struct ovnact *a)
1880{
1881 switch (a->type) {
1882#define OVNACT(ENUM, STRUCT) \
1883 case OVNACT_##ENUM: \
80b6743d 1884 STRUCT##_free(ALIGNED_CAST(struct STRUCT *, a)); \
d5a76da4
BP
1885 break;
1886 OVNACTS
1887#undef OVNACT
1888 default:
1889 OVS_NOT_REACHED();
1890 }
1891}
1892
1893/* Frees each of the actions in the 'ovnacts_len' bytes of actions starting at
1894 * 'ovnacts'.
1895 *
1896 * Does not call free(ovnacts); the caller must do so if desirable. */
1897void
1898ovnacts_free(struct ovnact *ovnacts, size_t ovnacts_len)
1899{
1900 if (ovnacts) {
1901 struct ovnact *a;
1902
1903 OVNACT_FOR_EACH (a, ovnacts, ovnacts_len) {
1904 ovnact_free(a);
1905 }
1906 }
1907}