示例#1
0
文件: learn.c 项目: yamt/openvswitch
static void
get_subfield(int n_bits, const void **p, struct mf_subfield *sf)
{
    sf->field = mf_from_nxm_header(ntohl(get_be32(p)));
    sf->ofs = ntohs(get_be16(p));
    sf->n_bits = n_bits;
}
示例#2
0
/* Converts 'nam' into 'mp'.  Returns 0 if successful, otherwise an
 * OFPERR_*. */
enum ofperr
multipath_from_openflow(const struct nx_action_multipath *nam,
                        struct ofpact_multipath *mp)
{
    uint32_t n_links = ntohs(nam->max_link) + 1;
    size_t min_n_bits = log_2_ceil(n_links);

    ofpact_init_MULTIPATH(mp);
    mp->fields = ntohs(nam->fields);
    mp->basis = ntohs(nam->basis);
    mp->algorithm = ntohs(nam->algorithm);
    mp->max_link = ntohs(nam->max_link);
    mp->arg = ntohl(nam->arg);
    mp->dst.field = mf_from_nxm_header(ntohl(nam->dst));
    mp->dst.ofs = nxm_decode_ofs(nam->ofs_nbits);
    mp->dst.n_bits = nxm_decode_n_bits(nam->ofs_nbits);

    if (!flow_hash_fields_valid(mp->fields)) {
        VLOG_WARN_RL(&rl, "unsupported fields %d", (int) mp->fields);
        return OFPERR_OFPBAC_BAD_ARGUMENT;
    } else if (mp->algorithm != NX_MP_ALG_MODULO_N
               && mp->algorithm != NX_MP_ALG_HASH_THRESHOLD
               && mp->algorithm != NX_MP_ALG_HRW
               && mp->algorithm != NX_MP_ALG_ITER_HASH) {
        VLOG_WARN_RL(&rl, "unsupported algorithm %d", (int) mp->algorithm);
        return OFPERR_OFPBAC_BAD_ARGUMENT;
    } else if (mp->dst.n_bits < min_n_bits) {
        VLOG_WARN_RL(&rl, "multipath action requires at least %zu bits for "
                     "%"PRIu32" links", min_n_bits, n_links);
        return OFPERR_OFPBAC_BAD_ARGUMENT;
    }

    return multipath_check(mp, NULL);
}
示例#3
0
static enum ofperr
nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict,
            struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask)
{
    uint32_t header;

    ovs_assert((cookie != NULL) == (cookie_mask != NULL));

    match_init_catchall(match);
    if (cookie) {
        *cookie = *cookie_mask = htonll(0);
    }
    if (!match_len) {
        return 0;
    }

    for (;
         (header = nx_entry_ok(p, match_len)) != 0;
         p += 4 + NXM_LENGTH(header), match_len -= 4 + NXM_LENGTH(header)) {
        const struct mf_field *mf;
        enum ofperr error;

        mf = mf_from_nxm_header(header);
        if (!mf) {
            if (strict) {
                error = OFPERR_OFPBMC_BAD_FIELD;
            } else {
                continue;
            }
        } else if (!mf_are_prereqs_ok(mf, &match->flow)) {
            error = OFPERR_OFPBMC_BAD_PREREQ;
        } else if (!mf_is_all_wild(mf, &match->wc)) {
            error = OFPERR_OFPBMC_DUP_FIELD;
        } else {
            unsigned int width = mf->n_bytes;
            union mf_value value;

            memcpy(&value, p + 4, width);
            if (!mf_is_value_valid(mf, &value)) {
                error = OFPERR_OFPBMC_BAD_VALUE;
            } else if (!NXM_HASMASK(header)) {
                error = 0;
                mf_set_value(mf, &value, match);
            } else {
                union mf_value mask;

                memcpy(&mask, p + 4 + width, width);
                if (!mf_is_mask_valid(mf, &mask)) {
                    error = OFPERR_OFPBMC_BAD_MASK;
                } else {
                    error = check_mask_consistency(p, mf);
                    if (!error) {
                        mf_set(mf, &value, &mask, match);
                    }
                }
            }
        }

        /* Check if the match is for a cookie rather than a classifier rule. */
        if ((header == NXM_NX_COOKIE || header == NXM_NX_COOKIE_W) && cookie) {
            if (*cookie_mask) {
                error = OFPERR_OFPBMC_DUP_FIELD;
            } else {
                unsigned int width = sizeof *cookie;

                memcpy(cookie, p + 4, width);
                if (NXM_HASMASK(header)) {
                    memcpy(cookie_mask, p + 4 + width, width);
                } else {
                    *cookie_mask = OVS_BE64_MAX;
                }
                error = 0;
            }
        }

        if (error) {
            VLOG_DBG_RL(&rl, "bad nxm_entry %#08"PRIx32" (vendor=%"PRIu32", "
                        "field=%"PRIu32", hasmask=%"PRIu32", len=%"PRIu32"), "
                        "(%s)", header,
                        NXM_VENDOR(header), NXM_FIELD(header),
                        NXM_HASMASK(header), NXM_LENGTH(header),
                        ofperr_to_string(error));
            return error;
        }
    }

    return match_len ? OFPERR_OFPBMC_BAD_LEN : 0;
}
示例#4
0
/* 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
 * OFPERR_* error code. */
