X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fbundle.c;h=a2059740c3001e0b8622cb98087fe40d04c6b722;hb=37344ffa58cdc6c057ef06c6822528c8fe08bb93;hp=e6b1c252e653386810ab309cc25ba589081fb94f;hpb=481db4883344161efab4bd5e7580e21411e62c9f;p=openvswitch diff --git a/lib/bundle.c b/lib/bundle.c index e6b1c252..a2059740 100644 --- a/lib/bundle.c +++ b/lib/bundle.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011 Nicira Networks. +/* Copyright (c) 2011, 2012 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,8 +22,10 @@ #include "dynamic-string.h" #include "multipath.h" +#include "meta-flow.h" #include "nx-match.h" #include "ofpbuf.h" +#include "ofp-errors.h" #include "ofp-util.h" #include "openflow/nicira-ext.h" #include "vlog.h" @@ -32,18 +34,30 @@ VLOG_DEFINE_THIS_MODULE(bundle); -/* Executes 'nab' on 'flow'. Uses 'slave_enabled' to determine if the slave - * designated by 'ofp_port' is up. Returns the chosen slave, or OFPP_NONE if - * none of the slaves are acceptable. */ -uint16_t -bundle_execute(const struct nx_action_bundle *nab, const struct flow *flow, - bool (*slave_enabled)(uint16_t ofp_port, void *aux), void *aux) +static uint16_t +execute_ab(const struct nx_action_bundle *nab, + bool (*slave_enabled)(uint16_t ofp_port, void *aux), void *aux) +{ + size_t i; + + for (i = 0; i < ntohs(nab->n_slaves); i++) { + uint16_t slave = bundle_get_slave(nab, i); + + if (slave_enabled(slave, aux)) { + return slave; + } + } + + return OFPP_NONE; +} + +static uint16_t +execute_hrw(const struct nx_action_bundle *nab, const struct flow *flow, + bool (*slave_enabled)(uint16_t ofp_port, void *aux), void *aux) { uint32_t flow_hash, best_hash; int best, i; - assert(nab->algorithm == htons(NX_BD_ALG_HRW)); - flow_hash = flow_hash_fields(flow, ntohs(nab->fields), ntohs(nab->basis)); best = -1; best_hash = 0; @@ -62,18 +76,45 @@ bundle_execute(const struct nx_action_bundle *nab, const struct flow *flow, return best >= 0 ? bundle_get_slave(nab, best) : OFPP_NONE; } +/* Executes 'nab' on 'flow'. Uses 'slave_enabled' to determine if the slave + * designated by 'ofp_port' is up. Returns the chosen slave, or OFPP_NONE if + * none of the slaves are acceptable. */ +uint16_t +bundle_execute(const struct nx_action_bundle *nab, const struct flow *flow, + bool (*slave_enabled)(uint16_t ofp_port, void *aux), void *aux) +{ + switch (ntohs(nab->algorithm)) { + case NX_BD_ALG_HRW: return execute_hrw(nab, flow, slave_enabled, aux); + case NX_BD_ALG_ACTIVE_BACKUP: return execute_ab(nab, slave_enabled, aux); + default: NOT_REACHED(); + } +} + +void +bundle_execute_load(const struct nx_action_bundle *nab, struct flow *flow, + bool (*slave_enabled)(uint16_t ofp_port, void *aux), + void *aux) +{ + struct mf_subfield dst; + + nxm_decode(&dst, nab->dst, nab->ofs_nbits); + mf_set_subfield_value(&dst, bundle_execute(nab, flow, slave_enabled, aux), + flow); +} + /* Checks that 'nab' specifies a bundle action which is supported by this * bundle module. Uses the 'max_ports' parameter to validate each port using * ofputil_check_output_port(). Returns 0 if 'nab' is supported, otherwise an - * OpenFlow error code (as returned by ofp_mkerr()). */ -int -bundle_check(const struct nx_action_bundle *nab, int max_ports) + * OFPERR_* error code. */ +enum ofperr +bundle_check(const struct nx_action_bundle *nab, int max_ports, + const struct flow *flow) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); uint16_t n_slaves, fields, algorithm, subtype; uint32_t slave_type; size_t slaves_size, i; - int error; + enum ofperr error; subtype = ntohs(nab->subtype); n_slaves = ntohs(nab->n_slaves); @@ -82,12 +123,13 @@ bundle_check(const struct nx_action_bundle *nab, int max_ports) slave_type = ntohl(nab->slave_type); slaves_size = ntohs(nab->len) - sizeof *nab; - error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); + error = OFPERR_OFPBAC_BAD_ARGUMENT; if (!flow_hash_fields_valid(fields)) { VLOG_WARN_RL(&rl, "unsupported fields %"PRIu16, fields); } else if (n_slaves > BUNDLE_MAX_SLAVES) { VLOG_WARN_RL(&rl, "too may slaves"); - } else if (algorithm != NX_BD_ALG_HRW) { + } else if (algorithm != NX_BD_ALG_HRW + && algorithm != NX_BD_ALG_ACTIVE_BACKUP) { VLOG_WARN_RL(&rl, "unsupported algorithm %"PRIu16, algorithm); } else if (slave_type != NXM_OF_IN_PORT) { VLOG_WARN_RL(&rl, "unsupported slave type %"PRIu16, slave_type); @@ -98,7 +140,25 @@ bundle_check(const struct nx_action_bundle *nab, int max_ports) for (i = 0; i < sizeof(nab->zero); i++) { if (nab->zero[i]) { VLOG_WARN_RL(&rl, "reserved field is nonzero"); - error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); + error = OFPERR_OFPBAC_BAD_ARGUMENT; + } + } + + if (subtype == NXAST_BUNDLE && (nab->ofs_nbits || nab->dst)) { + VLOG_WARN_RL(&rl, "bundle action has nonzero reserved fields"); + error = OFPERR_OFPBAC_BAD_ARGUMENT; + } + + if (subtype == NXAST_BUNDLE_LOAD) { + struct mf_subfield dst; + + nxm_decode(&dst, nab->dst, nab->ofs_nbits); + if (dst.n_bits < 16) { + VLOG_WARN_RL(&rl, "bundle_load action requires at least 16 bit " + "destination."); + error = OFPERR_OFPBAC_BAD_ARGUMENT; + } else if (!error) { + error = mf_check_dst(&dst, flow); } } @@ -107,13 +167,14 @@ bundle_check(const struct nx_action_bundle *nab, int max_ports) "allocated for slaves. %zu bytes are required for " "%"PRIu16" slaves.", subtype, slaves_size, n_slaves * sizeof(ovs_be16), n_slaves); - error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); + error = OFPERR_OFPBAC_BAD_LEN; } for (i = 0; i < n_slaves; i++) { uint16_t ofp_port = bundle_get_slave(nab, i); - int ofputil_error = ofputil_check_output_port(ofp_port, max_ports); + enum ofperr ofputil_error; + ofputil_error = ofputil_check_output_port(ofp_port, max_ports); if (ofputil_error) { VLOG_WARN_RL(&rl, "invalid slave %"PRIu16, ofp_port); error = ofputil_error; @@ -124,31 +185,24 @@ bundle_check(const struct nx_action_bundle *nab, int max_ports) * seem to be a real-world use-case for supporting it. */ if (ofp_port == OFPP_CONTROLLER) { VLOG_WARN_RL(&rl, "unsupported controller slave"); - error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT); + error = OFPERR_OFPBAC_BAD_OUT_PORT; } } return error; } -/* Converts a bundle action string contained in 's' to an nx_action_bundle and - * stores it in 'b'. Sets 'b''s l2 pointer to NULL. */ -void -bundle_parse(struct ofpbuf *b, const char *s) +/* Helper for bundle_parse and bundle_parse_load. */ +static void +bundle_parse__(struct ofpbuf *b, const char *s, char **save_ptr, + const char *fields, const char *basis, const char *algorithm, + const char *slave_type, const char *dst_s, + const char *slave_delim) { - char *fields, *basis, *algorithm, *slave_type, *slave_delim; + enum ofputil_action_code code; struct nx_action_bundle *nab; - char *tokstr, *save_ptr; uint16_t n_slaves; - save_ptr = NULL; - tokstr = xstrdup(s); - fields = strtok_r(tokstr, ", ", &save_ptr); - basis = strtok_r(NULL, ", ", &save_ptr); - algorithm = strtok_r(NULL, ", ", &save_ptr); - slave_type = strtok_r(NULL, ", ", &save_ptr); - slave_delim = strtok_r(NULL, ": ", &save_ptr); - if (!slave_delim) { ovs_fatal(0, "%s: not enough arguments to bundle action", s); } @@ -158,14 +212,15 @@ bundle_parse(struct ofpbuf *b, const char *s) s, slave_delim); } - b->l2 = ofpbuf_put_zeros(b, sizeof *nab); + code = dst_s ? OFPUTIL_NXAST_BUNDLE_LOAD : OFPUTIL_NXAST_BUNDLE; + b->l2 = ofputil_put_action(code, b); n_slaves = 0; for (;;) { ovs_be16 slave_be; char *slave; - slave = strtok_r(NULL, ", ", &save_ptr); + slave = strtok_r(NULL, ", [", save_ptr); if (!slave || n_slaves >= BUNDLE_MAX_SLAVES) { break; } @@ -182,10 +237,7 @@ bundle_parse(struct ofpbuf *b, const char *s) } nab = b->l2; - nab->type = htons(OFPAT_VENDOR); nab->len = htons(b->size - ((char *) b->l2 - (char *) b->data)); - nab->vendor = htonl(NX_VENDOR_ID); - nab->subtype = htons(NXAST_BUNDLE); nab->n_slaves = htons(n_slaves); nab->basis = htons(atoi(basis)); @@ -211,7 +263,58 @@ bundle_parse(struct ofpbuf *b, const char *s) ovs_fatal(0, "%s: unknown slave_type `%s'", s, slave_type); } + if (dst_s) { + struct mf_subfield dst; + + mf_parse_subfield(&dst, dst_s); + nab->dst = htonl(dst.field->nxm_header); + nab->ofs_nbits = nxm_encode_ofs_nbits(dst.ofs, dst.n_bits); + } + b->l2 = NULL; +} + +/* Converts a bundle action string contained in 's' to an nx_action_bundle and + * stores it in 'b'. Sets 'b''s l2 pointer to NULL. */ +void +bundle_parse(struct ofpbuf *b, const char *s) +{ + char *fields, *basis, *algorithm, *slave_type, *slave_delim; + char *tokstr, *save_ptr; + + save_ptr = NULL; + tokstr = xstrdup(s); + fields = strtok_r(tokstr, ", ", &save_ptr); + basis = strtok_r(NULL, ", ", &save_ptr); + algorithm = strtok_r(NULL, ", ", &save_ptr); + slave_type = strtok_r(NULL, ", ", &save_ptr); + slave_delim = strtok_r(NULL, ": ", &save_ptr); + + bundle_parse__(b, s, &save_ptr, fields, basis, algorithm, slave_type, NULL, + slave_delim); + free(tokstr); +} + +/* Converts a bundle_load action string contained in 's' to an nx_action_bundle + * and stores it in 'b'. Sets 'b''s l2 pointer to NULL. */ +void +bundle_parse_load(struct ofpbuf *b, const char *s) +{ + char *fields, *basis, *algorithm, *slave_type, *dst, *slave_delim; + char *tokstr, *save_ptr; + + save_ptr = NULL; + tokstr = xstrdup(s); + fields = strtok_r(tokstr, ", ", &save_ptr); + basis = strtok_r(NULL, ", ", &save_ptr); + algorithm = strtok_r(NULL, ", ", &save_ptr); + slave_type = strtok_r(NULL, ", ", &save_ptr); + dst = strtok_r(NULL, ", ", &save_ptr); + slave_delim = strtok_r(NULL, ": ", &save_ptr); + + bundle_parse__(b, s, &save_ptr, fields, basis, algorithm, slave_type, dst, + slave_delim); + free(tokstr); } @@ -219,7 +322,7 @@ bundle_parse(struct ofpbuf *b, const char *s) void bundle_format(const struct nx_action_bundle *nab, struct ds *s) { - const char *fields, *algorithm, *slave_type; + const char *action, *fields, *algorithm, *slave_type; size_t i; fields = flow_hash_fields_to_str(ntohs(nab->fields)); @@ -243,9 +346,29 @@ bundle_format(const struct nx_action_bundle *nab, struct ds *s) slave_type = ""; } - ds_put_format(s, "bundle(%s,%"PRIu16",%s,%s,slaves:", fields, + switch (ntohs(nab->subtype)) { + case NXAST_BUNDLE: + action = "bundle"; + break; + case NXAST_BUNDLE_LOAD: + action = "bundle_load"; + break; + default: + NOT_REACHED(); + } + + ds_put_format(s, "%s(%s,%"PRIu16",%s,%s,", action, fields, ntohs(nab->basis), algorithm, slave_type); + if (nab->subtype == htons(NXAST_BUNDLE_LOAD)) { + struct mf_subfield dst; + + nxm_decode(&dst, nab->dst, nab->ofs_nbits); + mf_format_subfield(&dst, s); + ds_put_cstr(s, ","); + } + + ds_put_cstr(s, "slaves:"); for (i = 0; i < ntohs(nab->n_slaves); i++) { if (i) { ds_put_cstr(s, ",");