X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=lib%2Flearn.c;h=66201d5016f07a1aac49a1971726df96d3fd1f9d;hb=ca7e7bee86b4ee821d61b58bf15c89a9d8a3cb30;hp=c5797ebbaf94eb19aa330a42bcb0e4062492b42e;hpb=35f48b8bd9b3b3491d79418878ef70dc54b0a8f0;p=cascardo%2Fovs.git diff --git a/lib/learn.c b/lib/learn.c index c5797ebba..66201d501 100644 --- a/lib/learn.c +++ b/lib/learn.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc. + * Copyright (c) 2011, 2012, 2013, 2014, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,145 +30,6 @@ #include "openflow/openflow.h" #include "unaligned.h" -static ovs_be16 -get_be16(const void **pp) -{ - const ovs_be16 *p = *pp; - ovs_be16 value = *p; - *pp = p + 1; - return value; -} - -static ovs_be32 -get_be32(const void **pp) -{ - const ovs_be32 *p = *pp; - ovs_be32 value = get_unaligned_be32(p); - *pp = p + 1; - return value; -} - -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; -} - -static unsigned int -learn_min_len(uint16_t header) -{ - 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; - unsigned int min_len; - - min_len = 0; - if (src_type == NX_LEARN_SRC_FIELD) { - min_len += sizeof(ovs_be32); /* src_field */ - min_len += sizeof(ovs_be16); /* src_ofs */ - } else { - min_len += DIV_ROUND_UP(n_bits, 16); - } - if (dst_type == NX_LEARN_DST_MATCH || - dst_type == NX_LEARN_DST_LOAD) { - min_len += sizeof(ovs_be32); /* dst_field */ - min_len += sizeof(ovs_be16); /* dst_ofs */ - } - return min_len; -} - -/* Converts 'nal' into a "struct ofpact_learn" and appends that struct to - * 'ofpacts'. Returns 0 if successful, otherwise an OFPERR_*. */ -enum ofperr -learn_from_openflow(const struct nx_action_learn *nal, struct ofpbuf *ofpacts) -{ - struct ofpact_learn *learn; - const void *p, *end; - - if (nal->pad) { - return OFPERR_OFPBAC_BAD_ARGUMENT; - } - - learn = ofpact_put_LEARN(ofpacts); - - learn->idle_timeout = ntohs(nal->idle_timeout); - learn->hard_timeout = ntohs(nal->hard_timeout); - learn->priority = ntohs(nal->priority); - learn->cookie = nal->cookie; - learn->table_id = nal->table_id; - learn->fin_idle_timeout = ntohs(nal->fin_idle_timeout); - learn->fin_hard_timeout = ntohs(nal->fin_hard_timeout); - - learn->flags = ntohs(nal->flags); - if (learn->flags & ~(NX_LEARN_F_SEND_FLOW_REM | - NX_LEARN_F_DELETE_LEARNED)) { - return OFPERR_OFPBAC_BAD_ARGUMENT; - } - - if (learn->table_id == 0xff) { - return OFPERR_OFPBAC_BAD_ARGUMENT; - } - - end = (char *) nal + ntohs(nal->len); - for (p = nal + 1; p != end; ) { - struct ofpact_learn_spec *spec; - uint16_t header = ntohs(get_be16(&p)); - - if (!header) { - break; - } - - spec = ofpbuf_put_zeros(ofpacts, sizeof *spec); - learn = ofpacts->frame; - learn->n_specs++; - - spec->src_type = header & NX_LEARN_SRC_MASK; - spec->dst_type = header & NX_LEARN_DST_MASK; - spec->n_bits = header & NX_LEARN_N_BITS_MASK; - - /* Check for valid src and dst type combination. */ - if (spec->dst_type == NX_LEARN_DST_MATCH || - spec->dst_type == NX_LEARN_DST_LOAD || - (spec->dst_type == NX_LEARN_DST_OUTPUT && - spec->src_type == NX_LEARN_SRC_FIELD)) { - /* OK. */ - } else { - return OFPERR_OFPBAC_BAD_ARGUMENT; - } - - /* Check that the arguments don't overrun the end of the action. */ - if ((char *) end - (char *) p < learn_min_len(header)) { - return OFPERR_OFPBAC_BAD_LEN; - } - - /* Get the source. */ - if (spec->src_type == NX_LEARN_SRC_FIELD) { - get_subfield(spec->n_bits, &p, &spec->src); - } else { - int p_bytes = 2 * DIV_ROUND_UP(spec->n_bits, 16); - - bitwise_copy(p, p_bytes, 0, - &spec->src_imm, sizeof spec->src_imm, 0, - spec->n_bits); - p = (const uint8_t *) p + p_bytes; - } - - /* Get the destination. */ - if (spec->dst_type == NX_LEARN_DST_MATCH || - spec->dst_type == NX_LEARN_DST_LOAD) { - get_subfield(spec->n_bits, &p, &spec->dst); - } - } - ofpact_update_len(ofpacts, &learn->ofpact); - - if (!is_all_zeros(p, (char *) end - (char *) p)) { - return OFPERR_OFPBAC_BAD_ARGUMENT; - } - - return 0; -} /* Checks that 'learn' is a valid action on 'flow'. Returns 0 if it is valid, * otherwise an OFPERR_*. */ @@ -216,79 +77,6 @@ learn_check(const struct ofpact_learn *learn, const struct flow *flow) return 0; } -static void -put_be16(struct ofpbuf *b, ovs_be16 x) -{ - ofpbuf_put(b, &x, sizeof x); -} - -static void -put_be32(struct ofpbuf *b, ovs_be32 x) -{ - ofpbuf_put(b, &x, sizeof x); -} - -static void -put_u16(struct ofpbuf *b, uint16_t x) -{ - put_be16(b, htons(x)); -} - -static void -put_u32(struct ofpbuf *b, uint32_t x) -{ - put_be32(b, htonl(x)); -} - -/* Converts 'learn' into a "struct nx_action_learn" and appends that action to - * 'ofpacts'. */ -void -learn_to_nxast(const struct ofpact_learn *learn, struct ofpbuf *openflow) -{ - const struct ofpact_learn_spec *spec; - struct nx_action_learn *nal; - size_t start_ofs; - - start_ofs = ofpbuf_size(openflow); - nal = ofputil_put_NXAST_LEARN(openflow); - nal->idle_timeout = htons(learn->idle_timeout); - nal->hard_timeout = htons(learn->hard_timeout); - nal->fin_idle_timeout = htons(learn->fin_idle_timeout); - nal->fin_hard_timeout = htons(learn->fin_hard_timeout); - nal->priority = htons(learn->priority); - nal->cookie = learn->cookie; - nal->flags = htons(learn->flags); - nal->table_id = learn->table_id; - - for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) { - put_u16(openflow, spec->n_bits | spec->dst_type | spec->src_type); - - if (spec->src_type == NX_LEARN_SRC_FIELD) { - put_u32(openflow, spec->src.field->nxm_header); - put_u16(openflow, spec->src.ofs); - } else { - size_t n_dst_bytes = 2 * DIV_ROUND_UP(spec->n_bits, 16); - uint8_t *bits = ofpbuf_put_zeros(openflow, n_dst_bytes); - bitwise_copy(&spec->src_imm, sizeof spec->src_imm, 0, - bits, n_dst_bytes, 0, - spec->n_bits); - } - - if (spec->dst_type == NX_LEARN_DST_MATCH || - spec->dst_type == NX_LEARN_DST_LOAD) { - put_u32(openflow, spec->dst.field->nxm_header); - put_u16(openflow, spec->dst.ofs); - } - } - - if ((ofpbuf_size(openflow) - start_ofs) % 8) { - ofpbuf_put_zeros(openflow, 8 - (ofpbuf_size(openflow) - start_ofs) % 8); - } - - nal = ofpbuf_at_assert(openflow, start_ofs, sizeof *nal); - nal->len = htons(ofpbuf_size(openflow) - start_ofs); -} - /* Composes 'fm' so that executing it will implement 'learn' given that the * packet being processed has 'flow' as its flow. * @@ -313,6 +101,7 @@ learn_execute(const struct ofpact_learn *learn, const struct flow *flow, fm->command = OFPFC_MODIFY_STRICT; fm->idle_timeout = learn->idle_timeout; fm->hard_timeout = learn->hard_timeout; + fm->importance = 0; fm->buffer_id = UINT32_MAX; fm->out_port = OFPP_NONE; fm->flags = 0; @@ -332,8 +121,8 @@ learn_execute(const struct ofpact_learn *learn, const struct flow *flow, } for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; spec++) { + struct ofpact_set_field *sf; union mf_subvalue value; - int chunk, ofs; if (spec->src_type == NX_LEARN_SRC_FIELD) { mf_read_subfield(&spec->src, flow, &value); @@ -347,25 +136,19 @@ learn_execute(const struct ofpact_learn *learn, const struct flow *flow, break; case NX_LEARN_DST_LOAD: - for (ofs = 0; ofs < spec->n_bits; ofs += chunk) { - struct ofpact_reg_load *load; - - chunk = MIN(spec->n_bits - ofs, 64); - - load = ofpact_put_REG_LOAD(ofpacts); - load->dst.field = spec->dst.field; - load->dst.ofs = spec->dst.ofs + ofs; - load->dst.n_bits = chunk; - bitwise_copy(&value, sizeof value, ofs, - &load->subvalue, sizeof load->subvalue, 0, - chunk); - } + sf = ofpact_put_reg_load(ofpacts); + sf->field = spec->dst.field; + bitwise_copy(&value, sizeof value, 0, + &sf->value, spec->dst.field->n_bytes, spec->dst.ofs, + spec->n_bits); + bitwise_one(&sf->mask, spec->dst.field->n_bytes, spec->dst.ofs, + spec->n_bits); break; case NX_LEARN_DST_OUTPUT: if (spec->n_bits <= 16 || is_all_zeros(value.u8, sizeof value - 2)) { - ofp_port_t port = u16_to_ofp(ntohs(value.be16[7])); + ofp_port_t port = u16_to_ofp(ntohll(value.integer)); if (ofp_to_u16(port) < ofp_to_u16(OFPP_MAX) || port == OFPP_IN_PORT @@ -378,10 +161,9 @@ learn_execute(const struct ofpact_learn *learn, const struct flow *flow, break; } } - ofpact_pad(ofpacts); - fm->ofpacts = ofpbuf_data(ofpacts); - fm->ofpacts_len = ofpbuf_size(ofpacts); + fm->ofpacts = ofpacts->data; + fm->ofpacts_len = ofpacts->size; } /* Perform a bitwise-OR on 'wc''s fields that are relevant as sources in @@ -402,32 +184,18 @@ learn_mask(const struct ofpact_learn *learn, struct flow_wildcards *wc) /* Returns NULL if successful, otherwise a malloc()'d string describing the * error. The caller is responsible for freeing the returned string. */ -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT learn_parse_load_immediate(const char *s, struct ofpact_learn_spec *spec) { const char *full_s = s; - const char *arrow = strstr(s, "->"); struct mf_subfield dst; union mf_subvalue imm; char *error; + int err; - memset(&imm, 0, sizeof imm); - if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X') && arrow) { - const char *in = arrow - 1; - uint8_t *out = imm.u8 + sizeof imm.u8 - 1; - int n = arrow - (s + 2); - int i; - - for (i = 0; i < n; i++) { - int hexit = hexit_value(in[-i]); - if (hexit < 0) { - return xasprintf("%s: bad hex digit in value", full_s); - } - out[-(i / 2)] |= i % 2 ? hexit << 4 : hexit; - } - s = arrow; - } else { - imm.be64[1] = htonll(strtoull(s, (char **) &s, 0)); + err = parse_int_string(s, imm.u8, sizeof imm.u8, (char **) &s); + if (err) { + return xasprintf("%s: too many bits in immediate value", full_s); } if (strncmp(s, "->", 2)) { @@ -439,6 +207,10 @@ learn_parse_load_immediate(const char *s, struct ofpact_learn_spec *spec) if (error) { return error; } + if (!mf_nxm_header(dst.field->id)) { + return xasprintf("%s: experimenter OXM field '%s' not supported", + full_s, s); + } if (!bitwise_is_all_zeros(&imm, sizeof imm, dst.n_bits, (8 * sizeof imm) - dst.n_bits)) { @@ -456,7 +228,7 @@ learn_parse_load_immediate(const char *s, struct ofpact_learn_spec *spec) /* Returns NULL if successful, otherwise a malloc()'d string describing the * error. The caller is responsible for freeing the returned string. */ -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT learn_parse_spec(const char *orig, char *name, char *value, struct ofpact_learn_spec *spec) { @@ -487,6 +259,10 @@ learn_parse_spec(const char *orig, char *name, char *value, if (error) { return error; } + if (!mf_nxm_header(spec->dst.field->id)) { + return xasprintf("%s: experimenter OXM field '%s' not supported", + orig, name); + } /* Parse source and check prerequisites. */ if (value[0] != '\0') { @@ -545,7 +321,7 @@ learn_parse_spec(const char *orig, char *name, char *value, /* Returns NULL if successful, otherwise a malloc()'d string describing the * error. The caller is responsible for freeing the returned string. */ -static char * WARN_UNUSED_RESULT +static char * OVS_WARN_UNUSED_RESULT learn_parse__(char *orig, char *arg, struct ofpbuf *ofpacts) { struct ofpact_learn *learn; @@ -587,7 +363,7 @@ learn_parse__(char *orig, char *arg, struct ofpbuf *ofpacts) char *error; spec = ofpbuf_put_zeros(ofpacts, sizeof *spec); - learn = ofpacts->frame; + learn = ofpacts->header; learn->n_specs++; error = learn_parse_spec(orig, name, value, spec); @@ -603,7 +379,7 @@ learn_parse__(char *orig, char *arg, struct ofpbuf *ofpacts) } } } - ofpact_update_len(ofpacts, &learn->ofpact); + ofpact_finish(ofpacts, &learn->ofpact); return NULL; } @@ -620,7 +396,7 @@ learn_parse__(char *orig, char *arg, struct ofpbuf *ofpacts) * the action's arguments. * * Modifies 'arg'. */ -char * WARN_UNUSED_RESULT +char * OVS_WARN_UNUSED_RESULT learn_parse(char *arg, struct ofpbuf *ofpacts) { char *orig = xstrdup(arg);