enum ofperr
bundle_from_openflow(const struct nx_action_bundle *nab,
                     struct ofpbuf *ofpacts)
{
    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
    struct ofpact_bundle *bundle;
    uint16_t subtype;
    uint32_t slave_type;
    size_t slaves_size, i;
    enum ofperr error;

    bundle = ofpact_put_BUNDLE(ofpacts);

    subtype = ntohs(nab->subtype);
    bundle->n_slaves = ntohs(nab->n_slaves);
    bundle->basis = ntohs(nab->basis);
    bundle->fields = ntohs(nab->fields);
    bundle->algorithm = ntohs(nab->algorithm);
    slave_type = ntohl(nab->slave_type);
    slaves_size = ntohs(nab->len) - sizeof *nab;

    error = OFPERR_OFPBAC_BAD_ARGUMENT;
    if (!flow_hash_fields_valid(bundle->fields)) {
        VLOG_WARN_RL(&rl, "unsupported fields %d", (int) bundle->fields);
    } else if (bundle->n_slaves > BUNDLE_MAX_SLAVES) {
        VLOG_WARN_RL(&rl, "too may slaves");
    } else if (bundle->algorithm != NX_BD_ALG_HRW
               && bundle->algorithm != NX_BD_ALG_ACTIVE_BACKUP) {
        VLOG_WARN_RL(&rl, "unsupported algorithm %d", (int) bundle->algorithm);
    } else if (slave_type != NXM_OF_IN_PORT) {
        VLOG_WARN_RL(&rl, "unsupported slave type %"PRIu16, slave_type);
    } else {
        error = 0;
    }

    if (!is_all_zeros(nab->zero, sizeof nab->zero)) {
        VLOG_WARN_RL(&rl, "reserved field is nonzero");
        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) {
        bundle->dst.field = mf_from_nxm_header(ntohl(nab->dst));
        bundle->dst.ofs = nxm_decode_ofs(nab->ofs_nbits);
        bundle->dst.n_bits = nxm_decode_n_bits(nab->ofs_nbits);

        if (bundle->dst.n_bits < 16) {
            VLOG_WARN_RL(&rl, "bundle_load action requires at least 16 bit "
                         "destination.");
            error = OFPERR_OFPBAC_BAD_ARGUMENT;
        }
    }

    if (slaves_size < bundle->n_slaves * sizeof(ovs_be16)) {
        VLOG_WARN_RL(&rl, "Nicira action %"PRIu16" only has %"PRIuSIZE" bytes "
                     "allocated for slaves.  %"PRIuSIZE" bytes are required for "
                     "%"PRIu16" slaves.", subtype, slaves_size,
                     bundle->n_slaves * sizeof(ovs_be16), bundle->n_slaves);
        error = OFPERR_OFPBAC_BAD_LEN;
    }

    for (i = 0; i < bundle->n_slaves; i++) {
        uint16_t ofp_port = ntohs(((ovs_be16 *)(nab + 1))[i]);
        ofpbuf_put(ofpacts, &ofp_port, sizeof ofp_port);
    }

    bundle = ofpacts->l2;
    ofpact_update_len(ofpacts, &bundle->ofpact);

    if (!error) {
        error = bundle_check(bundle, OFPP_MAX, NULL);
    }
    return error;
}
void
learn_execute(const struct nx_action_learn *learn, const struct flow *flow,
              struct ofputil_flow_mod *fm)
{
    const void *p, *end;
    struct ofpbuf actions;

    cls_rule_init_catchall(&fm->cr, ntohs(learn->priority));
    fm->cookie = learn->cookie;
    fm->table_id = learn->table_id;
    fm->command = OFPFC_MODIFY_STRICT;
    fm->idle_timeout = ntohs(learn->idle_timeout);
    fm->hard_timeout = ntohs(learn->hard_timeout);
    fm->buffer_id = UINT32_MAX;
    fm->out_port = OFPP_NONE;
    fm->flags = ntohs(learn->flags) & OFPFF_SEND_FLOW_REM;
    fm->actions = NULL;
    fm->n_actions = 0;

