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
,
56 const struct flow
*flow
, struct flow_wildcards
*wc
,
57 bool (*slave_enabled
)(uint16_t ofp_port
, void *aux
), void *aux
)
59 uint32_t flow_hash
, best_hash
;
62 if (bundle
->n_slaves
> 1) {
63 flow_mask_hash_fields(wc
, bundle
->fields
);
66 flow_hash
= flow_hash_fields(flow
, bundle
->fields
, bundle
->basis
);
70 for (i
= 0; i
< bundle
->n_slaves
; i
++) {
71 if (slave_enabled(bundle
->slaves
[i
], aux
)) {
72 uint32_t hash
= hash_2words(i
, flow_hash
);
74 if (best
< 0 || hash
> best_hash
) {
81 return best
>= 0 ? bundle
->slaves
[best
] : OFPP_NONE
;
84 /* Executes 'bundle' on 'flow'. Sets fields in 'wc' that were used to
85 * calculate the result. Uses 'slave_enabled' to determine if the slave
86 * designated by 'ofp_port' is up. Returns the chosen slave, or
87 * OFPP_NONE if none of the slaves are acceptable. */
89 bundle_execute(const struct ofpact_bundle
*bundle
,
90 const struct flow
*flow
, struct flow_wildcards
*wc
,
91 bool (*slave_enabled
)(uint16_t ofp_port
, void *aux
), void *aux
)
93 switch (bundle
->algorithm
) {
95 return execute_hrw(bundle
, flow
, wc
, slave_enabled
, aux
);
97 case NX_BD_ALG_ACTIVE_BACKUP
:
98 return execute_ab(bundle
, slave_enabled
, aux
);
105 /* Checks that 'nab' specifies a bundle action which is supported by this
106 * bundle module. Uses the 'max_ports' parameter to validate each port using
107 * ofputil_check_output_port(). Returns 0 if 'nab' is supported, otherwise an
108 * OFPERR_* error code. */
110 bundle_from_openflow(const struct nx_action_bundle
*nab
,
111 struct ofpbuf
*ofpacts
)
113 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
114 struct ofpact_bundle
*bundle
;
117 size_t slaves_size
, i
;
120 bundle
= ofpact_put_BUNDLE(ofpacts
);
122 subtype
= ntohs(nab
->subtype
);
123 bundle
->n_slaves
= ntohs(nab
->n_slaves
);
124 bundle
->basis
= ntohs(nab
->basis
);
125 bundle
->fields
= ntohs(nab
->fields
);
126 bundle
->algorithm
= ntohs(nab
->algorithm
);
127 slave_type
= ntohl(nab
->slave_type
);
128 slaves_size
= ntohs(nab
->len
) - sizeof *nab
;
130 error
= OFPERR_OFPBAC_BAD_ARGUMENT
;
131 if (!flow_hash_fields_valid(bundle
->fields
)) {
132 VLOG_WARN_RL(&rl
, "unsupported fields %d", (int) bundle
->fields
);
133 } else if (bundle
->n_slaves
> BUNDLE_MAX_SLAVES
) {
134 VLOG_WARN_RL(&rl
, "too may slaves");
135 } else if (bundle
->algorithm
!= NX_BD_ALG_HRW
136 && bundle
->algorithm
!= NX_BD_ALG_ACTIVE_BACKUP
) {
137 VLOG_WARN_RL(&rl
, "unsupported algorithm %d", (int) bundle
->algorithm
);
138 } else if (slave_type
!= NXM_OF_IN_PORT
) {
139 VLOG_WARN_RL(&rl
, "unsupported slave type %"PRIu16
, slave_type
);
144 if (!is_all_zeros(nab
->zero
, sizeof nab
->zero
)) {
145 VLOG_WARN_RL(&rl
, "reserved field is nonzero");
146 error
= OFPERR_OFPBAC_BAD_ARGUMENT
;
149 if (subtype
== NXAST_BUNDLE
&& (nab
->ofs_nbits
|| nab
->dst
)) {
150 VLOG_WARN_RL(&rl
, "bundle action has nonzero reserved fields");
151 error
= OFPERR_OFPBAC_BAD_ARGUMENT
;
154 if (subtype
== NXAST_BUNDLE_LOAD
) {
155 bundle
->dst
.field
= mf_from_nxm_header(ntohl(nab
->dst
));
156 bundle
->dst
.ofs
= nxm_decode_ofs(nab
->ofs_nbits
);
157 bundle
->dst
.n_bits
= nxm_decode_n_bits(nab
->ofs_nbits
);
159 if (bundle
->dst
.n_bits
< 16) {
160 VLOG_WARN_RL(&rl
, "bundle_load action requires at least 16 bit "
162 error
= OFPERR_OFPBAC_BAD_ARGUMENT
;
166 if (slaves_size
< bundle
->n_slaves
* sizeof(ovs_be16
)) {
167 VLOG_WARN_RL(&rl
, "Nicira action %"PRIu16
" only has %zu bytes "
168 "allocated for slaves. %zu bytes are required for "
169 "%"PRIu16
" slaves.", subtype
, slaves_size
,
170 bundle
->n_slaves
* sizeof(ovs_be16
), bundle
->n_slaves
);
171 error
= OFPERR_OFPBAC_BAD_LEN
;
174 for (i
= 0; i
< bundle
->n_slaves
; i
++) {
175 uint16_t ofp_port
= ntohs(((ovs_be16
*)(nab
+ 1))[i
]);
176 ofpbuf_put(ofpacts
, &ofp_port
, sizeof ofp_port
);
179 bundle
= ofpacts
->l2
;
180 ofpact_update_len(ofpacts
, &bundle
->ofpact
);
183 error
= bundle_check(bundle
, OFPP_MAX
, NULL
);
189 bundle_check(const struct ofpact_bundle
*bundle
, int max_ports
,
190 const struct flow
*flow
)
192 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
195 if (bundle
->dst
.field
) {
196 enum ofperr error
= mf_check_dst(&bundle
->dst
, flow
);
202 for (i
= 0; i
< bundle
->n_slaves
; i
++) {
203 uint16_t ofp_port
= bundle
->slaves
[i
];
206 error
= ofputil_check_output_port(ofp_port
, max_ports
);
208 VLOG_WARN_RL(&rl
, "invalid slave %"PRIu16
, ofp_port
);
212 /* Controller slaves are unsupported due to the lack of a max_len
213 * argument. This may or may not change in the future. There doesn't
214 * seem to be a real-world use-case for supporting it. */
215 if (ofp_port
== OFPP_CONTROLLER
) {
216 VLOG_WARN_RL(&rl
, "unsupported controller slave");
217 return OFPERR_OFPBAC_BAD_OUT_PORT
;
225 bundle_to_nxast(const struct ofpact_bundle
*bundle
, struct ofpbuf
*openflow
)
227 int slaves_len
= ROUND_UP(2 * bundle
->n_slaves
, OFP_ACTION_ALIGN
);
228 struct nx_action_bundle
*nab
;
232 nab
= (bundle
->dst
.field
233 ? ofputil_put_NXAST_BUNDLE_LOAD(openflow
)
234 : ofputil_put_NXAST_BUNDLE(openflow
));
235 nab
->len
= htons(ntohs(nab
->len
) + slaves_len
);
236 nab
->algorithm
= htons(bundle
->algorithm
);
237 nab
->fields
= htons(bundle
->fields
);
238 nab
->basis
= htons(bundle
->basis
);
239 nab
->slave_type
= htonl(NXM_OF_IN_PORT
);
240 nab
->n_slaves
= htons(bundle
->n_slaves
);
241 if (bundle
->dst
.field
) {
242 nab
->ofs_nbits
= nxm_encode_ofs_nbits(bundle
->dst
.ofs
,
244 nab
->dst
= htonl(bundle
->dst
.field
->nxm_header
);
247 slaves
= ofpbuf_put_zeros(openflow
, slaves_len
);
248 for (i
= 0; i
< bundle
->n_slaves
; i
++) {
249 slaves
[i
] = htons(bundle
->slaves
[i
]);
253 /* Helper for bundle_parse and bundle_parse_load. */
255 bundle_parse__(const char *s
, char **save_ptr
,
256 const char *fields
, const char *basis
, const char *algorithm
,
257 const char *slave_type
, const char *dst
,
258 const char *slave_delim
, struct ofpbuf
*ofpacts
)
260 struct ofpact_bundle
*bundle
;
263 ovs_fatal(0, "%s: not enough arguments to bundle action", s
);
266 if (strcasecmp(slave_delim
, "slaves")) {
267 ovs_fatal(0, "%s: missing slave delimiter, expected `slaves' got `%s'",
271 bundle
= ofpact_put_BUNDLE(ofpacts
);
277 slave
= strtok_r(NULL
, ", []", save_ptr
);
278 if (!slave
|| bundle
->n_slaves
>= BUNDLE_MAX_SLAVES
) {
282 if (!ofputil_port_from_string(slave
, &slave_port
)) {
283 ovs_fatal(0, "%s: bad port number", slave
);
285 ofpbuf_put(ofpacts
, &slave_port
, sizeof slave_port
);
287 bundle
= ofpacts
->l2
;
290 ofpact_update_len(ofpacts
, &bundle
->ofpact
);
292 bundle
->basis
= atoi(basis
);
294 if (!strcasecmp(fields
, "eth_src")) {
295 bundle
->fields
= NX_HASH_FIELDS_ETH_SRC
;
296 } else if (!strcasecmp(fields
, "symmetric_l4")) {
297 bundle
->fields
= NX_HASH_FIELDS_SYMMETRIC_L4
;
299 ovs_fatal(0, "%s: unknown fields `%s'", s
, fields
);
302 if (!strcasecmp(algorithm
, "active_backup")) {
303 bundle
->algorithm
= NX_BD_ALG_ACTIVE_BACKUP
;
304 } else if (!strcasecmp(algorithm
, "hrw")) {
305 bundle
->algorithm
= NX_BD_ALG_HRW
;
307 ovs_fatal(0, "%s: unknown algorithm `%s'", s
, algorithm
);
310 if (strcasecmp(slave_type
, "ofport")) {
311 ovs_fatal(0, "%s: unknown slave_type `%s'", s
, slave_type
);
315 mf_parse_subfield(&bundle
->dst
, dst
);
319 /* Converts a bundle action string contained in 's' to an nx_action_bundle and
320 * stores it in 'b'. Sets 'b''s l2 pointer to NULL. */
322 bundle_parse(const char *s
, struct ofpbuf
*ofpacts
)
324 char *fields
, *basis
, *algorithm
, *slave_type
, *slave_delim
;
325 char *tokstr
, *save_ptr
;
329 fields
= strtok_r(tokstr
, ", ", &save_ptr
);
330 basis
= strtok_r(NULL
, ", ", &save_ptr
);
331 algorithm
= strtok_r(NULL
, ", ", &save_ptr
);
332 slave_type
= strtok_r(NULL
, ", ", &save_ptr
);
333 slave_delim
= strtok_r(NULL
, ": ", &save_ptr
);
335 bundle_parse__(s
, &save_ptr
, fields
, basis
, algorithm
, slave_type
, NULL
,
336 slave_delim
, ofpacts
);
340 /* Converts a bundle_load action string contained in 's' to an nx_action_bundle
341 * and stores it in 'b'. Sets 'b''s l2 pointer to NULL. */
343 bundle_parse_load(const char *s
, struct ofpbuf
*ofpacts
)
345 char *fields
, *basis
, *algorithm
, *slave_type
, *dst
, *slave_delim
;
346 char *tokstr
, *save_ptr
;
350 fields
= strtok_r(tokstr
, ", ", &save_ptr
);
351 basis
= strtok_r(NULL
, ", ", &save_ptr
);
352 algorithm
= strtok_r(NULL
, ", ", &save_ptr
);
353 slave_type
= strtok_r(NULL
, ", ", &save_ptr
);
354 dst
= strtok_r(NULL
, ", ", &save_ptr
);
355 slave_delim
= strtok_r(NULL
, ": ", &save_ptr
);
357 bundle_parse__(s
, &save_ptr
, fields
, basis
, algorithm
, slave_type
, dst
,
358 slave_delim
, ofpacts
);
363 /* Appends a human-readable representation of 'nab' to 's'. */
365 bundle_format(const struct ofpact_bundle
*bundle
, struct ds
*s
)
367 const char *action
, *fields
, *algorithm
;
370 fields
= flow_hash_fields_to_str(bundle
->fields
);
372 switch (bundle
->algorithm
) {
376 case NX_BD_ALG_ACTIVE_BACKUP
:
377 algorithm
= "active_backup";
380 algorithm
= "<unknown>";
383 action
= bundle
->dst
.field
? "bundle_load" : "bundle";
385 ds_put_format(s
, "%s(%s,%"PRIu16
",%s,%s,", action
, fields
,
386 bundle
->basis
, algorithm
, "ofport");
388 if (bundle
->dst
.field
) {
389 mf_format_subfield(&bundle
->dst
, s
);
393 ds_put_cstr(s
, "slaves:");
394 for (i
= 0; i
< bundle
->n_slaves
; i
++) {
399 ofputil_format_port(bundle
->slaves
[i
], s
);