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