    ofpbuf_init(&actions, 64);

    for (p = learn + 1, end = (char *) learn + ntohs(learn->len); p != end; ) {
        uint16_t header = ntohs(get_be16(&p));
        int n_bits = header & NX_LEARN_N_BITS_MASK;
        int src_type = header & NX_LEARN_SRC_MASK;
        int dst_type = header & NX_LEARN_DST_MASK;
        uint64_t value;

        struct nx_action_reg_load *load;
        ovs_be32 dst_field;
        int dst_ofs;

        if (!header) {
            break;
        }

        if (src_type == NX_LEARN_SRC_FIELD) {
            ovs_be32 src_field = get_be32(&p);
            int src_ofs = ntohs(get_be16(&p));

            value = nxm_read_field_bits(src_field,
                                        nxm_encode_ofs_nbits(src_ofs, n_bits),
                                        flow);
        } else {
            value = get_bits(n_bits, &p);
        }

        switch (dst_type) {
        case NX_LEARN_DST_MATCH:
            dst_field = get_be32(&p);
            dst_ofs = ntohs(get_be16(&p));
            mf_set_subfield(mf_from_nxm_header(ntohl(dst_field)), value,
                            dst_ofs, n_bits, &fm->cr);
            break;

        case NX_LEARN_DST_LOAD:
            dst_field = get_be32(&p);
            dst_ofs = ntohs(get_be16(&p));
            load = ofputil_put_NXAST_REG_LOAD(&actions);
            load->ofs_nbits = nxm_encode_ofs_nbits(dst_ofs, n_bits);
            load->dst = dst_field;
            load->value = htonll(value);
            break;

        case NX_LEARN_DST_OUTPUT:
            ofputil_put_OFPAT_OUTPUT(&actions)->port = htons(value);
            break;
        }
    }

    fm->actions = ofpbuf_steal_data(&actions);
    fm->n_actions = actions.size / sizeof(struct ofp_action_header);
}
/* Checks that 'learn' (which must be at least 'sizeof *learn' bytes long) is a
 * valid action on 'flow'. */
int
learn_check(const struct nx_action_learn *learn, const struct flow *flow)
{
    struct cls_rule rule;
    const void *p, *end;

    cls_rule_init_catchall(&rule, 0);

    if (learn->flags & ~htons(OFPFF_SEND_FLOW_REM)
        || !is_all_zeros(learn->pad, sizeof learn->pad)
        || learn->table_id == 0xff) {
        return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
    }

    end = (char *) learn + ntohs(learn->len);
    for (p = learn + 1; p != end; ) {
        uint16_t header = ntohs(get_be16(&p));
        int n_bits = header & NX_LEARN_N_BITS_MASK;
        int src_type = header & NX_LEARN_SRC_MASK;
        int dst_type = header & NX_LEARN_DST_MASK;

        uint64_t value;
        int error;

        if (!header) {
            break;
        }

        error = learn_check_header(header, (char *) end - (char *) p);
        if (error) {
            return error;
        }

        /* Check the source. */
        if (src_type == NX_LEARN_SRC_FIELD) {
            ovs_be32 src_field = get_be32(&p);
            int src_ofs = ntohs(get_be16(&p));

            error = nxm_src_check(src_field, src_ofs, n_bits, flow);
            if (error) {
                return error;
            }
            value = 0;
        } else {
            value = get_bits(n_bits, &p);
        }

        /* Check the destination. */
        if (dst_type == NX_LEARN_DST_MATCH || dst_type == NX_LEARN_DST_LOAD) {
            ovs_be32 dst_field = get_be32(&p);
            int dst_ofs = ntohs(get_be16(&p));
            int error;

            error = (dst_type == NX_LEARN_DST_LOAD
                     ? nxm_dst_check(dst_field, dst_ofs, n_bits, &rule.flow)
                     : nxm_src_check(dst_field, dst_ofs, n_bits, &rule.flow));
            if (error) {
                return error;
            }

            if (dst_type == NX_LEARN_DST_MATCH
                && src_type == NX_LEARN_SRC_IMMEDIATE) {
                mf_set_subfield(mf_from_nxm_header(ntohl(dst_field)), value,
                                dst_ofs, n_bits, &rule);
            }
        }
    }
    if (!is_all_zeros(p, (char *) end - (char *) p)) {
        return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
    }

    return 0;
}