From 11b8d04900417e722bb9cfad6021870bdee37fd6 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Wed, 6 May 2015 18:00:52 -0700 Subject: [PATCH] nx-match: Handle receiving variable length fields. This adds support for receiving variable length fields encoded in NXM/OXM and mapping them into OVS internal structures. In order for this to make sense, we need to define some semantics: There are three lengths that matter in this process: the maximum size of the field (represented as the existing mf->n_bytes), the size of the field in the incoming NXM (given by the length in the NXM header), and the currently configured length of the field (defined by the consumer of the field and outside the scope of this patch). Fields are modeled as being their maximum length and have the characteristics expected by exsiting code (i.e. exact match fields have masks that are all 1's for the whole field, etc.). Incoming NXMs are stored in the field in the least significant bits. If the NXM length is larger than the field, is is truncated, if it is smaller it is zero-extended. When the field is consumed, the component that needs data picks the configured length out of the generated field. In most cases, the configured and NXM lengths will be equal and these edge cases do not matter. However, since we cannot easily enforce that the lengths match (and might not even know what the right length is, such as in the case of a string parsed by ovs-ofctl), these semantics should provide deterministic results that are easy to understand and not require most existing code to be aware of variable length fields. Signed-off-by: Jesse Gross Acked-by: Ben Pfaff --- lib/nx-match.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/lib/nx-match.c b/lib/nx-match.c index d0add6f7e..5d12aeeae 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -326,17 +326,36 @@ error: return OFPERR_OFPBMC_BAD_LEN; } +static void +copy_entry_value(const struct mf_field *field, union mf_value *value, + const uint8_t *payload, int width) +{ + int copy_len; + void *copy_dst; + + copy_dst = value; + copy_len = MIN(width, field ? field->n_bytes : sizeof *value); + + if (field && field->variable_len) { + memset(value, 0, field->n_bytes); + copy_dst = &value->u8 + field->n_bytes - copy_len; + } + + memcpy(copy_dst, payload, copy_len); +} + static enum ofperr nx_pull_entry__(struct ofpbuf *b, bool allow_cookie, uint64_t *header, - const struct mf_field **field, + const struct mf_field **field_, union mf_value *value, union mf_value *mask) { + const struct mf_field *field; enum ofperr header_error; unsigned int payload_len; const uint8_t *payload; int width; - header_error = nx_pull_header__(b, allow_cookie, header, field); + header_error = nx_pull_header__(b, allow_cookie, header, &field); if (header_error && header_error != OFPERR_OFPBMC_BAD_FIELD) { return header_error; } @@ -356,12 +375,13 @@ nx_pull_entry__(struct ofpbuf *b, bool allow_cookie, uint64_t *header, return OFPERR_OFPBMC_BAD_WILDCARDS; } - memcpy(value, payload, MIN(width, sizeof *value)); + copy_entry_value(field, value, payload, width); + if (mask) { if (nxm_hasmask(*header)) { - memcpy(mask, payload + width, MIN(width, sizeof *mask)); + copy_entry_value(field, mask, payload + width, width); } else { - memset(mask, 0xff, MIN(width, sizeof *mask)); + memset(mask, 0xff, sizeof *mask); } } else if (nxm_hasmask(*header)) { VLOG_DBG_RL(&rl, "OXM header "NXM_HEADER_FMT" includes mask but " @@ -370,7 +390,12 @@ nx_pull_entry__(struct ofpbuf *b, bool allow_cookie, uint64_t *header, return OFPERR_OFPBMC_BAD_MASK; } - return header_error; + if (field_) { + *field_ = field; + return header_error; + } + + return 0; } /* Attempts to pull an NXM or OXM header, value, and mask (if present) from the -- 2.20.1