1 /* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 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 <sys/types.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
26 #include "multipath.h"
28 #include "openflow/nicira-ext.h"
29 #include "openvswitch/dynamic-string.h"
30 #include "openvswitch/meta-flow.h"
31 #include "openvswitch/ofp-actions.h"
32 #include "openvswitch/ofp-errors.h"
33 #include "openvswitch/ofp-util.h"
34 #include "openvswitch/ofpbuf.h"
35 #include "openvswitch/vlog.h"
38 VLOG_DEFINE_THIS_MODULE(bundle
);
41 execute_ab(const struct ofpact_bundle
*bundle
,
42 bool (*slave_enabled
)(ofp_port_t ofp_port
, void *aux
), void *aux
)
46 for (i
= 0; i
< bundle
->n_slaves
; i
++) {
47 ofp_port_t slave
= bundle
->slaves
[i
];
48 if (slave_enabled(slave
, aux
)) {
57 execute_hrw(const struct ofpact_bundle
*bundle
,
58 const struct flow
*flow
, struct flow_wildcards
*wc
,
59 bool (*slave_enabled
)(ofp_port_t ofp_port
, void *aux
), void *aux
)
61 uint32_t flow_hash
, best_hash
;
64 if (bundle
->n_slaves
> 1) {
65 flow_mask_hash_fields(flow
, wc
, bundle
->fields
);
68 flow_hash
= flow_hash_fields(flow
, bundle
->fields
, bundle
->basis
);
72 for (i
= 0; i
< bundle
->n_slaves
; i
++) {
73 if (slave_enabled(bundle
->slaves
[i
], aux
)) {
74 uint32_t hash
= hash_2words(i
, flow_hash
);
76 if (best
< 0 || hash
> best_hash
) {
83 return best
>= 0 ? bundle
->slaves
[best
] : OFPP_NONE
;
86 /* Executes 'bundle' on 'flow'. Sets fields in 'wc' that were used to
87 * calculate the result. Uses 'slave_enabled' to determine if the slave
88 * designated by 'ofp_port' is up. Returns the chosen slave, or
89 * OFPP_NONE if none of the slaves are acceptable. */
91 bundle_execute(const struct ofpact_bundle
*bundle
,
92 const struct flow
*flow
, struct flow_wildcards
*wc
,
93 bool (*slave_enabled
)(ofp_port_t ofp_port
, void *aux
),
96 switch (bundle
->algorithm
) {
98 return execute_hrw(bundle
, flow
, wc
, slave_enabled
, aux
);
100 case NX_BD_ALG_ACTIVE_BACKUP
:
101 return execute_ab(bundle
, slave_enabled
, aux
);
109 bundle_check(const struct ofpact_bundle
*bundle
, ofp_port_t max_ports
,
110 const struct match
*match
)
112 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
115 if (bundle
->dst
.field
) {
116 enum ofperr error
= mf_check_dst(&bundle
->dst
, match
);
122 for (i
= 0; i
< bundle
->n_slaves
; i
++) {
123 ofp_port_t ofp_port
= bundle
->slaves
[i
];
125 if (ofp_port
!= OFPP_NONE
) {
126 enum ofperr error
= ofpact_check_output_port(ofp_port
, max_ports
);
128 VLOG_WARN_RL(&rl
, "invalid slave %"PRIu32
, ofp_port
);
132 /* Controller slaves are unsupported due to the lack of a max_len
133 * argument. This may or may not change in the future. There doesn't
134 * seem to be a real-world use-case for supporting it. */
135 if (ofp_port
== OFPP_CONTROLLER
) {
136 VLOG_WARN_RL(&rl
, "unsupported controller slave");
137 return OFPERR_OFPBAC_BAD_OUT_PORT
;
145 /* Helper for bundle_parse and bundle_parse_load.
147 * Returns NULL if successful, otherwise a malloc()'d string describing the
148 * error. The caller is responsible for freeing the returned string.*/
149 static char * OVS_WARN_UNUSED_RESULT
150 bundle_parse__(const char *s
, const struct ofputil_port_map
*port_map
,
152 const char *fields
, const char *basis
, const char *algorithm
,
153 const char *slave_type
, const char *dst
,
154 const char *slave_delim
, struct ofpbuf
*ofpacts
)
156 struct ofpact_bundle
*bundle
;
159 return xasprintf("%s: not enough arguments to bundle action", s
);
162 if (strcasecmp(slave_delim
, "slaves")) {
163 return xasprintf("%s: missing slave delimiter, expected `slaves' "
164 "got `%s'", s
, slave_delim
);
167 bundle
= ofpact_put_BUNDLE(ofpacts
);
170 ofp_port_t slave_port
;
173 slave
= strtok_r(NULL
, ", []", save_ptr
);
174 if (!slave
|| bundle
->n_slaves
>= BUNDLE_MAX_SLAVES
) {
178 if (!ofputil_port_from_string(slave
, port_map
, &slave_port
)) {
179 return xasprintf("%s: bad port number", slave
);
181 ofpbuf_put(ofpacts
, &slave_port
, sizeof slave_port
);
183 bundle
= ofpacts
->header
;
186 ofpact_finish_BUNDLE(ofpacts
, &bundle
);
187 bundle
->basis
= atoi(basis
);
189 if (!strcasecmp(fields
, "eth_src")) {
190 bundle
->fields
= NX_HASH_FIELDS_ETH_SRC
;
191 } else if (!strcasecmp(fields
, "symmetric_l4")) {
192 bundle
->fields
= NX_HASH_FIELDS_SYMMETRIC_L4
;
193 } else if (!strcasecmp(fields
, "symmetric_l3l4")) {
194 bundle
->fields
= NX_HASH_FIELDS_SYMMETRIC_L3L4
;
195 } else if (!strcasecmp(fields
, "symmetric_l3l4+udp")) {
196 bundle
->fields
= NX_HASH_FIELDS_SYMMETRIC_L3L4_UDP
;
197 } else if (!strcasecmp(fields
, "nw_src")) {
198 bundle
->fields
= NX_HASH_FIELDS_NW_SRC
;
199 } else if (!strcasecmp(fields
, "nw_dst")) {
200 bundle
->fields
= NX_HASH_FIELDS_NW_DST
;
202 return xasprintf("%s: unknown fields `%s'", s
, fields
);
205 if (!strcasecmp(algorithm
, "active_backup")) {
206 bundle
->algorithm
= NX_BD_ALG_ACTIVE_BACKUP
;
207 } else if (!strcasecmp(algorithm
, "hrw")) {
208 bundle
->algorithm
= NX_BD_ALG_HRW
;
210 return xasprintf("%s: unknown algorithm `%s'", s
, algorithm
);
213 if (strcasecmp(slave_type
, "ofport")) {
214 return xasprintf("%s: unknown slave_type `%s'", s
, slave_type
);
218 char *error
= mf_parse_subfield(&bundle
->dst
, dst
);
223 if (!mf_nxm_header(bundle
->dst
.field
->id
)) {
224 return xasprintf("%s: experimenter OXM field '%s' not supported",
232 /* Converts a bundle action string contained in 's' to an nx_action_bundle and
233 * stores it in 'b'. Sets 'b''s l2 pointer to NULL.
235 * Returns NULL if successful, otherwise a malloc()'d string describing the
236 * error. The caller is responsible for freeing the returned string. */
237 char * OVS_WARN_UNUSED_RESULT
238 bundle_parse(const char *s
, const struct ofputil_port_map
*port_map
,
239 struct ofpbuf
*ofpacts
)
241 char *fields
, *basis
, *algorithm
, *slave_type
, *slave_delim
;
242 char *tokstr
, *save_ptr
;
247 fields
= strtok_r(tokstr
, ", ", &save_ptr
);
248 basis
= strtok_r(NULL
, ", ", &save_ptr
);
249 algorithm
= strtok_r(NULL
, ", ", &save_ptr
);
250 slave_type
= strtok_r(NULL
, ", ", &save_ptr
);
251 slave_delim
= strtok_r(NULL
, ": ", &save_ptr
);
253 error
= bundle_parse__(s
, port_map
,
254 &save_ptr
, fields
, basis
, algorithm
, slave_type
,
255 NULL
, slave_delim
, ofpacts
);
261 /* Converts a bundle_load action string contained in 's' to an nx_action_bundle
262 * and stores it in 'b'. Sets 'b''s l2 pointer to NULL.
264 * Returns NULL if successful, otherwise a malloc()'d string describing the
265 * error. The caller is responsible for freeing the returned string.*/
266 char * OVS_WARN_UNUSED_RESULT
267 bundle_parse_load(const char *s
, const struct ofputil_port_map
*port_map
,
268 struct ofpbuf
*ofpacts
)
270 char *fields
, *basis
, *algorithm
, *slave_type
, *dst
, *slave_delim
;
271 char *tokstr
, *save_ptr
;
276 fields
= strtok_r(tokstr
, ", ", &save_ptr
);
277 basis
= strtok_r(NULL
, ", ", &save_ptr
);
278 algorithm
= strtok_r(NULL
, ", ", &save_ptr
);
279 slave_type
= strtok_r(NULL
, ", ", &save_ptr
);
280 dst
= strtok_r(NULL
, ", ", &save_ptr
);
281 slave_delim
= strtok_r(NULL
, ": ", &save_ptr
);
283 error
= bundle_parse__(s
, port_map
,
284 &save_ptr
, fields
, basis
, algorithm
, slave_type
,
285 dst
, slave_delim
, ofpacts
);
292 /* Appends a human-readable representation of 'nab' to 's'. If 'port_map' is
293 * nonnull, uses it to translate port numbers to names in output. */
295 bundle_format(const struct ofpact_bundle
*bundle
,
296 const struct ofputil_port_map
*port_map
, struct ds
*s
)
298 const char *action
, *fields
, *algorithm
;
301 fields
= flow_hash_fields_to_str(bundle
->fields
);
303 switch (bundle
->algorithm
) {
307 case NX_BD_ALG_ACTIVE_BACKUP
:
308 algorithm
= "active_backup";
311 algorithm
= "<unknown>";
314 action
= bundle
->dst
.field
? "bundle_load" : "bundle";
316 ds_put_format(s
, "%s%s(%s%s,%"PRIu16
",%s,%s,", colors
.paren
, action
,
317 colors
.end
, fields
, bundle
->basis
, algorithm
, "ofport");
319 if (bundle
->dst
.field
) {
320 mf_format_subfield(&bundle
->dst
, s
);
324 ds_put_format(s
, "%sslaves:%s", colors
.param
, colors
.end
);
325 for (i
= 0; i
< bundle
->n_slaves
; i
++) {
330 ofputil_format_port(bundle
->slaves
[i
], port_map
, s
);
333 ds_put_format(s
, "%s)%s", colors
.paren
, colors
.end
);