forked from openvswitch/ovs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathofp-actions.c
6836 lines (5991 loc) · 218 KB
/
ofp-actions.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <config.h>
#include "ofp-actions.h"
#include "bundle.h"
#include "byte-order.h"
#include "compiler.h"
#include "dummy.h"
#include "dynamic-string.h"
#include "hmap.h"
#include "learn.h"
#include "meta-flow.h"
#include "multipath.h"
#include "nx-match.h"
#include "ofp-parse.h"
#include "ofp-util.h"
#include "ofpbuf.h"
#include "unaligned.h"
#include "util.h"
#include "openvswitch/vlog.h"
VLOG_DEFINE_THIS_MODULE(ofp_actions);
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
struct ofp_action_header;
/* Raw identifiers for OpenFlow actions.
*
* Decoding and encoding OpenFlow actions across multiple versions is difficult
* to do in a clean, consistent way. This enumeration lays out all of the
* forms of actions that Open vSwitch supports.
*
* The comments here must follow a stylized form because the
* "extract-ofp-actions" program parses them at build time to generate data
* tables.
*
* - The first part of each comment specifies the vendor, OpenFlow versions,
* and type for each protocol that supports the action:
*
* # The vendor is OF for standard OpenFlow actions, NX for Nicira
* extension actions. (Support for other vendors can be added, but
* it can't be done just based on a vendor ID definition alone
* because OpenFlow doesn't define a standard way to specify a
* subtype for vendor actions, so other vendors might do it different
* from Nicira.)
*
* # The version can specify a specific OpenFlow version, a version
* range delimited by "-", or an open-ended range with "+".
*
* # The type, in parentheses, is the action type number (for standard
* OpenFlow actions) or subtype (for vendor extension actions).
*
* # Optionally one may add "is deprecated" followed by a
* human-readable reason in parentheses (which will be used in log
* messages), if a particular action should no longer be used.
*
* Multiple such specifications may be separated by commas.
*
* - The second part describes the action's wire format. It may be:
*
* # "struct <name>": The struct fully specifies the wire format. The
* action is exactly the size of the struct. (Thus, the struct must
* be an exact multiple of 8 bytes in size.)
*
* # "struct <name>, ...": The struct specifies the beginning of the
* wire format. An instance of the action is either the struct's
* exact size, or a multiple of 8 bytes longer.
*
* # "uint<N>_t" or "ovs_be<N>": The action consists of a (standard or
* vendor extension) header, followed by 0 or more pad bytes to align
* to a multiple of <N> bits, followed by an argument of the given
* type, followed by 0 or more pad bytes to bring the total action up
* to a multiple of 8 bytes.
*
* # "void": The action is just a (standard or vendor extension)
* header.
*
* - Optional additional text enclosed in square brackets is commentary for
* the human reader.
*/
enum ofp_raw_action_type {
/* ## ----------------- ## */
/* ## Standard actions. ## */
/* ## ----------------- ## */
/* OF1.0(0): struct ofp10_action_output. */
OFPAT_RAW10_OUTPUT,
/* OF1.1+(0): struct ofp11_action_output. */
OFPAT_RAW11_OUTPUT,
/* OF1.0(1): uint16_t. */
OFPAT_RAW10_SET_VLAN_VID,
/* OF1.0(2): uint8_t. */
OFPAT_RAW10_SET_VLAN_PCP,
/* OF1.1(1), OF1.2+(1) is deprecated (use Set-Field): uint16_t.
*
* [Semantics differ slightly between the 1.0 and 1.1 versions of the VLAN
* modification actions: the 1.0 versions push a VLAN header if none is
* present, but the 1.1 versions do not. That is the only reason that we
* distinguish their raw action types.] */
OFPAT_RAW11_SET_VLAN_VID,
/* OF1.1(2), OF1.2+(2) is deprecated (use Set-Field): uint8_t. */
OFPAT_RAW11_SET_VLAN_PCP,
/* OF1.1+(17): ovs_be16.
*
* [The argument is the Ethertype, e.g. ETH_TYPE_VLAN_8021Q, not the VID or
* TCI.] */
OFPAT_RAW11_PUSH_VLAN,
/* OF1.0(3): void. */
OFPAT_RAW10_STRIP_VLAN,
/* OF1.1+(18): void. */
OFPAT_RAW11_POP_VLAN,
/* OF1.0(4), OF1.1(3), OF1.2+(3) is deprecated (use Set-Field): struct
* ofp_action_dl_addr. */
OFPAT_RAW_SET_DL_SRC,
/* OF1.0(5), OF1.1(4), OF1.2+(4) is deprecated (use Set-Field): struct
* ofp_action_dl_addr. */
OFPAT_RAW_SET_DL_DST,
/* OF1.0(6), OF1.1(5), OF1.2+(5) is deprecated (use Set-Field):
* ovs_be32. */
OFPAT_RAW_SET_NW_SRC,
/* OF1.0(7), OF1.1(6), OF1.2+(6) is deprecated (use Set-Field):
* ovs_be32. */
OFPAT_RAW_SET_NW_DST,
/* OF1.0(8), OF1.1(7), OF1.2+(7) is deprecated (use Set-Field): uint8_t. */
OFPAT_RAW_SET_NW_TOS,
/* OF1.1(8), OF1.2+(8) is deprecated (use Set-Field): uint8_t. */
OFPAT_RAW11_SET_NW_ECN,
/* OF1.0(9), OF1.1(9), OF1.2+(9) is deprecated (use Set-Field):
* ovs_be16. */
OFPAT_RAW_SET_TP_SRC,
/* OF1.0(10), OF1.1(10), OF1.2+(10) is deprecated (use Set-Field):
* ovs_be16. */
OFPAT_RAW_SET_TP_DST,
/* OF1.0(11): struct ofp10_action_enqueue. */
OFPAT_RAW10_ENQUEUE,
/* NX1.0(30), OF1.1(13), OF1.2+(13) is deprecated (use Set-Field):
* ovs_be32. */
OFPAT_RAW_SET_MPLS_LABEL,
/* NX1.0(31), OF1.1(14), OF1.2+(14) is deprecated (use Set-Field):
* uint8_t. */
OFPAT_RAW_SET_MPLS_TC,
/* NX1.0(25), OF1.1(15), OF1.2+(15) is deprecated (use Set-Field):
* uint8_t. */
OFPAT_RAW_SET_MPLS_TTL,
/* NX1.0(26), OF1.1+(16): void. */
OFPAT_RAW_DEC_MPLS_TTL,
/* NX1.0(23), OF1.1+(19): ovs_be16.
*
* [The argument is the Ethertype, e.g. ETH_TYPE_MPLS, not the label.] */
OFPAT_RAW_PUSH_MPLS,
/* NX1.0(24), OF1.1+(20): ovs_be16.
*
* [The argument is the Ethertype, e.g. ETH_TYPE_IPV4 if at BoS or
* ETH_TYPE_MPLS otherwise, not the label.] */
OFPAT_RAW_POP_MPLS,
/* NX1.0(4), OF1.1+(21): uint32_t. */
OFPAT_RAW_SET_QUEUE,
/* OF1.1+(22): uint32_t. */
OFPAT_RAW11_GROUP,
/* OF1.1+(23): uint8_t. */
OFPAT_RAW11_SET_NW_TTL,
/* NX1.0(18), OF1.1+(24): void. */
OFPAT_RAW_DEC_NW_TTL,
/* NX1.0+(21): struct nx_action_cnt_ids, ... */
NXAST_RAW_DEC_TTL_CNT_IDS,
/* OF1.2-1.4(25): struct ofp12_action_set_field, ... */
OFPAT_RAW12_SET_FIELD,
/* OF1.5+(25): struct ofp12_action_set_field, ... */
OFPAT_RAW15_SET_FIELD,
/* NX1.0-1.4(7): struct nx_action_reg_load.
*
* [In OpenFlow 1.5, set_field is a superset of reg_load functionality, so
* we drop reg_load.] */
NXAST_RAW_REG_LOAD,
/* NX1.0-1.4(33): struct nx_action_reg_load2, ...
*
* [In OpenFlow 1.5, set_field is a superset of reg_load2 functionality, so
* we drop reg_load2.] */
NXAST_RAW_REG_LOAD2,
/* OF1.5+(28): struct ofp15_action_copy_field, ... */
OFPAT_RAW15_COPY_FIELD,
/* ONF1.3-1.4(3200): struct onf_action_copy_field, ... */
ONFACT_RAW13_COPY_FIELD,
/* NX1.0-1.4(6): struct nx_action_reg_move, ... */
NXAST_RAW_REG_MOVE,
/* ## ------------------------- ## */
/* ## Nicira extension actions. ## */
/* ## ------------------------- ## */
/* Actions similar to standard actions are listed with the standard actions. */
/* NX1.0+(1): uint16_t. */
NXAST_RAW_RESUBMIT,
/* NX1.0+(14): struct nx_action_resubmit. */
NXAST_RAW_RESUBMIT_TABLE,
/* NX1.0+(2): uint32_t. */
NXAST_RAW_SET_TUNNEL,
/* NX1.0+(9): uint64_t. */
NXAST_RAW_SET_TUNNEL64,
/* NX1.0+(5): void. */
NXAST_RAW_POP_QUEUE,
/* NX1.0+(8): struct nx_action_note, ... */
NXAST_RAW_NOTE,
/* NX1.0+(10): struct nx_action_multipath. */
NXAST_RAW_MULTIPATH,
/* NX1.0+(12): struct nx_action_bundle, ... */
NXAST_RAW_BUNDLE,
/* NX1.0+(13): struct nx_action_bundle, ... */
NXAST_RAW_BUNDLE_LOAD,
/* NX1.0+(15): struct nx_action_output_reg. */
NXAST_RAW_OUTPUT_REG,
/* NX1.0+(32): struct nx_action_output_reg2. */
NXAST_RAW_OUTPUT_REG2,
/* NX1.0+(16): struct nx_action_learn, ... */
NXAST_RAW_LEARN,
/* NX1.0+(17): void. */
NXAST_RAW_EXIT,
/* NX1.0+(19): struct nx_action_fin_timeout. */
NXAST_RAW_FIN_TIMEOUT,
/* NX1.0+(20): struct nx_action_controller. */
NXAST_RAW_CONTROLLER,
/* NX1.0+(22): struct nx_action_write_metadata. */
NXAST_RAW_WRITE_METADATA,
/* NX1.0+(27): struct nx_action_stack. */
NXAST_RAW_STACK_PUSH,
/* NX1.0+(28): struct nx_action_stack. */
NXAST_RAW_STACK_POP,
/* NX1.0+(29): struct nx_action_sample. */
NXAST_RAW_SAMPLE,
/* NX1.0+(34): struct nx_action_conjunction. */
NXAST_RAW_CONJUNCTION,
/* ## ------------------ ## */
/* ## Debugging actions. ## */
/* ## ------------------ ## */
/* These are intentionally undocumented, subject to change, and ovs-vswitchd */
/* accepts them only if started with --enable-dummy. */
/* NX1.0+(255): void. */
NXAST_RAW_DEBUG_RECIRC,
};
/* OpenFlow actions are always a multiple of 8 bytes in length. */
#define OFP_ACTION_ALIGN 8
/* Define a few functions for working with instructions. */
#define DEFINE_INST(ENUM, STRUCT, EXTENSIBLE, NAME) \
static inline const struct STRUCT * OVS_UNUSED \
instruction_get_##ENUM(const struct ofp11_instruction *inst)\
{ \
ovs_assert(inst->type == htons(ENUM)); \
return ALIGNED_CAST(struct STRUCT *, inst); \
} \
\
static inline void OVS_UNUSED \
instruction_init_##ENUM(struct STRUCT *s) \
{ \
memset(s, 0, sizeof *s); \
s->type = htons(ENUM); \
s->len = htons(sizeof *s); \
} \
\
static inline struct STRUCT * OVS_UNUSED \
instruction_put_##ENUM(struct ofpbuf *buf) \
{ \
struct STRUCT *s = ofpbuf_put_uninit(buf, sizeof *s); \
instruction_init_##ENUM(s); \
return s; \
}
OVS_INSTRUCTIONS
#undef DEFINE_INST
static void ofpacts_update_instruction_actions(struct ofpbuf *openflow,
size_t ofs);
static void pad_ofpat(struct ofpbuf *openflow, size_t start_ofs);
static enum ofperr ofpacts_verify(const struct ofpact[], size_t ofpacts_len,
uint32_t allowed_ovsinsts,
enum ofpact_type outer_action);
static void ofpact_put_set_field(struct ofpbuf *openflow, enum ofp_version,
enum mf_field_id, uint64_t value);
static enum ofperr ofpact_pull_raw(struct ofpbuf *, enum ofp_version,
enum ofp_raw_action_type *, uint64_t *arg);
static void *ofpact_put_raw(struct ofpbuf *, enum ofp_version,
enum ofp_raw_action_type, uint64_t arg);
static char *OVS_WARN_UNUSED_RESULT ofpacts_parse(
char *str, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols,
bool allow_instructions, enum ofpact_type outer_action);
/* Pull off existing actions or instructions. Used by nesting actions to keep
* ofpacts_parse() oblivious of actions nesting.
*
* Push the actions back on after nested parsing, e.g.:
*
* size_t ofs = ofpacts_pull(ofpacts);
* ...nested parsing...
* ofpbuf_push_uninit(ofpacts, ofs);
*/
static size_t
ofpacts_pull(struct ofpbuf *ofpacts)
{
size_t ofs;
ofpact_pad(ofpacts);
ofs = ofpacts->size;
ofpbuf_pull(ofpacts, ofs);
return ofs;
}
#include "ofp-actions.inc1"
/* Output actions. */
/* Action structure for OFPAT10_OUTPUT, which sends packets out 'port'.
* When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max
* number of bytes to send. A 'max_len' of zero means no bytes of the
* packet should be sent. */
struct ofp10_action_output {
ovs_be16 type; /* OFPAT10_OUTPUT. */
ovs_be16 len; /* Length is 8. */
ovs_be16 port; /* Output port. */
ovs_be16 max_len; /* Max length to send to controller. */
};
OFP_ASSERT(sizeof(struct ofp10_action_output) == 8);
/* Action structure for OFPAT_OUTPUT, which sends packets out 'port'.
* When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max
* number of bytes to send. A 'max_len' of zero means no bytes of the
* packet should be sent.*/
struct ofp11_action_output {
ovs_be16 type; /* OFPAT11_OUTPUT. */
ovs_be16 len; /* Length is 16. */
ovs_be32 port; /* Output port. */
ovs_be16 max_len; /* Max length to send to controller. */
uint8_t pad[6]; /* Pad to 64 bits. */
};
OFP_ASSERT(sizeof(struct ofp11_action_output) == 16);
static enum ofperr
decode_OFPAT_RAW10_OUTPUT(const struct ofp10_action_output *oao,
struct ofpbuf *out)
{
struct ofpact_output *output;
output = ofpact_put_OUTPUT(out);
output->port = u16_to_ofp(ntohs(oao->port));
output->max_len = ntohs(oao->max_len);
return ofpact_check_output_port(output->port, OFPP_MAX);
}
static enum ofperr
decode_OFPAT_RAW11_OUTPUT(const struct ofp11_action_output *oao,
struct ofpbuf *out)
{
struct ofpact_output *output;
enum ofperr error;
output = ofpact_put_OUTPUT(out);
output->max_len = ntohs(oao->max_len);
error = ofputil_port_from_ofp11(oao->port, &output->port);
if (error) {
return error;
}
return ofpact_check_output_port(output->port, OFPP_MAX);
}
static void
encode_OUTPUT(const struct ofpact_output *output,
enum ofp_version ofp_version, struct ofpbuf *out)
{
if (ofp_version == OFP10_VERSION) {
struct ofp10_action_output *oao;
oao = put_OFPAT10_OUTPUT(out);
oao->port = htons(ofp_to_u16(output->port));
oao->max_len = htons(output->max_len);
} else {
struct ofp11_action_output *oao;
oao = put_OFPAT11_OUTPUT(out);
oao->port = ofputil_port_to_ofp11(output->port);
oao->max_len = htons(output->max_len);
}
}
static char * OVS_WARN_UNUSED_RESULT
parse_OUTPUT(const char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
if (strchr(arg, '[')) {
struct ofpact_output_reg *output_reg;
output_reg = ofpact_put_OUTPUT_REG(ofpacts);
output_reg->max_len = UINT16_MAX;
return mf_parse_subfield(&output_reg->src, arg);
} else {
struct ofpact_output *output;
output = ofpact_put_OUTPUT(ofpacts);
if (!ofputil_port_from_string(arg, &output->port)) {
return xasprintf("%s: output to unknown port", arg);
}
output->max_len = output->port == OFPP_CONTROLLER ? UINT16_MAX : 0;
return NULL;
}
}
static void
format_OUTPUT(const struct ofpact_output *a, struct ds *s)
{
if (ofp_to_u16(a->port) < ofp_to_u16(OFPP_MAX)) {
ds_put_format(s, "output:%"PRIu16, a->port);
} else {
ofputil_format_port(a->port, s);
if (a->port == OFPP_CONTROLLER) {
ds_put_format(s, ":%"PRIu16, a->max_len);
}
}
}
/* Group actions. */
static enum ofperr
decode_OFPAT_RAW11_GROUP(uint32_t group_id, struct ofpbuf *out)
{
ofpact_put_GROUP(out)->group_id = group_id;
return 0;
}
static void
encode_GROUP(const struct ofpact_group *group,
enum ofp_version ofp_version, struct ofpbuf *out)
{
if (ofp_version == OFP10_VERSION) {
/* XXX */
} else {
put_OFPAT11_GROUP(out, group->group_id);
}
}
static char * OVS_WARN_UNUSED_RESULT
parse_GROUP(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
return str_to_u32(arg, &ofpact_put_GROUP(ofpacts)->group_id);
}
static void
format_GROUP(const struct ofpact_group *a, struct ds *s)
{
ds_put_format(s, "group:%"PRIu32, a->group_id);
}
/* Action structure for NXAST_CONTROLLER.
*
* This generalizes using OFPAT_OUTPUT to send a packet to OFPP_CONTROLLER. In
* addition to the 'max_len' that OFPAT_OUTPUT supports, it also allows
* specifying:
*
* - 'reason': The reason code to use in the ofp_packet_in or nx_packet_in.
*
* - 'controller_id': The ID of the controller connection to which the
* ofp_packet_in should be sent. The ofp_packet_in or nx_packet_in is
* sent only to controllers that have the specified controller connection
* ID. See "struct nx_controller_id" for more information. */
struct nx_action_controller {
ovs_be16 type; /* OFPAT_VENDOR. */
ovs_be16 len; /* Length is 16. */
ovs_be32 vendor; /* NX_VENDOR_ID. */
ovs_be16 subtype; /* NXAST_CONTROLLER. */
ovs_be16 max_len; /* Maximum length to send to controller. */
ovs_be16 controller_id; /* Controller ID to send packet-in. */
uint8_t reason; /* enum ofp_packet_in_reason (OFPR_*). */
uint8_t zero; /* Must be zero. */
};
OFP_ASSERT(sizeof(struct nx_action_controller) == 16);
static enum ofperr
decode_NXAST_RAW_CONTROLLER(const struct nx_action_controller *nac,
struct ofpbuf *out)
{
struct ofpact_controller *oc;
oc = ofpact_put_CONTROLLER(out);
oc->max_len = ntohs(nac->max_len);
oc->controller_id = ntohs(nac->controller_id);
oc->reason = nac->reason;
return 0;
}
static void
encode_CONTROLLER(const struct ofpact_controller *controller,
enum ofp_version ofp_version OVS_UNUSED,
struct ofpbuf *out)
{
struct nx_action_controller *nac;
nac = put_NXAST_CONTROLLER(out);
nac->max_len = htons(controller->max_len);
nac->controller_id = htons(controller->controller_id);
nac->reason = controller->reason;
}
static char * OVS_WARN_UNUSED_RESULT
parse_CONTROLLER(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
enum ofp_packet_in_reason reason = OFPR_ACTION;
uint16_t controller_id = 0;
uint16_t max_len = UINT16_MAX;
if (!arg[0]) {
/* Use defaults. */
} else if (strspn(arg, "0123456789") == strlen(arg)) {
char *error = str_to_u16(arg, "max_len", &max_len);
if (error) {
return error;
}
} else {
char *name, *value;
while (ofputil_parse_key_value(&arg, &name, &value)) {
if (!strcmp(name, "reason")) {
if (!ofputil_packet_in_reason_from_string(value, &reason)) {
return xasprintf("unknown reason \"%s\"", value);
}
} else if (!strcmp(name, "max_len")) {
char *error = str_to_u16(value, "max_len", &max_len);
if (error) {
return error;
}
} else if (!strcmp(name, "id")) {
char *error = str_to_u16(value, "id", &controller_id);
if (error) {
return error;
}
} else {
return xasprintf("unknown key \"%s\" parsing controller "
"action", name);
}
}
}
if (reason == OFPR_ACTION && controller_id == 0) {
struct ofpact_output *output;
output = ofpact_put_OUTPUT(ofpacts);
output->port = OFPP_CONTROLLER;
output->max_len = max_len;
} else {
struct ofpact_controller *controller;
controller = ofpact_put_CONTROLLER(ofpacts);
controller->max_len = max_len;
controller->reason = reason;
controller->controller_id = controller_id;
}
return NULL;
}
static void
format_CONTROLLER(const struct ofpact_controller *a, struct ds *s)
{
if (a->reason == OFPR_ACTION && a->controller_id == 0) {
ds_put_format(s, "CONTROLLER:%"PRIu16, a->max_len);
} else {
enum ofp_packet_in_reason reason = a->reason;
ds_put_cstr(s, "controller(");
if (reason != OFPR_ACTION) {
char reasonbuf[OFPUTIL_PACKET_IN_REASON_BUFSIZE];
ds_put_format(s, "reason=%s,",
ofputil_packet_in_reason_to_string(
reason, reasonbuf, sizeof reasonbuf));
}
if (a->max_len != UINT16_MAX) {
ds_put_format(s, "max_len=%"PRIu16",", a->max_len);
}
if (a->controller_id != 0) {
ds_put_format(s, "id=%"PRIu16",", a->controller_id);
}
ds_chomp(s, ',');
ds_put_char(s, ')');
}
}
/* Enqueue action. */
struct ofp10_action_enqueue {
ovs_be16 type; /* OFPAT10_ENQUEUE. */
ovs_be16 len; /* Len is 16. */
ovs_be16 port; /* Port that queue belongs. Should
refer to a valid physical port
(i.e. < OFPP_MAX) or OFPP_IN_PORT. */
uint8_t pad[6]; /* Pad for 64-bit alignment. */
ovs_be32 queue_id; /* Where to enqueue the packets. */
};
OFP_ASSERT(sizeof(struct ofp10_action_enqueue) == 16);
static enum ofperr
decode_OFPAT_RAW10_ENQUEUE(const struct ofp10_action_enqueue *oae,
struct ofpbuf *out)
{
struct ofpact_enqueue *enqueue;
enqueue = ofpact_put_ENQUEUE(out);
enqueue->port = u16_to_ofp(ntohs(oae->port));
enqueue->queue = ntohl(oae->queue_id);
if (ofp_to_u16(enqueue->port) >= ofp_to_u16(OFPP_MAX)
&& enqueue->port != OFPP_IN_PORT
&& enqueue->port != OFPP_LOCAL) {
return OFPERR_OFPBAC_BAD_OUT_PORT;
}
return 0;
}
static void
encode_ENQUEUE(const struct ofpact_enqueue *enqueue,
enum ofp_version ofp_version, struct ofpbuf *out)
{
if (ofp_version == OFP10_VERSION) {
struct ofp10_action_enqueue *oae;
oae = put_OFPAT10_ENQUEUE(out);
oae->port = htons(ofp_to_u16(enqueue->port));
oae->queue_id = htonl(enqueue->queue);
} else {
/* XXX */
}
}
static char * OVS_WARN_UNUSED_RESULT
parse_ENQUEUE(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
char *sp = NULL;
char *port = strtok_r(arg, ":q,", &sp);
char *queue = strtok_r(NULL, "", &sp);
struct ofpact_enqueue *enqueue;
if (port == NULL || queue == NULL) {
return xstrdup("\"enqueue\" syntax is \"enqueue:PORT:QUEUE\" or "
"\"enqueue(PORT,QUEUE)\"");
}
enqueue = ofpact_put_ENQUEUE(ofpacts);
if (!ofputil_port_from_string(port, &enqueue->port)) {
return xasprintf("%s: enqueue to unknown port", port);
}
return str_to_u32(queue, &enqueue->queue);
}
static void
format_ENQUEUE(const struct ofpact_enqueue *a, struct ds *s)
{
ds_put_format(s, "enqueue:");
ofputil_format_port(a->port, s);
ds_put_format(s, ":%"PRIu32, a->queue);
}
/* Action structure for NXAST_OUTPUT_REG.
*
* Outputs to the OpenFlow port number written to src[ofs:ofs+nbits].
*
* The format and semantics of 'src' and 'ofs_nbits' are similar to those for
* the NXAST_REG_LOAD action.
*
* The acceptable nxm_header values for 'src' are the same as the acceptable
* nxm_header values for the 'src' field of NXAST_REG_MOVE.
*
* The 'max_len' field indicates the number of bytes to send when the chosen
* port is OFPP_CONTROLLER. Its semantics are equivalent to the 'max_len'
* field of OFPAT_OUTPUT.
*
* The 'zero' field is required to be zeroed for forward compatibility. */
struct nx_action_output_reg {
ovs_be16 type; /* OFPAT_VENDOR. */
ovs_be16 len; /* 24. */
ovs_be32 vendor; /* NX_VENDOR_ID. */
ovs_be16 subtype; /* NXAST_OUTPUT_REG. */
ovs_be16 ofs_nbits; /* (ofs << 6) | (n_bits - 1). */
ovs_be32 src; /* Source. */
ovs_be16 max_len; /* Max length to send to controller. */
uint8_t zero[6]; /* Reserved, must be zero. */
};
OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24);
/* Action structure for NXAST_OUTPUT_REG2.
*
* Like the NXAST_OUTPUT_REG but organized so that there is room for a 64-bit
* experimenter OXM as 'src'.
*/
struct nx_action_output_reg2 {
ovs_be16 type; /* OFPAT_VENDOR. */
ovs_be16 len; /* 24. */
ovs_be32 vendor; /* NX_VENDOR_ID. */
ovs_be16 subtype; /* NXAST_OUTPUT_REG2. */
ovs_be16 ofs_nbits; /* (ofs << 6) | (n_bits - 1). */
ovs_be16 max_len; /* Max length to send to controller. */
/* Followed by:
* - 'src', as an OXM/NXM header (either 4 or 8 bytes).
* - Enough 0-bytes to pad the action out to 24 bytes. */
uint8_t pad[10];
};
OFP_ASSERT(sizeof(struct nx_action_output_reg2) == 24);
static enum ofperr
decode_NXAST_RAW_OUTPUT_REG(const struct nx_action_output_reg *naor,
struct ofpbuf *out)
{
struct ofpact_output_reg *output_reg;
if (!is_all_zeros(naor->zero, sizeof naor->zero)) {
return OFPERR_OFPBAC_BAD_ARGUMENT;
}
output_reg = ofpact_put_OUTPUT_REG(out);
output_reg->ofpact.raw = NXAST_RAW_OUTPUT_REG;
output_reg->src.field = mf_from_nxm_header(ntohl(naor->src));
output_reg->src.ofs = nxm_decode_ofs(naor->ofs_nbits);
output_reg->src.n_bits = nxm_decode_n_bits(naor->ofs_nbits);
output_reg->max_len = ntohs(naor->max_len);
return mf_check_src(&output_reg->src, NULL);
}
static enum ofperr
decode_NXAST_RAW_OUTPUT_REG2(const struct nx_action_output_reg2 *naor,
struct ofpbuf *out)
{
struct ofpact_output_reg *output_reg;
enum ofperr error;
struct ofpbuf b;
output_reg = ofpact_put_OUTPUT_REG(out);
output_reg->ofpact.raw = NXAST_RAW_OUTPUT_REG2;
output_reg->src.ofs = nxm_decode_ofs(naor->ofs_nbits);
output_reg->src.n_bits = nxm_decode_n_bits(naor->ofs_nbits);
output_reg->max_len = ntohs(naor->max_len);
ofpbuf_use_const(&b, naor, ntohs(naor->len));
ofpbuf_pull(&b, OBJECT_OFFSETOF(naor, pad));
error = nx_pull_header(&b, &output_reg->src.field, NULL);
if (error) {
return error;
}
if (!is_all_zeros(b.data, b.size)) {
return OFPERR_NXBRC_MUST_BE_ZERO;
}
return mf_check_src(&output_reg->src, NULL);
}
static void
encode_OUTPUT_REG(const struct ofpact_output_reg *output_reg,
enum ofp_version ofp_version OVS_UNUSED,
struct ofpbuf *out)
{
/* If 'output_reg' came in as an NXAST_RAW_OUTPUT_REG2 action, or if it
* cannot be encoded in the older form, encode it as
* NXAST_RAW_OUTPUT_REG2. */
if (output_reg->ofpact.raw == NXAST_RAW_OUTPUT_REG2
|| !mf_nxm_header(output_reg->src.field->id)) {
struct nx_action_output_reg2 *naor = put_NXAST_OUTPUT_REG2(out);
size_t size = out->size;
naor->ofs_nbits = nxm_encode_ofs_nbits(output_reg->src.ofs,
output_reg->src.n_bits);
naor->max_len = htons(output_reg->max_len);
out->size = size - sizeof naor->pad;
nx_put_header(out, output_reg->src.field->id, 0, false);
out->size = size;
} else {
struct nx_action_output_reg *naor = put_NXAST_OUTPUT_REG(out);
naor->ofs_nbits = nxm_encode_ofs_nbits(output_reg->src.ofs,
output_reg->src.n_bits);
naor->src = htonl(mf_nxm_header(output_reg->src.field->id));
naor->max_len = htons(output_reg->max_len);
}
}
static char * OVS_WARN_UNUSED_RESULT
parse_OUTPUT_REG(const char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
return parse_OUTPUT(arg, ofpacts, usable_protocols);
}
static void
format_OUTPUT_REG(const struct ofpact_output_reg *a, struct ds *s)
{
ds_put_cstr(s, "output:");
mf_format_subfield(&a->src, s);
}
/* Action structure for NXAST_BUNDLE and NXAST_BUNDLE_LOAD.
*
* The bundle actions choose a slave from a supplied list of options.
* NXAST_BUNDLE outputs to its selection. NXAST_BUNDLE_LOAD writes its
* selection to a register.
*
* The list of possible slaves follows the nx_action_bundle structure. The size
* of each slave is governed by its type as indicated by the 'slave_type'
* parameter. The list of slaves should be padded at its end with zeros to make
* the total length of the action a multiple of 8.
*
* Switches infer from the 'slave_type' parameter the size of each slave. All
* implementations must support the NXM_OF_IN_PORT 'slave_type' which indicates
* that the slaves are OpenFlow port numbers with NXM_LENGTH(NXM_OF_IN_PORT) ==
* 2 byte width. Switches should reject actions which indicate unknown or
* unsupported slave types.
*
* Switches use a strategy dictated by the 'algorithm' parameter to choose a
* slave. If the switch does not support the specified 'algorithm' parameter,
* it should reject the action.
*
* Several algorithms take into account liveness when selecting slaves. The
* liveness of a slave is implementation defined (with one exception), but will
* generally take into account things like its carrier status and the results
* of any link monitoring protocols which happen to be running on it. In order
* to give controllers a place-holder value, the OFPP_NONE port is always
* considered live.
*
* Some slave selection strategies require the use of a hash function, in which
* case the 'fields' and 'basis' parameters should be populated. The 'fields'
* parameter (one of NX_HASH_FIELDS_*) designates which parts of the flow to
* hash. Refer to the definition of "enum nx_hash_fields" for details. The
* 'basis' parameter is used as a universal hash parameter. Different values
* of 'basis' yield different hash results.
*
* The 'zero' parameter at the end of the action structure is reserved for
* future use. Switches are required to reject actions which have nonzero
* bytes in the 'zero' field.
*
* NXAST_BUNDLE actions should have 'ofs_nbits' and 'dst' zeroed. Switches
* should reject actions which have nonzero bytes in either of these fields.
*
* NXAST_BUNDLE_LOAD stores the OpenFlow port number of the selected slave in
* dst[ofs:ofs+n_bits]. The format and semantics of 'dst' and 'ofs_nbits' are
* similar to those for the NXAST_REG_LOAD action. */
struct nx_action_bundle {
ovs_be16 type; /* OFPAT_VENDOR. */
ovs_be16 len; /* Length including slaves. */
ovs_be32 vendor; /* NX_VENDOR_ID. */
ovs_be16 subtype; /* NXAST_BUNDLE or NXAST_BUNDLE_LOAD. */
/* Slave choice algorithm to apply to hash value. */
ovs_be16 algorithm; /* One of NX_BD_ALG_*. */
/* What fields to hash and how. */
ovs_be16 fields; /* One of NX_HASH_FIELDS_*. */
ovs_be16 basis; /* Universal hash parameter. */
ovs_be32 slave_type; /* NXM_OF_IN_PORT. */
ovs_be16 n_slaves; /* Number of slaves. */
ovs_be16 ofs_nbits; /* (ofs << 6) | (n_bits - 1). */
ovs_be32 dst; /* Destination. */
uint8_t zero[4]; /* Reserved. Must be zero. */
};
OFP_ASSERT(sizeof(struct nx_action_bundle) == 32);
static enum ofperr
decode_bundle(bool load, const struct nx_action_bundle *nab,
struct ofpbuf *ofpacts)
{
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
struct ofpact_bundle *bundle;
uint32_t slave_type;
size_t slaves_size, i;
enum ofperr error;
bundle = ofpact_put_BUNDLE(ofpacts);
bundle->n_slaves = ntohs(nab->n_slaves);
bundle->basis = ntohs(nab->basis);
bundle->fields = ntohs(nab->fields);
bundle->algorithm = ntohs(nab->algorithm);
slave_type = ntohl(nab->slave_type);
slaves_size = ntohs(nab->len) - sizeof *nab;
error = OFPERR_OFPBAC_BAD_ARGUMENT;
if (!flow_hash_fields_valid(bundle->fields)) {
VLOG_WARN_RL(&rl, "unsupported fields %d", (int) bundle->fields);
} else if (bundle->n_slaves > BUNDLE_MAX_SLAVES) {
VLOG_WARN_RL(&rl, "too many slaves");
} else if (bundle->algorithm != NX_BD_ALG_HRW
&& bundle->algorithm != NX_BD_ALG_ACTIVE_BACKUP) {
VLOG_WARN_RL(&rl, "unsupported algorithm %d", (int) bundle->algorithm);
} else if (slave_type != mf_nxm_header(MFF_IN_PORT)) {
VLOG_WARN_RL(&rl, "unsupported slave type %"PRIu16, slave_type);
} else {
error = 0;
}
if (!is_all_zeros(nab->zero, sizeof nab->zero)) {
VLOG_WARN_RL(&rl, "reserved field is nonzero");
error = OFPERR_OFPBAC_BAD_ARGUMENT;
}
if (load) {
bundle->dst.field = mf_from_nxm_header(ntohl(nab->dst));
bundle->dst.ofs = nxm_decode_ofs(nab->ofs_nbits);
bundle->dst.n_bits = nxm_decode_n_bits(nab->ofs_nbits);
if (bundle->dst.n_bits < 16) {
VLOG_WARN_RL(&rl, "bundle_load action requires at least 16 bit "
"destination.");
error = OFPERR_OFPBAC_BAD_ARGUMENT;
}
} else {
if (nab->ofs_nbits || nab->dst) {
VLOG_WARN_RL(&rl, "bundle action has nonzero reserved fields");
error = OFPERR_OFPBAC_BAD_ARGUMENT;
}
}
if (slaves_size < bundle->n_slaves * sizeof(ovs_be16)) {
VLOG_WARN_RL(&rl, "Nicira action %s only has %"PRIuSIZE" bytes "
"allocated for slaves. %"PRIuSIZE" bytes are required "
"for %"PRIu16" slaves.",
load ? "bundle_load" : "bundle", slaves_size,
bundle->n_slaves * sizeof(ovs_be16), bundle->n_slaves);
error = OFPERR_OFPBAC_BAD_LEN;
}
for (i = 0; i < bundle->n_slaves; i++) {