1 /* Copyright (c) 2011, 2012 Nicira, Inc.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
20 #include <arpa/inet.h>
23 #include "dynamic-string.h"
24 #include "multipath.h"
25 #include "meta-flow.h"
28 #include "ofp-actions.h"
29 #include "ofp-errors.h"
31 #include "openflow/nicira-ext.h"
34 #define BUNDLE_MAX_SLAVES 2048
36 VLOG_DEFINE_THIS_MODULE(bundle
);
39 execute_ab(const struct ofpact_bundle
*bundle
,
40 bool (*slave_enabled
)(uint16_t ofp_port
, void *aux
), void *aux
)
44 for (i
= 0; i
< bundle
->n_slaves
; i
++) {
45 uint16_t slave
= bundle
->slaves
[i
];
46 if (slave_enabled(slave
, aux
)) {
55 execute_hrw(const struct ofpact_bundle
*bundle
, const struct flow
*flow
,
56 bool (*slave_enabled
)(uint16_t ofp_port
, void *aux
), void *aux
)
58 uint32_t flow_hash
, best_hash
;
61 flow_hash
= flow_hash_fields(flow
, bundle
->fields
, bundle
->basis
);
65 for (i
= 0; i
< bundle
->n_slaves
; i
++) {
66 if (slave_enabled(bundle
->slaves
[i
], aux
)) {
67 uint32_t hash
= hash_2words(i
, flow_hash
);
69 if (best
< 0 || hash
> best_hash
) {
76 return best
>= 0 ? bundle
->slaves
[best
] : OFPP_NONE
;
79 /* Executes 'bundle' on 'flow'. Uses 'slave_enabled' to determine if the slave
80 * designated by 'ofp_port' is up. Returns the chosen slave, or OFPP_NONE if
81 * none of the slaves are acceptable. */
83 bundle_execute(const struct ofpact_bundle
*bundle
, const struct flow
*flow
,
84 bool (*slave_enabled
)(uint16_t ofp_port
, void *aux
), void *aux
)
86 switch (bundle
->algorithm
) {
88 return execute_hrw(bundle
, flow
, slave_enabled
, aux
);
90 case NX_BD_ALG_ACTIVE_BACKUP
:
91 return execute_ab(bundle
, slave_enabled
, aux
);
98 /* Checks that 'nab' specifies a bundle action which is supported by this
99 * bundle module. Uses the 'max_ports' parameter to validate each port using
100 * ofputil_check_output_port(). Returns 0 if 'nab' is supported, otherwise an
101 * OFPERR_* error code. */
103 bundle_from_openflow(const struct nx_action_bundle
*nab
,
104 struct ofpbuf
*ofpacts
)
106 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
107 struct ofpact_bundle
*bundle
;
110 size_t slaves_size
, i
;
113 bundle
= ofpact_put_BUNDLE(ofpacts
);
115 subtype
= ntohs(nab
->subtype
);
116 bundle
->n_slaves
= ntohs(nab
->n_slaves
);
117 bundle
->basis
= ntohs(nab
->basis
);
118 bundle
->fields
= ntohs(nab
->fields
);
119 bundle
->algorithm
= ntohs(nab
->algorithm
);
120 slave_type
= ntohl(nab
->slave_type
);
121 slaves_size
= ntohs(nab
->len
) - sizeof *nab
;
123 error
= OFPERR_OFPBAC_BAD_ARGUMENT
;
124 if (!flow_hash_fields_valid(bundle
->fields
)) {
125 VLOG_WARN_RL(&rl
, "unsupported fields %d", (int) bundle
->fields
);
126 } else if (bundle
->n_slaves
> BUNDLE_MAX_SLAVES
) {
127 VLOG_WARN_RL(&rl
, "too may slaves");
128 } else if (bundle
->algorithm
!= NX_BD_ALG_HRW
129 && bundle
->algorithm
!= NX_BD_ALG_ACTIVE_BACKUP
) {
130 VLOG_WARN_RL(&rl
, "unsupported algorithm %d", (int) bundle
->algorithm
);
131 } else if (slave_type
!= NXM_OF_IN_PORT
) {
132 VLOG_WARN_RL(&rl
, "unsupported slave type %"PRIu16
, slave_type
);
137 if (!is_all_zeros(nab
->zero
, sizeof nab
->zero
)) {
138 VLOG_WARN_RL(&rl
, "reserved field is nonzero");
139 error
= OFPERR_OFPBAC_BAD_ARGUMENT
;
142 if (subtype
== NXAST_BUNDLE
&& (nab
->ofs_nbits
|| nab
->dst
)) {
143 VLOG_WARN_RL(&rl
, "bundle action has nonzero reserved fields");
144 error
= OFPERR_OFPBAC_BAD_ARGUMENT
;
147 if (subtype
== NXAST_BUNDLE_LOAD
) {
148 bundle
->dst
.field
= mf_from_nxm_header(ntohl(nab
->dst
));
149 bundle
->dst
.ofs
= nxm_decode_ofs(nab
->ofs_nbits
);
150 bundle
->dst
.n_bits
= nxm_decode_n_bits(nab
->ofs_nbits
);
152 if (bundle
->dst
.n_bits
< 16) {
153 VLOG_WARN_RL(&rl
, "bundle_load action requires at least 16 bit "
155 error
= OFPERR_OFPBAC_BAD_ARGUMENT
;
159 if (slaves_size
< bundle
->n_slaves
* sizeof(ovs_be16
)) {
160 VLOG_WARN_RL(&rl
, "Nicira action %"PRIu16
" only has %zu bytes "
161 "allocated for slaves. %zu bytes are required for "
162 "%"PRIu16
" slaves.", subtype
, slaves_size
,
163 bundle
->n_slaves
* sizeof(ovs_be16
), bundle
->n_slaves
);
164 error
= OFPERR_OFPBAC_BAD_LEN
;
167 for (i
= 0; i
< bundle
->n_slaves
; i
++) {
168 uint16_t ofp_port
= ntohs(((ovs_be16
*)(nab
+ 1))[i
]);
169 ofpbuf_put(ofpacts
, &ofp_port
, sizeof ofp_port
);
172 bundle
= ofpacts
->l2
;
173 ofpact_update_len(ofpacts
, &bundle
->ofpact
);
176 error
= bundle_check(bundle
, OFPP_MAX
, NULL
);
182 bundle_check(const struct ofpact_bundle
*bundle
, int max_ports
,
183 const struct flow
*flow
)
185 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
188 if (bundle
->dst
.field
) {
189 enum ofperr error
= mf_check_dst(&bundle
->dst
, flow
);
195 for (i
= 0; i
< bundle
->n_slaves
; i
++) {
196 uint16_t ofp_port
= bundle
->slaves
[i
];
199 error
= ofputil_check_output_port(ofp_port
, max_ports
);
201 VLOG_WARN_RL(&rl
, "invalid slave %"PRIu16
, ofp_port
);
205 /* Controller slaves are unsupported due to the lack of a max_len
206 * argument. This may or may not change in the future. There doesn't
207 * seem to be a real-world use-case for supporting it. */
208 if (ofp_port
== OFPP_CONTROLLER
) {
209 VLOG_WARN_RL(&rl
, "unsupported controller slave");
210 return OFPERR_OFPBAC_BAD_OUT_PORT
;
218 bundle_to_nxast(const struct ofpact_bundle
*bundle
, struct ofpbuf
*openflow
)
220 int slaves_len
= ROUND_UP(2 * bundle
->n_slaves
, OFP_ACTION_ALIGN
);
221 struct nx_action_bundle
*nab
;
225 nab
= (bundle
->dst
.field
226 ? ofputil_put_NXAST_BUNDLE_LOAD(openflow
)
227 : ofputil_put_NXAST_BUNDLE(openflow
));
228 nab
->len
= htons(ntohs(nab
->len
) + slaves_len
);
229 nab
->algorithm
= htons(bundle
->algorithm
);
230 nab
->fields
= htons(bundle
->fields
);
231 nab
->basis
= htons(bundle
->basis
);
232 nab
->slave_type
= htonl(NXM_OF_IN_PORT
);
233 nab
->n_slaves
= htons(bundle
->n_slaves
);
234 if (bundle
->dst
.field
) {
235 nab
->ofs_nbits
= nxm_encode_ofs_nbits(bundle
->dst
.ofs
,
237 nab
->dst
= htonl(bundle
->dst
.field
->nxm_header
);
240 slaves
= ofpbuf_put_zeros(openflow
, slaves_len
);
241 for (i
= 0; i
< bundle
->n_slaves
; i
++) {
242 slaves
[i
] = htons(bundle
->slaves
[i
]);
246 /* Helper for bundle_parse and bundle_parse_load. */
248 bundle_parse__(const char *s
, char **save_ptr
,
249 const char *fields
, const char *basis
, const char *algorithm
,
250 const char *slave_type
, const char *dst
,
251 const char *slave_delim
, struct ofpbuf
*ofpacts
)
253 struct ofpact_bundle
*bundle
;
256 ovs_fatal(0, "%s: not enough arguments to bundle action", s
);
259 if (strcasecmp(slave_delim
, "slaves")) {
260 ovs_fatal(0, "%s: missing slave delimiter, expected `slaves' got `%s'",
264 bundle
= ofpact_put_BUNDLE(ofpacts
);
270 slave
= strtok_r(NULL
, ", []", save_ptr
);
271 if (!slave
|| bundle
->n_slaves
>= BUNDLE_MAX_SLAVES
) {
275 if (!ofputil_port_from_string(slave
, &slave_port
)) {
276 ovs_fatal(0, "%s: bad port number", slave
);
278 ofpbuf_put(ofpacts
, &slave_port
, sizeof slave_port
);
280 bundle
= ofpacts
->l2
;
283 ofpact_update_len(ofpacts
, &bundle
->ofpact
);
285 bundle
->basis
= atoi(basis
);
287 if (!strcasecmp(fields
, "eth_src")) {
288 bundle
->fields
= NX_HASH_FIELDS_ETH_SRC
;
289 } else if (!strcasecmp(fields
, "symmetric_l4")) {
290 bundle
->fields
= NX_HASH_FIELDS_SYMMETRIC_L4
;
292 ovs_fatal(0, "%s: unknown fields `%s'", s
, fields
);
295 if (!strcasecmp(algorithm
, "active_backup")) {
296 bundle
->algorithm
= NX_BD_ALG_ACTIVE_BACKUP
;
297 } else if (!strcasecmp(algorithm
, "hrw")) {
298 bundle
->algorithm
= NX_BD_ALG_HRW
;
300 ovs_fatal(0, "%s: unknown algorithm `%s'", s
, algorithm
);
303 if (strcasecmp(slave_type
, "ofport")) {
304 ovs_fatal(0, "%s: unknown slave_type `%s'", s
, slave_type
);
308 mf_parse_subfield(&bundle
->dst
, dst
);
312 /* Converts a bundle action string contained in 's' to an nx_action_bundle and
313 * stores it in 'b'. Sets 'b''s l2 pointer to NULL. */
315 bundle_parse(const char *s
, struct ofpbuf
*ofpacts
)
317 char *fields
, *basis
, *algorithm
, *slave_type
, *slave_delim
;
318 char *tokstr
, *save_ptr
;
322 fields
= strtok_r(tokstr
, ", ", &save_ptr
);
323 basis
= strtok_r(NULL
, ", ", &save_ptr
);
324 algorithm
= strtok_r(NULL
, ", ", &save_ptr
);
325 slave_type
= strtok_r(NULL
, ", ", &save_ptr
);
326 slave_delim
= strtok_r(NULL
, ": ", &save_ptr
);
328 bundle_parse__(s
, &save_ptr
, fields
, basis
, algorithm
, slave_type
, NULL
,
329 slave_delim
, ofpacts
);
333 /* Converts a bundle_load action string contained in 's' to an nx_action_bundle
334 * and stores it in 'b'. Sets 'b''s l2 pointer to NULL. */
336 bundle_parse_load(const char *s
, struct ofpbuf
*ofpacts
)
338 char *fields
, *basis
, *algorithm
, *slave_type
, *dst
, *slave_delim
;
339 char *tokstr
, *save_ptr
;
343 fields
= strtok_r(tokstr
, ", ", &save_ptr
);
344 basis
= strtok_r(NULL
, ", ", &save_ptr
);
345 algorithm
= strtok_r(NULL
, ", ", &save_ptr
);
346 slave_type
= strtok_r(NULL
, ", ", &save_ptr
);
347 dst
= strtok_r(NULL
, ", ", &save_ptr
);
348 slave_delim
= strtok_r(NULL
, ": ", &save_ptr
);
350 bundle_parse__(s
, &save_ptr
, fields
, basis
, algorithm
, slave_type
, dst
,
351 slave_delim
, ofpacts
);
356 /* Appends a human-readable representation of 'nab' to 's'. */
358 bundle_format(const struct ofpact_bundle
*bundle
, struct ds
*s
)
360 const char *action
, *fields
, *algorithm
;
363 fields
= flow_hash_fields_to_str(bundle
->fields
);
365 switch (bundle
->algorithm
) {
369 case NX_BD_ALG_ACTIVE_BACKUP
:
370 algorithm
= "active_backup";
373 algorithm
= "<unknown>";
376 action
= bundle
->dst
.field
? "bundle_load" : "bundle";
378 ds_put_format(s
, "%s(%s,%"PRIu16
",%s,%s,", action
, fields
,
379 bundle
->basis
, algorithm
, "ofport");
381 if (bundle
->dst
.field
) {
382 mf_format_subfield(&bundle
->dst
, s
);
386 ds_put_cstr(s
, "slaves:");
387 for (i
= 0; i
< bundle
->n_slaves
; i
++) {
392 ofputil_format_port(bundle
->slaves
[i
], s
);