2 * Copyright (c) 2011, 2012 Nicira Networks.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include "byte-order.h"
22 #include "dynamic-string.h"
23 #include "meta-flow.h"
25 #include "ofp-errors.h"
28 #include "openflow/openflow.h"
29 #include "unaligned.h"
32 get_be16(const void **pp
)
34 const ovs_be16
*p
= *pp
;
41 get_be32(const void **pp
)
43 const ovs_be32
*p
= *pp
;
44 ovs_be32 value
= get_unaligned_be32(p
);
50 get_bits(int n_bits
, const void **p
)
52 int n_segs
= DIV_ROUND_UP(n_bits
, 16);
56 while (n_segs
-- > 0) {
57 value
= (value
<< 16) | ntohs(get_be16(p
));
63 get_subfield(int n_bits
, const void **p
, struct mf_subfield
*sf
)
65 sf
->field
= mf_from_nxm_header(ntohl(get_be32(p
)));
66 sf
->ofs
= ntohs(get_be16(p
));
71 learn_min_len(uint16_t header
)
73 int n_bits
= header
& NX_LEARN_N_BITS_MASK
;
74 int src_type
= header
& NX_LEARN_SRC_MASK
;
75 int dst_type
= header
& NX_LEARN_DST_MASK
;
79 if (src_type
== NX_LEARN_SRC_FIELD
) {
80 min_len
+= sizeof(ovs_be32
); /* src_field */
81 min_len
+= sizeof(ovs_be16
); /* src_ofs */
83 min_len
+= DIV_ROUND_UP(n_bits
, 16);
85 if (dst_type
== NX_LEARN_DST_MATCH
||
86 dst_type
== NX_LEARN_DST_LOAD
) {
87 min_len
+= sizeof(ovs_be32
); /* dst_field */
88 min_len
+= sizeof(ovs_be16
); /* dst_ofs */
94 learn_check_header(uint16_t header
, size_t len
)
96 int src_type
= header
& NX_LEARN_SRC_MASK
;
97 int dst_type
= header
& NX_LEARN_DST_MASK
;
99 /* Check for valid src and dst type combination. */
100 if (dst_type
== NX_LEARN_DST_MATCH
||
101 dst_type
== NX_LEARN_DST_LOAD
||
102 (dst_type
== NX_LEARN_DST_OUTPUT
&&
103 src_type
== NX_LEARN_SRC_FIELD
)) {
106 return OFPERR_OFPBAC_BAD_ARGUMENT
;
109 /* Check that the arguments don't overrun the end of the action. */
110 if (len
< learn_min_len(header
)) {
111 return OFPERR_OFPBAC_BAD_LEN
;
117 /* Checks that 'learn' (which must be at least 'sizeof *learn' bytes long) is a
118 * valid action on 'flow'. */
120 learn_check(const struct nx_action_learn
*learn
, const struct flow
*flow
)
122 struct cls_rule rule
;
125 cls_rule_init_catchall(&rule
, 0);
127 if (learn
->flags
& ~htons(OFPFF_SEND_FLOW_REM
)
129 || learn
->table_id
== 0xff) {
130 return OFPERR_OFPBAC_BAD_ARGUMENT
;
133 end
= (char *) learn
+ ntohs(learn
->len
);
134 for (p
= learn
+ 1; p
!= end
; ) {
135 uint16_t header
= ntohs(get_be16(&p
));
136 int n_bits
= header
& NX_LEARN_N_BITS_MASK
;
137 int src_type
= header
& NX_LEARN_SRC_MASK
;
138 int dst_type
= header
& NX_LEARN_DST_MASK
;
147 error
= learn_check_header(header
, (char *) end
- (char *) p
);
152 /* Check the source. */
153 if (src_type
== NX_LEARN_SRC_FIELD
) {
154 struct mf_subfield src
;
156 get_subfield(n_bits
, &p
, &src
);
157 error
= mf_check_src(&src
, flow
);
163 value
= get_bits(n_bits
, &p
);
166 /* Check the destination. */
167 if (dst_type
== NX_LEARN_DST_MATCH
|| dst_type
== NX_LEARN_DST_LOAD
) {
168 struct mf_subfield dst
;
170 get_subfield(n_bits
, &p
, &dst
);
171 error
= (dst_type
== NX_LEARN_DST_LOAD
172 ? mf_check_dst(&dst
, &rule
.flow
)
173 : mf_check_src(&dst
, &rule
.flow
));
178 if (dst_type
== NX_LEARN_DST_MATCH
179 && src_type
== NX_LEARN_SRC_IMMEDIATE
) {
180 mf_set_subfield(&dst
, value
, &rule
);
184 if (!is_all_zeros(p
, (char *) end
- (char *) p
)) {
185 return OFPERR_OFPBAC_BAD_ARGUMENT
;
192 learn_execute(const struct nx_action_learn
*learn
, const struct flow
*flow
,
193 struct ofputil_flow_mod
*fm
)
196 struct ofpbuf actions
;
198 cls_rule_init_catchall(&fm
->cr
, ntohs(learn
->priority
));
199 fm
->cookie
= learn
->cookie
;
200 fm
->table_id
= learn
->table_id
;
201 fm
->command
= OFPFC_MODIFY_STRICT
;
202 fm
->idle_timeout
= ntohs(learn
->idle_timeout
);
203 fm
->hard_timeout
= ntohs(learn
->hard_timeout
);
204 fm
->buffer_id
= UINT32_MAX
;
205 fm
->out_port
= OFPP_NONE
;
206 fm
->flags
= ntohs(learn
->flags
) & OFPFF_SEND_FLOW_REM
;
210 ofpbuf_init(&actions
, 64);
212 if (learn
->fin_idle_timeout
|| learn
->fin_hard_timeout
) {
213 struct nx_action_fin_timeout
*naft
;
215 naft
= ofputil_put_NXAST_FIN_TIMEOUT(&actions
);
216 naft
->fin_idle_timeout
= learn
->fin_idle_timeout
;
217 naft
->fin_hard_timeout
= learn
->fin_hard_timeout
;
220 for (p
= learn
+ 1, end
= (char *) learn
+ ntohs(learn
->len
); p
!= end
; ) {
221 uint16_t header
= ntohs(get_be16(&p
));
222 int n_bits
= header
& NX_LEARN_N_BITS_MASK
;
223 int src_type
= header
& NX_LEARN_SRC_MASK
;
224 int dst_type
= header
& NX_LEARN_DST_MASK
;
227 struct nx_action_reg_load
*load
;
228 struct mf_subfield dst
;
234 if (src_type
== NX_LEARN_SRC_FIELD
) {
235 struct mf_subfield src
;
237 get_subfield(n_bits
, &p
, &src
);
238 value
= mf_get_subfield(&src
, flow
);
240 value
= get_bits(n_bits
, &p
);
244 case NX_LEARN_DST_MATCH
:
245 get_subfield(n_bits
, &p
, &dst
);
246 mf_set_subfield(&dst
, value
, &fm
->cr
);
249 case NX_LEARN_DST_LOAD
:
250 get_subfield(n_bits
, &p
, &dst
);
251 load
= ofputil_put_NXAST_REG_LOAD(&actions
);
252 load
->ofs_nbits
= nxm_encode_ofs_nbits(dst
.ofs
, dst
.n_bits
);
253 load
->dst
= htonl(dst
.field
->nxm_header
);
254 load
->value
= htonll(value
);
257 case NX_LEARN_DST_OUTPUT
:
258 ofputil_put_OFPAT_OUTPUT(&actions
)->port
= htons(value
);
263 fm
->actions
= ofpbuf_steal_data(&actions
);
264 fm
->n_actions
= actions
.size
/ sizeof(struct ofp_action_header
);
268 put_be16(struct ofpbuf
*b
, ovs_be16 x
)
270 ofpbuf_put(b
, &x
, sizeof x
);
274 put_be32(struct ofpbuf
*b
, ovs_be32 x
)
276 ofpbuf_put(b
, &x
, sizeof x
);
280 put_u16(struct ofpbuf
*b
, uint16_t x
)
282 put_be16(b
, htons(x
));
286 put_u32(struct ofpbuf
*b
, uint32_t x
)
288 put_be32(b
, htonl(x
));
295 struct mf_subfield src
;
296 uint8_t src_imm
[sizeof(union mf_value
)];
299 struct mf_subfield dst
;
303 learn_parse_spec(const char *orig
, char *name
, char *value
,
304 struct learn_spec
*spec
)
306 memset(spec
, 0, sizeof *spec
);
307 if (mf_from_name(name
)) {
308 const struct mf_field
*dst
= mf_from_name(name
);
312 error
= mf_parse_value(dst
, value
, &imm
);
314 ovs_fatal(0, "%s", error
);
317 spec
->n_bits
= dst
->n_bits
;
318 spec
->src_type
= NX_LEARN_SRC_IMMEDIATE
;
319 memcpy(spec
->src_imm
, &imm
, dst
->n_bytes
);
320 spec
->dst_type
= NX_LEARN_DST_MATCH
;
321 spec
->dst
.field
= dst
;
323 spec
->dst
.n_bits
= dst
->n_bits
;
324 } else if (strchr(name
, '[')) {
325 /* Parse destination and check prerequisites. */
326 if (mf_parse_subfield(&spec
->dst
, name
)[0] != '\0') {
327 ovs_fatal(0, "%s: syntax error after NXM field name `%s'",
331 /* Parse source and check prerequisites. */
332 if (value
[0] != '\0') {
333 if (mf_parse_subfield(&spec
->src
, value
)[0] != '\0') {
334 ovs_fatal(0, "%s: syntax error after NXM field name `%s'",
337 if (spec
->src
.n_bits
!= spec
->dst
.n_bits
) {
338 ovs_fatal(0, "%s: bit widths of %s (%u) and %s (%u) differ",
339 orig
, name
, spec
->src
.n_bits
, value
,
343 spec
->src
= spec
->dst
;
346 spec
->n_bits
= spec
->src
.n_bits
;
347 spec
->src_type
= NX_LEARN_SRC_FIELD
;
348 spec
->dst_type
= NX_LEARN_DST_MATCH
;
349 } else if (!strcmp(name
, "load")) {
350 if (value
[strcspn(value
, "[-")] == '-') {
351 struct nx_action_reg_load load
;
352 int nbits
, imm_bytes
;
356 nxm_parse_reg_load(&load
, value
);
357 nbits
= nxm_decode_n_bits(load
.ofs_nbits
);
358 imm_bytes
= DIV_ROUND_UP(nbits
, 8);
359 imm
= ntohll(load
.value
);
361 spec
->n_bits
= nbits
;
362 spec
->src_type
= NX_LEARN_SRC_IMMEDIATE
;
363 for (i
= 0; i
< imm_bytes
; i
++) {
364 spec
->src_imm
[i
] = imm
>> ((imm_bytes
- i
- 1) * 8);
366 spec
->dst_type
= NX_LEARN_DST_LOAD
;
367 nxm_decode(&spec
->dst
, load
.dst
, load
.ofs_nbits
);
369 struct nx_action_reg_move move
;
371 nxm_parse_reg_move(&move
, value
);
373 spec
->n_bits
= ntohs(move
.n_bits
);
374 spec
->src_type
= NX_LEARN_SRC_FIELD
;
375 nxm_decode_discrete(&spec
->src
,
376 move
.src
, move
.src_ofs
, move
.n_bits
);
377 spec
->dst_type
= NX_LEARN_DST_LOAD
;
378 nxm_decode_discrete(&spec
->dst
,
379 move
.dst
, move
.dst_ofs
, move
.n_bits
);
381 } else if (!strcmp(name
, "output")) {
382 if (mf_parse_subfield(&spec
->src
, value
)[0] != '\0') {
383 ovs_fatal(0, "%s: syntax error after NXM field name `%s'",
387 spec
->n_bits
= spec
->src
.n_bits
;
388 spec
->src_type
= NX_LEARN_SRC_FIELD
;
389 spec
->dst_type
= NX_LEARN_DST_OUTPUT
;
391 ovs_fatal(0, "%s: unknown keyword %s", orig
, name
);
395 /* Parses 'arg' as a set of arguments to the "learn" action and appends a
396 * matching NXAST_LEARN action to 'b'. The format parsed is described in
399 * Prints an error on stderr and aborts the program if 'arg' syntax is invalid.
401 * If 'flow' is nonnull, then it should be the flow from a cls_rule that is
402 * the matching rule for the learning action. This helps to better validate
403 * the action's arguments.
407 learn_parse(struct ofpbuf
*b
, char *arg
, const struct flow
*flow
)
409 char *orig
= xstrdup(arg
);
415 struct nx_action_learn
*learn
;
416 struct cls_rule rule
;
419 learn
= ofputil_put_NXAST_LEARN(b
);
420 learn
->idle_timeout
= htons(OFP_FLOW_PERMANENT
);
421 learn
->hard_timeout
= htons(OFP_FLOW_PERMANENT
);
422 learn
->priority
= htons(OFP_DEFAULT_PRIORITY
);
423 learn
->cookie
= htonll(0);
424 learn
->flags
= htons(0);
427 cls_rule_init_catchall(&rule
, 0);
428 while (ofputil_parse_key_value(&arg
, &name
, &value
)) {
429 learn
= ofpbuf_at_assert(b
, learn_ofs
, sizeof *learn
);
430 if (!strcmp(name
, "table")) {
431 learn
->table_id
= atoi(value
);
432 if (learn
->table_id
== 255) {
433 ovs_fatal(0, "%s: table id 255 not valid for `learn' action",
436 } else if (!strcmp(name
, "priority")) {
437 learn
->priority
= htons(atoi(value
));
438 } else if (!strcmp(name
, "idle_timeout")) {
439 learn
->idle_timeout
= htons(atoi(value
));
440 } else if (!strcmp(name
, "hard_timeout")) {
441 learn
->hard_timeout
= htons(atoi(value
));
442 } else if (!strcmp(name
, "fin_idle_timeout")) {
443 learn
->fin_idle_timeout
= htons(atoi(value
));
444 } else if (!strcmp(name
, "fin_hard_timeout")) {
445 learn
->fin_hard_timeout
= htons(atoi(value
));
446 } else if (!strcmp(name
, "cookie")) {
447 learn
->cookie
= htonll(strtoull(value
, NULL
, 0));
449 struct learn_spec spec
;
451 learn_parse_spec(orig
, name
, value
, &spec
);
453 /* Check prerequisites. */
454 if (spec
.src_type
== NX_LEARN_SRC_FIELD
455 && flow
&& !mf_are_prereqs_ok(spec
.src
.field
, flow
)) {
456 ovs_fatal(0, "%s: cannot specify source field %s because "
457 "prerequisites are not satisfied",
458 orig
, spec
.src
.field
->name
);
460 if ((spec
.dst_type
== NX_LEARN_DST_MATCH
461 || spec
.dst_type
== NX_LEARN_DST_LOAD
)
462 && !mf_are_prereqs_ok(spec
.dst
.field
, &rule
.flow
)) {
463 ovs_fatal(0, "%s: cannot specify destination field %s because "
464 "prerequisites are not satisfied",
465 orig
, spec
.dst
.field
->name
);
468 /* Update 'rule' to allow for satisfying destination
470 if (spec
.src_type
== NX_LEARN_SRC_IMMEDIATE
471 && spec
.dst_type
== NX_LEARN_DST_MATCH
473 && spec
.n_bits
== spec
.dst
.field
->n_bytes
* 8) {
476 memcpy(&imm
, spec
.src_imm
, spec
.dst
.field
->n_bytes
);
477 mf_set_value(spec
.dst
.field
, &imm
, &rule
);
480 /* Output the flow_mod_spec. */
481 put_u16(b
, spec
.n_bits
| spec
.src_type
| spec
.dst_type
);
482 if (spec
.src_type
== NX_LEARN_SRC_IMMEDIATE
) {
483 int n_bytes
= DIV_ROUND_UP(spec
.n_bits
, 8);
485 ofpbuf_put_zeros(b
, 1);
487 ofpbuf_put(b
, spec
.src_imm
, n_bytes
);
489 put_u32(b
, spec
.src
.field
->nxm_header
);
490 put_u16(b
, spec
.src
.ofs
);
492 if (spec
.dst_type
== NX_LEARN_DST_MATCH
||
493 spec
.dst_type
== NX_LEARN_DST_LOAD
) {
494 put_u32(b
, spec
.dst
.field
->nxm_header
);
495 put_u16(b
, spec
.dst
.ofs
);
497 assert(spec
.dst_type
== NX_LEARN_DST_OUTPUT
);
504 len
= b
->size
- learn_ofs
;
506 ofpbuf_put_zeros(b
, 8 - len
% 8);
509 learn
= ofpbuf_at_assert(b
, learn_ofs
, sizeof *learn
);
510 learn
->len
= htons(b
->size
- learn_ofs
);
512 /* In theory the above should have caught any errors, but... */
514 error
= learn_check(learn
, flow
);
516 ovs_fatal(0, "%s: %s", orig
, ofperr_to_string(error
));
523 learn_format(const struct nx_action_learn
*learn
, struct ds
*s
)
525 struct cls_rule rule
;
528 cls_rule_init_catchall(&rule
, 0);
530 ds_put_format(s
, "learn(table=%"PRIu8
, learn
->table_id
);
531 if (learn
->idle_timeout
!= htons(OFP_FLOW_PERMANENT
)) {
532 ds_put_format(s
, ",idle_timeout=%"PRIu16
, ntohs(learn
->idle_timeout
));
534 if (learn
->hard_timeout
!= htons(OFP_FLOW_PERMANENT
)) {
535 ds_put_format(s
, ",hard_timeout=%"PRIu16
, ntohs(learn
->hard_timeout
));
537 if (learn
->fin_idle_timeout
) {
538 ds_put_format(s
, ",fin_idle_timeout=%"PRIu16
,
539 ntohs(learn
->fin_idle_timeout
));
541 if (learn
->fin_hard_timeout
) {
542 ds_put_format(s
, ",fin_hard_timeout=%"PRIu16
,
543 ntohs(learn
->fin_hard_timeout
));
545 if (learn
->priority
!= htons(OFP_DEFAULT_PRIORITY
)) {
546 ds_put_format(s
, ",priority=%"PRIu16
, ntohs(learn
->priority
));
548 if (learn
->flags
& htons(OFPFF_SEND_FLOW_REM
)) {
549 ds_put_cstr(s
, ",OFPFF_SEND_FLOW_REM");
551 if (learn
->flags
& htons(~OFPFF_SEND_FLOW_REM
)) {
552 ds_put_format(s
, ",***flags=%"PRIu16
"***",
553 ntohs(learn
->flags
) & ~OFPFF_SEND_FLOW_REM
);
555 if (learn
->cookie
!= htonll(0)) {
556 ds_put_format(s
, ",cookie=0x%"PRIx64
, ntohll(learn
->cookie
));
558 if (learn
->pad
!= 0) {
559 ds_put_cstr(s
, ",***nonzero pad***");
562 end
= (char *) learn
+ ntohs(learn
->len
);
563 for (p
= learn
+ 1; p
!= end
; ) {
564 uint16_t header
= ntohs(get_be16(&p
));
565 int n_bits
= header
& NX_LEARN_N_BITS_MASK
;
567 int src_type
= header
& NX_LEARN_SRC_MASK
;
568 struct mf_subfield src
;
569 const uint8_t *src_value
;
572 int dst_type
= header
& NX_LEARN_DST_MASK
;
573 struct mf_subfield dst
;
582 error
= learn_check_header(header
, (char *) end
- (char *) p
);
583 if (error
== OFPERR_OFPBAC_BAD_ARGUMENT
) {
584 ds_put_format(s
, ",***bad flow_mod_spec header %"PRIx16
"***)",
587 } else if (error
== OFPERR_OFPBAC_BAD_LEN
) {
588 ds_put_format(s
, ",***flow_mod_spec at offset %td is %u bytes "
589 "long but only %td bytes are left***)",
590 (char *) p
- (char *) (learn
+ 1) - 2,
591 learn_min_len(header
) + 2,
592 (char *) end
- (char *) p
+ 2);
597 /* Get the source. */
598 if (src_type
== NX_LEARN_SRC_FIELD
) {
599 get_subfield(n_bits
, &p
, &src
);
606 src_value_bytes
= 2 * DIV_ROUND_UP(n_bits
, 16);
608 p
= (const void *) ((const uint8_t *) p
+ src_value_bytes
);
611 /* Get the destination. */
612 if (dst_type
== NX_LEARN_DST_MATCH
|| dst_type
== NX_LEARN_DST_LOAD
) {
613 get_subfield(n_bits
, &p
, &dst
);
622 switch (src_type
| dst_type
) {
623 case NX_LEARN_SRC_IMMEDIATE
| NX_LEARN_DST_MATCH
:
624 if (dst
.field
&& dst
.ofs
== 0 && n_bits
== dst
.field
->n_bits
) {
625 union mf_value value
;
626 uint8_t *bytes
= (uint8_t *) &value
;
628 if (src_value_bytes
> dst
.field
->n_bytes
) {
629 /* The destination field is an odd number of bytes, which
630 * got rounded up to a multiple of 2 to be put into the
631 * learning action. Skip over the leading byte, which
632 * should be zero anyway. Otherwise the memcpy() below
633 * will overrun the start of 'value'. */
634 int diff
= src_value_bytes
- dst
.field
->n_bytes
;
636 src_value_bytes
-= diff
;
639 memset(&value
, 0, sizeof value
);
640 memcpy(&bytes
[dst
.field
->n_bytes
- src_value_bytes
],
641 src_value
, src_value_bytes
);
642 ds_put_format(s
, "%s=", dst
.field
->name
);
643 mf_format(dst
.field
, &value
, NULL
, s
);
645 mf_format_subfield(&dst
, s
);
646 ds_put_cstr(s
, "=0x");
647 for (i
= 0; i
< src_value_bytes
; i
++) {
648 ds_put_format(s
, "%02"PRIx8
, src_value
[i
]);
653 case NX_LEARN_SRC_FIELD
| NX_LEARN_DST_MATCH
:
654 mf_format_subfield(&dst
, s
);
655 if (src
.field
!= dst
.field
|| src
.ofs
!= dst
.ofs
) {
657 mf_format_subfield(&src
, s
);
661 case NX_LEARN_SRC_IMMEDIATE
| NX_LEARN_DST_LOAD
:
662 ds_put_cstr(s
, "load:0x");
663 for (i
= 0; i
< src_value_bytes
; i
++) {
664 ds_put_format(s
, "%02"PRIx8
, src_value
[i
]);
666 ds_put_cstr(s
, "->");
667 mf_format_subfield(&dst
, s
);
670 case NX_LEARN_SRC_FIELD
| NX_LEARN_DST_LOAD
:
671 ds_put_cstr(s
, "load:");
672 mf_format_subfield(&src
, s
);
673 ds_put_cstr(s
, "->");
674 mf_format_subfield(&dst
, s
);
677 case NX_LEARN_SRC_FIELD
| NX_LEARN_DST_OUTPUT
:
678 ds_put_cstr(s
, "output:");
679 mf_format_subfield(&src
, s
);
683 if (!is_all_zeros(p
, (char *) end
- (char *) p
)) {
684 ds_put_cstr(s
, ",***nonzero trailer***");