1 /* Copyright (c) 2011 Nicira Networks.
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"
28 #include "openflow/nicira-ext.h"
31 #define BUNDLE_MAX_SLAVES 2048
33 VLOG_DEFINE_THIS_MODULE(bundle
);
36 execute_ab(const struct nx_action_bundle
*nab
,
37 bool (*slave_enabled
)(uint16_t ofp_port
, void *aux
), void *aux
)
41 for (i
= 0; i
< ntohs(nab
->n_slaves
); i
++) {
42 uint16_t slave
= bundle_get_slave(nab
, i
);
44 if (slave_enabled(slave
, aux
)) {
53 execute_hrw(const struct nx_action_bundle
*nab
, const struct flow
*flow
,
54 bool (*slave_enabled
)(uint16_t ofp_port
, void *aux
), void *aux
)
56 uint32_t flow_hash
, best_hash
;
59 flow_hash
= flow_hash_fields(flow
, ntohs(nab
->fields
), ntohs(nab
->basis
));
63 for (i
= 0; i
< ntohs(nab
->n_slaves
); i
++) {
64 if (slave_enabled(bundle_get_slave(nab
, i
), aux
)) {
65 uint32_t hash
= hash_2words(i
, flow_hash
);
67 if (best
< 0 || hash
> best_hash
) {
74 return best
>= 0 ? bundle_get_slave(nab
, best
) : OFPP_NONE
;
77 /* Executes 'nab' on 'flow'. Uses 'slave_enabled' to determine if the slave
78 * designated by 'ofp_port' is up. Returns the chosen slave, or OFPP_NONE if
79 * none of the slaves are acceptable. */
81 bundle_execute(const struct nx_action_bundle
*nab
, const struct flow
*flow
,
82 bool (*slave_enabled
)(uint16_t ofp_port
, void *aux
), void *aux
)
84 switch (ntohs(nab
->algorithm
)) {
85 case NX_BD_ALG_HRW
: return execute_hrw(nab
, flow
, slave_enabled
, aux
);
86 case NX_BD_ALG_ACTIVE_BACKUP
: return execute_ab(nab
, slave_enabled
, aux
);
87 default: NOT_REACHED();
92 bundle_execute_load(const struct nx_action_bundle
*nab
, struct flow
*flow
,
93 bool (*slave_enabled
)(uint16_t ofp_port
, void *aux
),
96 nxm_reg_load(nab
->dst
, nab
->ofs_nbits
,
97 bundle_execute(nab
, flow
, slave_enabled
, aux
), flow
);
100 /* Checks that 'nab' specifies a bundle action which is supported by this
101 * bundle module. Uses the 'max_ports' parameter to validate each port using
102 * ofputil_check_output_port(). Returns 0 if 'nab' is supported, otherwise an
103 * OpenFlow error code (as returned by ofp_mkerr()). */
105 bundle_check(const struct nx_action_bundle
*nab
, int max_ports
,
106 const struct flow
*flow
)
108 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
109 uint16_t n_slaves
, fields
, algorithm
, subtype
;
111 size_t slaves_size
, i
;
114 subtype
= ntohs(nab
->subtype
);
115 n_slaves
= ntohs(nab
->n_slaves
);
116 fields
= ntohs(nab
->fields
);
117 algorithm
= ntohs(nab
->algorithm
);
118 slave_type
= ntohl(nab
->slave_type
);
119 slaves_size
= ntohs(nab
->len
) - sizeof *nab
;
121 error
= ofp_mkerr(OFPET_BAD_ACTION
, OFPBAC_BAD_ARGUMENT
);
122 if (!flow_hash_fields_valid(fields
)) {
123 VLOG_WARN_RL(&rl
, "unsupported fields %"PRIu16
, fields
);
124 } else if (n_slaves
> BUNDLE_MAX_SLAVES
) {
125 VLOG_WARN_RL(&rl
, "too may slaves");
126 } else if (algorithm
!= NX_BD_ALG_HRW
127 && algorithm
!= NX_BD_ALG_ACTIVE_BACKUP
) {
128 VLOG_WARN_RL(&rl
, "unsupported algorithm %"PRIu16
, algorithm
);
129 } else if (slave_type
!= NXM_OF_IN_PORT
) {
130 VLOG_WARN_RL(&rl
, "unsupported slave type %"PRIu16
, slave_type
);
135 for (i
= 0; i
< sizeof(nab
->zero
); i
++) {
137 VLOG_WARN_RL(&rl
, "reserved field is nonzero");
138 error
= ofp_mkerr(OFPET_BAD_ACTION
, 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
= ofp_mkerr(OFPET_BAD_ACTION
, OFPBAC_BAD_ARGUMENT
);
147 if (subtype
== NXAST_BUNDLE_LOAD
) {
148 int ofs
= nxm_decode_ofs(nab
->ofs_nbits
);
149 int n_bits
= nxm_decode_n_bits(nab
->ofs_nbits
);
152 VLOG_WARN_RL(&rl
, "bundle_load action requires at least 16 bit "
154 error
= ofp_mkerr(OFPET_BAD_ACTION
, OFPBAC_BAD_ARGUMENT
);
156 error
= nxm_dst_check(nab
->dst
, ofs
, n_bits
, flow
) || error
;
160 if (slaves_size
< n_slaves
* sizeof(ovs_be16
)) {
161 VLOG_WARN_RL(&rl
, "Nicira action %"PRIu16
" only has %zu bytes "
162 "allocated for slaves. %zu bytes are required for "
163 "%"PRIu16
" slaves.", subtype
, slaves_size
,
164 n_slaves
* sizeof(ovs_be16
), n_slaves
);
165 error
= ofp_mkerr(OFPET_BAD_ACTION
, OFPBAC_BAD_LEN
);
168 for (i
= 0; i
< n_slaves
; i
++) {
169 uint16_t ofp_port
= bundle_get_slave(nab
, i
);
170 int ofputil_error
= ofputil_check_output_port(ofp_port
, max_ports
);
173 VLOG_WARN_RL(&rl
, "invalid slave %"PRIu16
, ofp_port
);
174 error
= ofputil_error
;
177 /* Controller slaves are unsupported due to the lack of a max_len
178 * argument. This may or may not change in the future. There doesn't
179 * seem to be a real-world use-case for supporting it. */
180 if (ofp_port
== OFPP_CONTROLLER
) {
181 VLOG_WARN_RL(&rl
, "unsupported controller slave");
182 error
= ofp_mkerr(OFPET_BAD_ACTION
, OFPBAC_BAD_OUT_PORT
);
189 /* Helper for bundle_parse and bundle_parse_load. */
191 bundle_parse__(struct ofpbuf
*b
, const char *s
, char **save_ptr
,
192 const char *fields
, const char *basis
, const char *algorithm
,
193 const char *slave_type
, const char *dst
,
194 const char *slave_delim
)
196 struct nx_action_bundle
*nab
;
200 ovs_fatal(0, "%s: not enough arguments to bundle action", s
);
203 if (strcasecmp(slave_delim
, "slaves")) {
204 ovs_fatal(0, "%s: missing slave delimiter, expected `slaves' got `%s'",
208 b
->l2
= ofpbuf_put_zeros(b
, sizeof *nab
);
215 slave
= strtok_r(NULL
, ", ", save_ptr
);
216 if (!slave
|| n_slaves
>= BUNDLE_MAX_SLAVES
) {
220 slave_be
= htons(atoi(slave
));
221 ofpbuf_put(b
, &slave_be
, sizeof slave_be
);
226 /* Slaves array must be multiple of 8 bytes long. */
228 ofpbuf_put_zeros(b
, 8 - (b
->size
% 8));
232 nab
->type
= htons(OFPAT_VENDOR
);
233 nab
->len
= htons(b
->size
- ((char *) b
->l2
- (char *) b
->data
));
234 nab
->vendor
= htonl(NX_VENDOR_ID
);
235 nab
->subtype
= htons(dst
? NXAST_BUNDLE_LOAD
: NXAST_BUNDLE
);
236 nab
->n_slaves
= htons(n_slaves
);
237 nab
->basis
= htons(atoi(basis
));
239 if (!strcasecmp(fields
, "eth_src")) {
240 nab
->fields
= htons(NX_HASH_FIELDS_ETH_SRC
);
241 } else if (!strcasecmp(fields
, "symmetric_l4")) {
242 nab
->fields
= htons(NX_HASH_FIELDS_SYMMETRIC_L4
);
244 ovs_fatal(0, "%s: unknown fields `%s'", s
, fields
);
247 if (!strcasecmp(algorithm
, "active_backup")) {
248 nab
->algorithm
= htons(NX_BD_ALG_ACTIVE_BACKUP
);
249 } else if (!strcasecmp(algorithm
, "hrw")) {
250 nab
->algorithm
= htons(NX_BD_ALG_HRW
);
252 ovs_fatal(0, "%s: unknown algorithm `%s'", s
, algorithm
);
255 if (!strcasecmp(slave_type
, "ofport")) {
256 nab
->slave_type
= htonl(NXM_OF_IN_PORT
);
258 ovs_fatal(0, "%s: unknown slave_type `%s'", s
, slave_type
);
265 nxm_parse_field_bits(dst
, ®
, &ofs
, &n_bits
);
267 nab
->dst
= htonl(reg
);
268 nab
->ofs_nbits
= nxm_encode_ofs_nbits(ofs
, n_bits
);
274 /* Converts a bundle action string contained in 's' to an nx_action_bundle and
275 * stores it in 'b'. Sets 'b''s l2 pointer to NULL. */
277 bundle_parse(struct ofpbuf
*b
, const char *s
)
279 char *fields
, *basis
, *algorithm
, *slave_type
, *slave_delim
;
280 char *tokstr
, *save_ptr
;
284 fields
= strtok_r(tokstr
, ", ", &save_ptr
);
285 basis
= strtok_r(NULL
, ", ", &save_ptr
);
286 algorithm
= strtok_r(NULL
, ", ", &save_ptr
);
287 slave_type
= strtok_r(NULL
, ", ", &save_ptr
);
288 slave_delim
= strtok_r(NULL
, ": ", &save_ptr
);
290 bundle_parse__(b
, s
, &save_ptr
, fields
, basis
, algorithm
, slave_type
, NULL
,
295 /* Converts a bundle_load action string contained in 's' to an nx_action_bundle
296 * and stores it in 'b'. Sets 'b''s l2 pointer to NULL. */
298 bundle_parse_load(struct ofpbuf
*b
, const char *s
)
300 char *fields
, *basis
, *algorithm
, *slave_type
, *dst
, *slave_delim
;
301 char *tokstr
, *save_ptr
;
305 fields
= strtok_r(tokstr
, ", ", &save_ptr
);
306 basis
= strtok_r(NULL
, ", ", &save_ptr
);
307 algorithm
= strtok_r(NULL
, ", ", &save_ptr
);
308 slave_type
= strtok_r(NULL
, ", ", &save_ptr
);
309 dst
= strtok_r(NULL
, ", ", &save_ptr
);
310 slave_delim
= strtok_r(NULL
, ": ", &save_ptr
);
312 bundle_parse__(b
, s
, &save_ptr
, fields
, basis
, algorithm
, slave_type
, dst
,
318 /* Appends a human-readable representation of 'nab' to 's'. */
320 bundle_format(const struct nx_action_bundle
*nab
, struct ds
*s
)
322 const char *action
, *fields
, *algorithm
, *slave_type
;
325 fields
= flow_hash_fields_to_str(ntohs(nab
->fields
));
327 switch (ntohs(nab
->algorithm
)) {
331 case NX_BD_ALG_ACTIVE_BACKUP
:
332 algorithm
= "active_backup";
335 algorithm
= "<unknown>";
338 switch (ntohl(nab
->slave_type
)) {
340 slave_type
= "ofport";
343 slave_type
= "<unknown>";
346 switch (ntohs(nab
->subtype
)) {
350 case NXAST_BUNDLE_LOAD
:
351 action
= "bundle_load";
357 ds_put_format(s
, "%s(%s,%"PRIu16
",%s,%s,", action
, fields
,
358 ntohs(nab
->basis
), algorithm
, slave_type
);
360 if (nab
->subtype
== htons(NXAST_BUNDLE_LOAD
)) {
361 nxm_format_field_bits(s
, ntohl(nab
->dst
),
362 nxm_decode_ofs(nab
->ofs_nbits
),
363 nxm_decode_n_bits(nab
->ofs_nbits
));
367 ds_put_cstr(s
, "slaves:");
368 for (i
= 0; i
< ntohs(nab
->n_slaves
); i
++) {
373 ds_put_format(s
, "%"PRIu16
, bundle_get_slave(nab
, i
));